From 0f694d3db694773d0fadf4141b1fa3695858c472 Mon Sep 17 00:00:00 2001 From: Chidozie Ononiwu Date: Tue, 13 Oct 2020 11:46:44 -0700 Subject: [PATCH 1/3] Refactpr Submit Pull Request Script --- eng/common/scripts/Submit-PullRequest.ps1 | 79 +++++++++-------------- 1 file changed, 31 insertions(+), 48 deletions(-) diff --git a/eng/common/scripts/Submit-PullRequest.ps1 b/eng/common/scripts/Submit-PullRequest.ps1 index 93ca35512c85..be5803a8cbde 100644 --- a/eng/common/scripts/Submit-PullRequest.ps1 +++ b/eng/common/scripts/Submit-PullRequest.ps1 @@ -49,61 +49,43 @@ param( [string]$PRBody = $PRTitle, [Parameter(Mandatory = $false)] - [string]$PRLabels -) + [string]$PRLabels, -$headers = @{ - Authorization = "bearer $AuthToken" -} + [Parameter(Mandatory = $false)] + [string]$UserReviewers, -$query = "state=open&head=${PROwner}:${PRBranch}&base=${BaseBranch}" + [Parameter(Mandatory = $false)] + [string]$TeamReviewers, -function AddLabels([int] $prNumber, [string] $prLabelString, [array] $existingLabels) -{ - # Adding labels to the pr. - if (-not $prLabelString) { - Write-Verbose "There are no labels added to the PR." - return - } + [Parameter(Mandatory = $false)] + [string]$Assignees +) - # Parse the labels from string to array - $prLabelArray = @($prLabelString.Split(",") | % { $_.Trim() } | ? { return $_ }) - foreach ($label in $existingLabels) { - if ($prLabelArray -contains $label.name) { - continue - } - $prLabelArray += $label.name - } - $prLabelUri = "https://api.github.com/repos/$RepoOwner/$RepoName/issues/$prNumber" - $labelRequestData = @{ - labels = $prLabelArray - } - try { - $resp = Invoke-RestMethod -Method PATCH -Headers $headers $prLabelUri -Body ($labelRequestData | ConvertTo-Json) - } - catch { - Write-Error "Invoke-RestMethod $prLabelUri failed with exception:`n$_" - } - - $resp | Write-Verbose - Write-Host -f green "Label(s) [$prLabelArray] added to pull request: https://github.com/$RepoOwner/$RepoName/pull/$prNumber" -} +. "${PSScriptRoot}\common.ps1" try { - $resp = Invoke-RestMethod -Headers $headers "https://api.github.com/repos/$RepoOwner/$RepoName/pulls?$query" + $resp = List-PullRequests -RepoOwner $RepoOwner -RepoName $RepoName -Head "${PROwner}:${PRBranch}" -Base $BaseBranch } catch { - Write-Error "Invoke-RestMethod [https://api.github.com/repos/$RepoOwner/$RepoName/pulls?$query] failed with exception:`n$_" + LogError "List-PullRequests failed with exception:`n$_" exit 1 } + $resp | Write-Verbose if ($resp.Count -gt 0) { - Write-Host -f green "Pull request already exists $($resp[0].html_url)" + try { + LogDebug "Pull request already exists $($resp[0].html_url)" # setting variable to reference the pull request by number Write-Host "##vso[task.setvariable variable=Submitted.PullRequest.Number]$($resp[0].number)" - AddLabels $resp[0].number $PRLabels $resp[0].labels + Add-IssueLabels -RepoOwner $RepoOwner -RepoName $RepoName -IssueNumber $resp[0].number` + -Labels $PRLabels -AuthToken $AuthToken + } + catch { + LogError "Call to GitHub API failed with exception:`n$_" + exit 1 + } } else { $data = @{ @@ -118,17 +100,18 @@ else { $resp = Invoke-RestMethod -Method POST -Headers $headers ` "https://api.github.com/repos/$RepoOwner/$RepoName/pulls" ` -Body ($data | ConvertTo-Json) + + $resp | Write-Verbose + LogDebug "Pull request created https://github.com/$RepoOwner/$RepoName/pull/$($resp.number)" + + # setting variable to reference the pull request by number + Write-Host "##vso[task.setvariable variable=Submitted.PullRequest.Number]$($resp.number)" + + Add-IssueLabels -RepoOwner $RepoOwner -RepoName $RepoName -IssueNumber $resp.number` + -Labels $PRLabels -AuthToken $AuthToken } catch { - Write-Error "Invoke-RestMethod [https://api.github.com/repos/$RepoOwner/$RepoName/pulls] failed with exception:`n$_" + LogError "Call to GitHub API failed with exception:`n$_" exit 1 } - - $resp | Write-Verbose - Write-Host -f green "Pull request created https://github.com/$RepoOwner/$RepoName/pull/$($resp.number)" - - # setting variable to reference the pull request by number - Write-Host "##vso[task.setvariable variable=Submitted.PullRequest.Number]$($resp.number)" - - AddLabels $resp.number $PRLabels $resp.labels } From e76d5aae230204e4cf6f9bbed686ce50cfe02144 Mon Sep 17 00:00:00 2001 From: Chidozie Ononiwu Date: Tue, 13 Oct 2020 15:52:55 -0700 Subject: [PATCH 2/3] Refactor logic for interacting with Pull Requests --- .../templates/steps/create-pull-request.yml | 20 +-- eng/common/scripts/Get-PrCreator.ps1 | 24 ++++ eng/common/scripts/Invoke-GitHubAPI.ps1 | 130 ++++++++++++++++-- eng/common/scripts/Submit-PullRequest.ps1 | 35 ++--- .../scripts/add-pullrequest-reviewers.ps1 | 61 -------- 5 files changed, 169 insertions(+), 101 deletions(-) create mode 100644 eng/common/scripts/Get-PrCreator.ps1 delete mode 100644 eng/common/scripts/add-pullrequest-reviewers.ps1 diff --git a/eng/common/pipelines/templates/steps/create-pull-request.yml b/eng/common/pipelines/templates/steps/create-pull-request.yml index e3b3e538c036..afd0e4bfc929 100644 --- a/eng/common/pipelines/templates/steps/create-pull-request.yml +++ b/eng/common/pipelines/templates/steps/create-pull-request.yml @@ -15,6 +15,7 @@ parameters: ScriptDirectory: eng/common/scripts GHReviewersVariable: '' GHTeamReviewersVariable: '' + GHAssignessVariable: '' # Multiple labels seperated by comma, e.g. "bug, APIView" PRLabels: '' SkipCheckingForChanges: false @@ -81,19 +82,6 @@ steps: -PRTitle "${{ parameters.PRTitle }}" -PRBody "${{ coalesce(parameters.PRBody, parameters.CommitMsg, parameters.PRTitle) }}" -PRLabels "${{ parameters.PRLabels}}" - -- task: PowerShell@2 - displayName: Tag a Reviewer on PR - condition: and(succeeded(), eq(variables['HasChanges'], 'true')) - continueOnError: true - inputs: - pwsh: true - workingDirectory: ${{ parameters.WorkingDirectory }} - filePath: ${{ parameters.ScriptDirectory }}/add-pullrequest-reviewers.ps1 - arguments: > - -RepoOwner "${{ parameters.RepoOwner }}" - -RepoName "$(RepoNameWithoutOwner)" - -AuthToken "$(azuresdk-github-pat)" - -GitHubUsers "$(${{ parameters.GHReviewersVariable }})" - -GitHubTeams "$(${{ parameters.GHTeamReviewersVariable }})" - -PRNumber "$(Submitted.PullRequest.Number)" + -UserReviewers "${{ parameters.GHReviewersVariable }}" + -TeamReviewers "${{ parameters.GHTeamReviewersVariable }}" + -Assignees "${{ parameters.GHAssignessVariable }}" diff --git a/eng/common/scripts/Get-PrCreator.ps1 b/eng/common/scripts/Get-PrCreator.ps1 new file mode 100644 index 000000000000..34cb86991b96 --- /dev/null +++ b/eng/common/scripts/Get-PrCreator.ps1 @@ -0,0 +1,24 @@ +param ( + [Parameter(Mandatory = $true)] + [string]$RepoOwner, + + [Parameter(Mandatory = $true)] + [string]$RepoName, + + [Parameter(Mandatory = $true)] + $PullRequestNumber +) + +. "${PSScriptRoot}\common.ps1" + +try +{ + $pullRequest = Get-PullRequest -RepoOwner $RepoOwner -RepoName $RepoName -PullRequestNumber $PullRequestNumber + Write-Host "##vso[task.setvariable variable=System.PullRequest.Creator;]$($pullRequest.user.login)" +} +catch +{ + Write-Error "Get-PullRequest failed with exception:`n$_" + exit 1 +} + diff --git a/eng/common/scripts/Invoke-GitHubAPI.ps1 b/eng/common/scripts/Invoke-GitHubAPI.ps1 index 22f370f3202f..a263282766db 100644 --- a/eng/common/scripts/Invoke-GitHubAPI.ps1 +++ b/eng/common/scripts/Invoke-GitHubAPI.ps1 @@ -109,11 +109,18 @@ function List-PullRequests { [ValidateSet("created","updated","popularity","long-running")] $Sort, [ValidateSet("asc","desc")] - $Direction + $Direction, + [Parameter(DontShow)] + $PullRequestNumber ) $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/pulls" - if ($State -or $Head -or $Base -or $Sort -or $Direction) { $uri += '?'} + if ($State -or $Head -or $Base -or $Sort -or $Direction) { + $uri += '?' + } + elseif ($PullRequestNumber) { + $uri += "/${PullRequestNumber}" + } if ($State) { $uri += "state=$State&" } if ($Head) { $uri += "head=$Head&" } if ($Base) { $uri += "base=$Base&" } @@ -144,6 +151,51 @@ function List-References { return Invoke-GitHubAPIGet -apiURI $uri } +function Get-PullRequest { + param ( + [Parameter(Mandatory = $true)] + $RepoOwner, + [Parameter(Mandatory = $true)] + $RepoName, + [Parameter(Mandatory = $true)] + $PullRequestNumber + ) + + return List-PullRequests -RepoOwner $RepoOwner -RepoName $RepoName -PullRequestNumber $PullRequestNumber +} + +function Create-PullRequest { + param ( + [Parameter(Mandatory = $true)] + $RepoOwner, + [Parameter(Mandatory = $true)] + $RepoName, + [Parameter(Mandatory = $true)] + $Title, + [Parameter(Mandatory = $true)] + $Head, + [Parameter(Mandatory = $true)] + $Base, + $Body=$Title, + [Boolean]$Maintainer_Can_Modify=$false, + [Boolean]$Draft=$false, + [Parameter(Mandatory = $true)] + $AuthToken + ) + + $parameters = @{ + title = $Title + head = $Head + base = $Base + body = $Body + maintainer_can_modify = $Maintainer_Can_Modify + $draft = $Draft + } + + $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/pulls" + return Invoke-GitHubAPIPost -apiURI $uri -body $parameters -token $AuthToken +} + function Add-IssueComment { param ( [Parameter(Mandatory = $true)] @@ -229,6 +281,54 @@ function Add-IssueAssignees { return Invoke-GitHubAPIPost -apiURI $uri -body $parameters -token $AuthToken } +function Request-PrReviewer { + param ( + [Parameter(Mandatory = $true)] + $RepoOwner, + [Parameter(Mandatory = $true)] + $RepoName, + [Parameter(Mandatory = $true)] + $PrNumber, + $Users, + $Teams, + [Parameter(Mandatory = $true)] + $AuthToken + ) + + if (!$users -and !$teams) + { + throw "You must specify either Users or Teams." + exit 1 + } + + $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/pulls/$PrNumber/requested_reviewers" + $parameters = @{} + + if ($Users) { + if ($Users -is [array]) + { + $parameters["reviewers"] = @($Users) + } + else { + $userAdditions = SplitMembers -membersString $Users + $parameters["reviewers"] = @($userAdditions) + } + } + + if ($Teams) { + if ($Teams -is [array]) + { + $parameters["team_reviewers"] = @($Teams) + } + else { + $teamAdditions = SplitMembers -membersString $Teams + $parameters["team_reviewers"] = @($teamAdditions) + } + } + + return Invoke-GitHubAPIPost -apiURI $uri -body $parameters -token AuthToken +} + # For labels and assignee pass comma delimited string, to replace existing labels or assignees. # Or pass white space " " to remove all labels or assignees function Update-Issue { @@ -245,9 +345,9 @@ function Update-Issue { [string]$State, [int]$Milestome, [ValidateNotNullOrEmpty()] - [string]$Labels, + $Labels, [ValidateNotNullOrEmpty()] - [string]$Assignees, + $Assignees, [Parameter(Mandatory = $true)] $AuthToken ) @@ -258,13 +358,27 @@ function Update-Issue { if ($Body) { $parameters["body"] = $Body } if ($State) { $parameters["state"] = $State } if ($Milestone) { $parameters["milestone"] = $Milestone } + if ($Labels) { - $labelAdditions = SplitMembers -membersString $Labels - $parameters["labels"] = @($labelAdditions) + if ($Labels -is [array]) + { + $parameters["labels"] = @($Labels) + } + else { + $labelAdditions = SplitMembers -membersString $Labels + $parameters["labels"] = @($labelAdditions) + } } + if ($Assignees) { - $assigneesAdditions = SplitMembers -membersString $Assignees - $parameters["assignees"] = @($assigneesAdditions) + if ($Assignees -is [array]) + { + $parameters["labels"] = @($Assignees) + } + else { + $assigneesAdditions = SplitMembers -membersString $Assignees + $parameters["assignees"] = @($assigneesAdditions) + } } return Invoke-GitHubAPIPatch -apiURI $uri -body $parameters -token $AuthToken diff --git a/eng/common/scripts/Submit-PullRequest.ps1 b/eng/common/scripts/Submit-PullRequest.ps1 index be5803a8cbde..3acc6b7fad99 100644 --- a/eng/common/scripts/Submit-PullRequest.ps1 +++ b/eng/common/scripts/Submit-PullRequest.ps1 @@ -64,7 +64,8 @@ param( . "${PSScriptRoot}\common.ps1" try { - $resp = List-PullRequests -RepoOwner $RepoOwner -RepoName $RepoName -Head "${PROwner}:${PRBranch}" -Base $BaseBranch + $resp = List-PullRequests -RepoOwner $RepoOwner -RepoName $RepoName` + -Head "${PROwner}:${PRBranch}" -Base $BaseBranch } catch { LogError "List-PullRequests failed with exception:`n$_" @@ -79,8 +80,15 @@ if ($resp.Count -gt 0) { # setting variable to reference the pull request by number Write-Host "##vso[task.setvariable variable=Submitted.PullRequest.Number]$($resp[0].number)" - Add-IssueLabels -RepoOwner $RepoOwner -RepoName $RepoName -IssueNumber $resp[0].number` - -Labels $PRLabels -AuthToken $AuthToken + + $lablesArray = $resp[0].labels.name + ($PRLabels -split ',') | Sort-Object -Unique + $AssigneesArray = $resp[0].assignees.login + ($Assignees -split ',') | Sort-Object -Unique + + Update-Issue -RepoOwner $RepoOwner -RepoName $RepoName -IssueNumber $resp[0].number` + -Labels $lablesArray -Assignees $AssigneesArray -AuthToken $AuthToken + + Request-PrReviewer -RepoOwner $RepoOwner -RepoName $RepoName -PrNumber $resp[0].number` + -Users $UserReviewers -Teams $TeamReviewers -AuthToken $AuthToken } catch { LogError "Call to GitHub API failed with exception:`n$_" @@ -88,18 +96,10 @@ if ($resp.Count -gt 0) { } } else { - $data = @{ - title = $PRTitle - head = "${PROwner}:${PRBranch}" - base = $BaseBranch - body = $PRBody - maintainer_can_modify = $true - } - try { - $resp = Invoke-RestMethod -Method POST -Headers $headers ` - "https://api.github.com/repos/$RepoOwner/$RepoName/pulls" ` - -Body ($data | ConvertTo-Json) + $resp = Create-PullRequest -RepoOwner $RepoOwner -RepoName $RepoName -Title $PRTitle` + -Head "${PROwner}:${PRBranch}" -Base $BaseBranch -Body $PRBody -Maintainer_Can_Modify $true` + -AuthToken $AuthToken $resp | Write-Verbose LogDebug "Pull request created https://github.com/$RepoOwner/$RepoName/pull/$($resp.number)" @@ -107,8 +107,11 @@ else { # setting variable to reference the pull request by number Write-Host "##vso[task.setvariable variable=Submitted.PullRequest.Number]$($resp.number)" - Add-IssueLabels -RepoOwner $RepoOwner -RepoName $RepoName -IssueNumber $resp.number` - -Labels $PRLabels -AuthToken $AuthToken + Update-Issue -RepoOwner $RepoOwner -RepoName $RepoName -IssueNumber $resp.number` + -Labels $PRLabels -Assignees $Assignees -AuthToken $AuthToken + + Request-PrReviewer -RepoOwner $RepoOwner -RepoName $RepoName -PrNumber $resp.number` + -Users $UserReviewers -Teams $TeamReviewers -AuthToken $AuthToken } catch { LogError "Call to GitHub API failed with exception:`n$_" diff --git a/eng/common/scripts/add-pullrequest-reviewers.ps1 b/eng/common/scripts/add-pullrequest-reviewers.ps1 deleted file mode 100644 index 3198dcb40d2c..000000000000 --- a/eng/common/scripts/add-pullrequest-reviewers.ps1 +++ /dev/null @@ -1,61 +0,0 @@ -param( - [Parameter(Mandatory = $true)] - $RepoOwner, - - [Parameter(Mandatory = $true)] - $RepoName, - - [Parameter(Mandatory = $false)] - $GitHubUsers = "", - - [Parameter(Mandatory = $false)] - $GitHubTeams = "", - - [Parameter(Mandatory = $true)] - $PRNumber, - - [Parameter(Mandatory = $true)] - $AuthToken -) - -function AddMembers($memberName, $additionSet) { - $headers = @{ - Authorization = "bearer $AuthToken" - } - $uri = "https://api.github.com/repos/$RepoOwner/$RepoName/pulls/$PRNumber/requested_reviewers" - $errorOccurred = $false - - foreach ($id in $additionSet) { - try { - $postResp = @{} - $postResp[$memberName] = @($id) - $postResp = $postResp | ConvertTo-Json - - Write-Host $postResp - $resp = Invoke-RestMethod -Method Post -Headers $headers -Body $postResp -Uri $uri -MaximumRetryCount 3 - $resp | Write-Verbose - } - catch { - Write-Host "Error attempting to add $user `n$_" - $errorOccurred = $true - } - } - - return $errorOccurred -} - -# at least one of these needs to be populated -if (-not $GitHubUsers -and -not $GitHubTeams) { - Write-Host "No user provided for addition, exiting." - exit 0 -} - -$userAdditions = @($GitHubUsers.Split(",") | % { $_.Trim() } | ? { return $_ }) -$teamAdditions = @($GitHubTeams.Split(",") | % { $_.Trim() } | ? { return $_ }) - -$errorsOccurredAddingUsers = AddMembers -memberName "reviewers" -additionSet $userAdditions -$errorsOccurredAddingTeams = AddMembers -memberName "team_reviewers" -additionSet $teamAdditions - -if ($errorsOccurredAddingUsers -or $errorsOccurredAddingTeams) { - exit 1 -} From f8b44634a171421bea2b2063f5da055a59aae989 Mon Sep 17 00:00:00 2001 From: Chidozie Ononiwu Date: Wed, 14 Oct 2020 12:47:54 -0700 Subject: [PATCH 3/3] Rework API Lib --- .../templates/steps/create-pull-request.yml | 2 +- eng/common/scripts/Add-IssueComment.ps1 | 4 +- eng/common/scripts/Add-IssueLabels.ps1 | 4 +- eng/common/scripts/Delete-RemoteBranches.ps1 | 12 +- ...Creator.ps1 => Get-PullRequestCreator.ps1} | 2 +- eng/common/scripts/Invoke-GitHubAPI.ps1 | 257 ++++++++++-------- eng/common/scripts/Submit-PullRequest.ps1 | 42 +-- 7 files changed, 160 insertions(+), 163 deletions(-) rename eng/common/scripts/{Get-PrCreator.ps1 => Get-PullRequestCreator.ps1} (77%) diff --git a/eng/common/pipelines/templates/steps/create-pull-request.yml b/eng/common/pipelines/templates/steps/create-pull-request.yml index afd0e4bfc929..bdf923654c66 100644 --- a/eng/common/pipelines/templates/steps/create-pull-request.yml +++ b/eng/common/pipelines/templates/steps/create-pull-request.yml @@ -81,7 +81,7 @@ steps: -AuthToken "$(azuresdk-github-pat)" -PRTitle "${{ parameters.PRTitle }}" -PRBody "${{ coalesce(parameters.PRBody, parameters.CommitMsg, parameters.PRTitle) }}" - -PRLabels "${{ parameters.PRLabels}}" + -PRLabels "${{ parameters.PRLabels }}" -UserReviewers "${{ parameters.GHReviewersVariable }}" -TeamReviewers "${{ parameters.GHTeamReviewersVariable }}" -Assignees "${{ parameters.GHAssignessVariable }}" diff --git a/eng/common/scripts/Add-IssueComment.ps1 b/eng/common/scripts/Add-IssueComment.ps1 index 7b797a12d418..b1d8a649797c 100644 --- a/eng/common/scripts/Add-IssueComment.ps1 +++ b/eng/common/scripts/Add-IssueComment.ps1 @@ -19,10 +19,10 @@ param( . "${PSScriptRoot}\common.ps1" try { - Add-IssueComment -RepoOwner $RepoOwner -RepoName $RepoName ` + Add-GithubIssueComment -RepoOwner $RepoOwner -RepoName $RepoName ` -IssueNumber $IssueNumber -Comment $Comment -AuthToken $AuthToken } catch { - LogError "Add-IssueComment failed with exception:`n$_" + LogError "Add-GithubIssueComment failed with exception:`n$_" exit 1 } \ No newline at end of file diff --git a/eng/common/scripts/Add-IssueLabels.ps1 b/eng/common/scripts/Add-IssueLabels.ps1 index 7f0debe35610..0cd4837e69ad 100644 --- a/eng/common/scripts/Add-IssueLabels.ps1 +++ b/eng/common/scripts/Add-IssueLabels.ps1 @@ -19,10 +19,10 @@ param( . "${PSScriptRoot}\common.ps1" try { - Add-IssueLabels -RepoOwner $RepoOwner -RepoName $RepoName ` + Add-GithubIssueLabels -RepoOwner $RepoOwner -RepoName $RepoName ` -IssueNumber $IssueNumber -Labels $Labels -AuthToken $AuthToken } catch { - LogError "Add-IssueLabels failed with exception:`n$_" + LogError "Add-GithubIssueLabels failed with exception:`n$_" exit 1 } \ No newline at end of file diff --git a/eng/common/scripts/Delete-RemoteBranches.ps1 b/eng/common/scripts/Delete-RemoteBranches.ps1 index da55471ef25f..0ca7c55be932 100644 --- a/eng/common/scripts/Delete-RemoteBranches.ps1 +++ b/eng/common/scripts/Delete-RemoteBranches.ps1 @@ -9,10 +9,10 @@ param( LogDebug "Operating on Repo [ $RepoName ]" try{ - $branches = (List-References -RepoOwner $RepoOwner -RepoName $RepoName -Ref "heads/$BranchPrefix").ref + $branches = (Get-GitHubSourceReferences -RepoOwner $RepoOwner -RepoName $RepoName -Ref "heads/$BranchPrefix").ref } catch { - LogError "List-References failed with exception:`n$_" + LogError "Get-GitHubSourceReferences failed with exception:`n$_" exit 1 } @@ -22,11 +22,11 @@ foreach ($branch in $branches) $branchName = $branch.Replace("refs/heads/","") $head = "${RepoOwner}/${RepoName}:${branchName}" LogDebug "Operating on branch [ $branchName ]" - $pullRequests = List-PullRequests -RepoOwner $RepoOwner -RepoName $RepoName -head $head + $pullRequests = Get-GitHubPullRequests -RepoOwner $RepoOwner -RepoName $RepoName -head $head } catch { - LogError "List-PullRequests failed with exception:`n$_" + LogError "Get-GitHubPullRequests failed with exception:`n$_" exit 1 } @@ -34,10 +34,10 @@ foreach ($branch in $branches) { LogDebug "Branch [ $branchName ] in repo [ $RepoName ] has no associated Pull Request. Deleting Branch" try{ - Delete-References -RepoOwner $RepoOwner -RepoName $RepoName -Ref ($branch.Remove(0,5)) -AuthToken $AuthToken + Remove-GitHubSourceReferences -RepoOwner $RepoOwner -RepoName $RepoName -Ref ($branch.Remove(0,5)) -AuthToken $AuthToken } catch { - LogError "Delete-References failed with exception:`n$_" + LogError "Remove-GitHubSourceReferences failed with exception:`n$_" exit 1 } } diff --git a/eng/common/scripts/Get-PrCreator.ps1 b/eng/common/scripts/Get-PullRequestCreator.ps1 similarity index 77% rename from eng/common/scripts/Get-PrCreator.ps1 rename to eng/common/scripts/Get-PullRequestCreator.ps1 index 34cb86991b96..1b531ad5ee70 100644 --- a/eng/common/scripts/Get-PrCreator.ps1 +++ b/eng/common/scripts/Get-PullRequestCreator.ps1 @@ -13,7 +13,7 @@ param ( try { - $pullRequest = Get-PullRequest -RepoOwner $RepoOwner -RepoName $RepoName -PullRequestNumber $PullRequestNumber + $pullRequest = Get-GithubPullRequest -RepoOwner $RepoOwner -RepoName $RepoName -PullRequestNumber $PullRequestNumber Write-Host "##vso[task.setvariable variable=System.PullRequest.Creator;]$($pullRequest.user.login)" } catch diff --git a/eng/common/scripts/Invoke-GitHubAPI.ps1 b/eng/common/scripts/Invoke-GitHubAPI.ps1 index a263282766db..c5d2bea1db44 100644 --- a/eng/common/scripts/Invoke-GitHubAPI.ps1 +++ b/eng/common/scripts/Invoke-GitHubAPI.ps1 @@ -1,3 +1,7 @@ +if ((Get-ChildItem -Path Function: | ? { $_.Name -eq "LogWarning" }).Count -eq 0) { + . "${PSScriptRoot}\logging.ps1" +} + $GithubAPIBaseURI = "https://api.github.com/repos" function Get-GitHubHeaders ($token) { @@ -17,14 +21,26 @@ function Invoke-GitHubAPIPost { $token ) - $resp = Invoke-RestMethod ` - -Method POST ` - -Body ($body | ConvertTo-Json) ` - -Uri $apiURI ` - -Headers (Get-GitHubHeaders -token $token) ` - -MaximumRetryCount 3 - - return $resp + try { + if ($body.Count -gt 0) { + $resp = Invoke-RestMethod ` + -Method POST ` + -Body ($body | ConvertTo-Json) ` + -Uri $apiURI ` + -Headers (Get-GitHubHeaders -token $token) ` + -MaximumRetryCount 3 + + return $resp + } + else { + throw "Did not fire request because of empty body." + } + } + catch { + $warning = "{0} with Uri [ $apiURI ] failed. `nBody: [ {1} ]" -f (Get-PSCallStack)[1].FunctionName , ($body | Out-String) + LogWarning $warning + throw + } } function Invoke-GitHubAPIPatch { @@ -37,14 +53,26 @@ function Invoke-GitHubAPIPatch { $token ) - $resp = Invoke-RestMethod ` - -Method PATCH ` - -Body ($body | ConvertTo-Json) ` - -Uri $apiURI ` - -Headers (Get-GitHubHeaders -token $token) ` - -MaximumRetryCount 3 + try { + if ($body.Count -gt 0) { + $resp = Invoke-RestMethod ` + -Method PATCH ` + -Body ($body | ConvertTo-Json) ` + -Uri $apiURI ` + -Headers (Get-GitHubHeaders -token $token) ` + -MaximumRetryCount 3 - return $resp + return $resp + } + else { + throw "Did not fire request because of empty body." + } + } + catch { + $warning = "{0} with Uri [ $apiURI ] failed. `nBody: [ {1} ]" -f (Get-PSCallStack)[1].FunctionName , ($body | Out-String) + LogWarning $warning + throw + } } function Invoke-GitHubAPIDelete { @@ -55,13 +83,20 @@ function Invoke-GitHubAPIDelete { $token ) - $resp = Invoke-RestMethod ` + try { + $resp = Invoke-RestMethod ` -Method DELETE ` -Uri $apiURI ` -Headers (Get-GitHubHeaders -token $token) ` -MaximumRetryCount 3 - return $resp + return $resp + } + catch { + $warning = "{0} with Uri [ $apiURI ] failed." -f (Get-PSCallStack)[1].FunctionName + LogWarning $warning + throw + } } @@ -72,31 +107,48 @@ function Invoke-GitHubAPIGet { $token ) - if ($token) - { - $resp = Invoke-RestMethod ` - -Method GET ` - -Uri $apiURI ` - -Headers (Get-GitHubHeaders -token $token) ` - -MaximumRetryCount 3 + try { + if ($token) + { + $resp = Invoke-RestMethod ` + -Method GET ` + -Uri $apiURI ` + -Headers (Get-GitHubHeaders -token $token) ` + -MaximumRetryCount 3 + } + else { + $resp = Invoke-RestMethod ` + -Method GET ` + -Uri $apiURI ` + -MaximumRetryCount 3 + } + return $resp } - else { - $resp = Invoke-RestMethod ` - -Method GET ` - -Uri $apiURI ` - -MaximumRetryCount 3 + catch { + $warning = "{0} with Uri [ $apiURI ] failed." -f (Get-PSCallStack)[1].FunctionName + LogWarning $warning + throw } - - return $resp } -function SplitMembers ($membersString) -{ - if (!$membersString) { return $null } - return @($membersString.Split(",") | % { $_.Trim() } | ? { return $_ }) +function Set-GitHubAPIParameters ($members, $parameterName, $parameters, $allowEmptyMembers=$false) { + if ($null -ne $members) { + if ($members -is [array]) + { + $parameters[$parameterName] = $members + } + else { + $memberAdditions = @($members.Split(",") | % { $_.Trim() } | ? { return $_ }) + if (($memberAdditions.Count -gt 0) -or $allowEmptyMembers) { + $parameters[$parameterName] = $memberAdditions + } + } + } + + return $parameters } -function List-PullRequests { +function Get-GitHubPullRequests { param ( [Parameter(Mandatory = $true)] $RepoOwner, @@ -110,24 +162,19 @@ function List-PullRequests { $Sort, [ValidateSet("asc","desc")] $Direction, - [Parameter(DontShow)] - $PullRequestNumber + [ValidateNotNullOrEmpty()] + $AuthToken ) $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/pulls" - if ($State -or $Head -or $Base -or $Sort -or $Direction) { - $uri += '?' - } - elseif ($PullRequestNumber) { - $uri += "/${PullRequestNumber}" - } + if ($State -or $Head -or $Base -or $Sort -or $Direction) { $uri += '?' } if ($State) { $uri += "state=$State&" } if ($Head) { $uri += "head=$Head&" } if ($Base) { $uri += "base=$Base&" } if ($Sort) { $uri += "sort=$Sort&" } if ($Direction){ $uri += "direction=$Direction&" } - return Invoke-GitHubAPIGet -apiURI $uri + return Invoke-GitHubAPIGet -apiURI $uri -token $AuthToken } # @@ -136,35 +183,40 @@ function List-PullRequests { Ref to search for Pass 'heads/ ,tags/, or nothing #> -function List-References { +function Get-GitHubSourceReferences { param ( [Parameter(Mandatory = $true)] $RepoOwner, [Parameter(Mandatory = $true)] $RepoName, - $Ref + $Ref, + [ValidateNotNullOrEmpty()] + $AuthToken ) $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/git/matching-refs/" if ($Ref) { $uri += "$Ref" } - return Invoke-GitHubAPIGet -apiURI $uri + return Invoke-GitHubAPIGet -apiURI $uri -token $AuthToken } -function Get-PullRequest { +function Get-GitHubPullRequest { param ( [Parameter(Mandatory = $true)] $RepoOwner, [Parameter(Mandatory = $true)] $RepoName, [Parameter(Mandatory = $true)] - $PullRequestNumber + $PullRequestNumber, + [ValidateNotNullOrEmpty()] + $AuthToken ) - return List-PullRequests -RepoOwner $RepoOwner -RepoName $RepoName -PullRequestNumber $PullRequestNumber + $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/pulls/$PullRequestNumber" + return Invoke-GitHubAPIGet -apiURI $uri -token $AuthToken } -function Create-PullRequest { +function New-GitHubPullRequest { param ( [Parameter(Mandatory = $true)] $RepoOwner, @@ -179,6 +231,7 @@ function Create-PullRequest { $Body=$Title, [Boolean]$Maintainer_Can_Modify=$false, [Boolean]$Draft=$false, + [ValidateNotNullOrEmpty()] [Parameter(Mandatory = $true)] $AuthToken ) @@ -189,14 +242,14 @@ function Create-PullRequest { base = $Base body = $Body maintainer_can_modify = $Maintainer_Can_Modify - $draft = $Draft + draft = $Draft } $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/pulls" return Invoke-GitHubAPIPost -apiURI $uri -body $parameters -token $AuthToken } -function Add-IssueComment { +function Add-GitHubIssueComment { param ( [Parameter(Mandatory = $true)] $RepoOwner, @@ -206,6 +259,7 @@ function Add-IssueComment { $IssueNumber, [Parameter(Mandatory = $true)] $Comment, + [ValidateNotNullOrEmpty()] [Parameter(Mandatory = $true)] $AuthToken @@ -220,7 +274,7 @@ function Add-IssueComment { } # Will add labels to existing labels on the issue -function Add-IssueLabels { +function Add-GitHubIssueLabels { param ( [Parameter(Mandatory = $true)] $RepoOwner, @@ -231,27 +285,27 @@ function Add-IssueLabels { [ValidateNotNullOrEmpty()] [Parameter(Mandatory = $true)] $Labels, + [ValidateNotNullOrEmpty()] [Parameter(Mandatory = $true)] $AuthToken ) if ($Labels.Trim().Length -eq 0) { - throw "The 'Labels' parameter should not not be whitespace..` - You can use the 'Update-Issue' function if you plan to reset the labels" + throw " The 'Labels' parameter should not not be whitespace. + Use the 'Update-Issue' function if you plan to reset the labels" } $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/issues/$IssueNumber/labels" - $labelAdditions = SplitMembers -membersString $Labels - $parameters = @{ - labels = @($labelAdditions) - } + $parameters = @{} + $parameters = Set-GitHubAPIParameters -members $Labels -parameterName "labels" ` + -parameters $parameters return Invoke-GitHubAPIPost -apiURI $uri -body $parameters -token $AuthToken } # Will add assignees to existing assignees on the issue -function Add-IssueAssignees { +function Add-GitHubIssueAssignees { param ( [Parameter(Mandatory = $true)] $RepoOwner, @@ -262,26 +316,26 @@ function Add-IssueAssignees { [ValidateNotNullOrEmpty()] [Parameter(Mandatory = $true)] $Assignees, + [ValidateNotNullOrEmpty()] [Parameter(Mandatory = $true)] $AuthToken ) if ($Assignees.Trim().Length -eq 0) { - throw "The 'Assignees' parameter should not be whitespace.` + throw "The 'Assignees' parameter should not be whitespace. You can use the 'Update-Issue' function if you plan to reset the Assignees" } $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/issues/$IssueNumber/assignees" - $assigneesAdditions = SplitMembers -membersString $Assignees - $parameters = @{ - assignees = @($assigneesAdditions) - } + $parameters = @{} + $parameters = Set-GitHubAPIParameters -members $Assignees -parameterName "assignees" ` + -parameters $parameters return Invoke-GitHubAPIPost -apiURI $uri -body $parameters -token $AuthToken } -function Request-PrReviewer { +function Add-GitHubPullRequestReviewers { param ( [Parameter(Mandatory = $true)] $RepoOwner, @@ -291,47 +345,26 @@ function Request-PrReviewer { $PrNumber, $Users, $Teams, + [ValidateNotNullOrEmpty()] [Parameter(Mandatory = $true)] $AuthToken ) - if (!$users -and !$teams) - { - throw "You must specify either Users or Teams." - exit 1 - } - $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/pulls/$PrNumber/requested_reviewers" $parameters = @{} - if ($Users) { - if ($Users -is [array]) - { - $parameters["reviewers"] = @($Users) - } - else { - $userAdditions = SplitMembers -membersString $Users - $parameters["reviewers"] = @($userAdditions) - } - } + $parameters = Set-GitHubAPIParameters -members $Users -parameterName "reviewers" ` + -parameters $parameters - if ($Teams) { - if ($Teams -is [array]) - { - $parameters["team_reviewers"] = @($Teams) - } - else { - $teamAdditions = SplitMembers -membersString $Teams - $parameters["team_reviewers"] = @($teamAdditions) - } - } + $parameters = Set-GitHubAPIParameters -members $Teams -parameterName "team_reviewers" ` + -parameters $parameters - return Invoke-GitHubAPIPost -apiURI $uri -body $parameters -token AuthToken + return Invoke-GitHubAPIPost -apiURI $uri -body $parameters -token $AuthToken } # For labels and assignee pass comma delimited string, to replace existing labels or assignees. # Or pass white space " " to remove all labels or assignees -function Update-Issue { +function Update-GitHubIssue { param ( [Parameter(Mandatory = $true)] $RepoOwner, @@ -344,10 +377,9 @@ function Update-Issue { [ValidateSet("open","closed")] [string]$State, [int]$Milestome, - [ValidateNotNullOrEmpty()] $Labels, - [ValidateNotNullOrEmpty()] $Assignees, + [ValidateNotNullOrEmpty()] [Parameter(Mandatory = $true)] $AuthToken ) @@ -359,32 +391,16 @@ function Update-Issue { if ($State) { $parameters["state"] = $State } if ($Milestone) { $parameters["milestone"] = $Milestone } - if ($Labels) { - if ($Labels -is [array]) - { - $parameters["labels"] = @($Labels) - } - else { - $labelAdditions = SplitMembers -membersString $Labels - $parameters["labels"] = @($labelAdditions) - } - } + $parameters = Set-GitHubAPIParameters -members $Labels -parameterName "labels" ` + -parameters $parameters -allowEmptyMembers $true - if ($Assignees) { - if ($Assignees -is [array]) - { - $parameters["labels"] = @($Assignees) - } - else { - $assigneesAdditions = SplitMembers -membersString $Assignees - $parameters["assignees"] = @($assigneesAdditions) - } - } + $parameters = Set-GitHubAPIParameters -members $Assignees -parameterName "assignees" ` + -parameters $parameters -allowEmptyMembers $true return Invoke-GitHubAPIPatch -apiURI $uri -body $parameters -token $AuthToken } -function Delete-References { +function Remove-GitHubSourceReferences { param ( [Parameter(Mandatory = $true)] $RepoOwner, @@ -393,13 +409,14 @@ function Delete-References { [ValidateNotNullOrEmpty()] [Parameter(Mandatory = $true)] $Ref, + [ValidateNotNullOrEmpty()] [Parameter(Mandatory = $true)] $AuthToken ) if ($Ref.Trim().Length -eq 0) { - throw "You must supply a valid 'Ref' Parameter to 'Delete-Reference'." + throw "You must supply a valid 'Ref' Parameter to 'Delete-GithubSourceReferences'." } $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/git/refs/$Ref" diff --git a/eng/common/scripts/Submit-PullRequest.ps1 b/eng/common/scripts/Submit-PullRequest.ps1 index 3acc6b7fad99..58a082baaf26 100644 --- a/eng/common/scripts/Submit-PullRequest.ps1 +++ b/eng/common/scripts/Submit-PullRequest.ps1 @@ -48,58 +48,38 @@ param( [Parameter(Mandatory = $false)] [string]$PRBody = $PRTitle, - [Parameter(Mandatory = $false)] [string]$PRLabels, - [Parameter(Mandatory = $false)] [string]$UserReviewers, - [Parameter(Mandatory = $false)] [string]$TeamReviewers, - [Parameter(Mandatory = $false)] [string]$Assignees ) . "${PSScriptRoot}\common.ps1" try { - $resp = List-PullRequests -RepoOwner $RepoOwner -RepoName $RepoName` - -Head "${PROwner}:${PRBranch}" -Base $BaseBranch + $resp = Get-GitHubPullRequests -RepoOwner $RepoOwner -RepoName $RepoName ` + -Head "${PROwner}:${PRBranch}" -Base $BaseBranch } catch { - LogError "List-PullRequests failed with exception:`n$_" + LogError "Get-GitHubPullRequests failed with exception:`n$_" exit 1 } $resp | Write-Verbose if ($resp.Count -gt 0) { - try { - LogDebug "Pull request already exists $($resp[0].html_url)" - - # setting variable to reference the pull request by number - Write-Host "##vso[task.setvariable variable=Submitted.PullRequest.Number]$($resp[0].number)" - - $lablesArray = $resp[0].labels.name + ($PRLabels -split ',') | Sort-Object -Unique - $AssigneesArray = $resp[0].assignees.login + ($Assignees -split ',') | Sort-Object -Unique - - Update-Issue -RepoOwner $RepoOwner -RepoName $RepoName -IssueNumber $resp[0].number` - -Labels $lablesArray -Assignees $AssigneesArray -AuthToken $AuthToken - - Request-PrReviewer -RepoOwner $RepoOwner -RepoName $RepoName -PrNumber $resp[0].number` - -Users $UserReviewers -Teams $TeamReviewers -AuthToken $AuthToken - } - catch { - LogError "Call to GitHub API failed with exception:`n$_" - exit 1 - } + LogDebug "Pull request already exists $($resp[0].html_url)" + # setting variable to reference the pull request by number + Write-Host "##vso[task.setvariable variable=Submitted.PullRequest.Number]$($resp[0].number)" } else { try { - $resp = Create-PullRequest -RepoOwner $RepoOwner -RepoName $RepoName -Title $PRTitle` - -Head "${PROwner}:${PRBranch}" -Base $BaseBranch -Body $PRBody -Maintainer_Can_Modify $true` - -AuthToken $AuthToken + $resp = New-GitHubPullRequest -RepoOwner $RepoOwner -RepoName $RepoName -Title $PRTitle ` + -Head "${PROwner}:${PRBranch}" -Base $BaseBranch -Body $PRBody -Maintainer_Can_Modify $true ` + -AuthToken $AuthToken $resp | Write-Verbose LogDebug "Pull request created https://github.com/$RepoOwner/$RepoName/pull/$($resp.number)" @@ -107,10 +87,10 @@ else { # setting variable to reference the pull request by number Write-Host "##vso[task.setvariable variable=Submitted.PullRequest.Number]$($resp.number)" - Update-Issue -RepoOwner $RepoOwner -RepoName $RepoName -IssueNumber $resp.number` + Update-GitHubIssue -RepoOwner $RepoOwner -RepoName $RepoName -IssueNumber $resp.number ` -Labels $PRLabels -Assignees $Assignees -AuthToken $AuthToken - Request-PrReviewer -RepoOwner $RepoOwner -RepoName $RepoName -PrNumber $resp.number` + Add-GitHubPullRequestReviewers -RepoOwner $RepoOwner -RepoName $RepoName -PrNumber $resp.number ` -Users $UserReviewers -Teams $TeamReviewers -AuthToken $AuthToken } catch {