From e56db82c0e770c200d1ec3efba808e2997242c78 Mon Sep 17 00:00:00 2001 From: Chidozie Ononiwu Date: Tue, 6 Oct 2020 21:14:38 -0700 Subject: [PATCH 1/5] Add auto-merge label to sync PRs, Remove verify and merge step and add pipeline to clean-up sync PRs --- eng/common/scripts/Add-Issue-Comment.ps1 | 18 ++--- eng/common/scripts/Delete-Remote-Branches.ps1 | 38 ++++++++++ eng/common/scripts/Invoke-GitHub-API.ps1 | 72 +++++++++++++++++++ 3 files changed, 114 insertions(+), 14 deletions(-) create mode 100644 eng/common/scripts/Delete-Remote-Branches.ps1 create mode 100644 eng/common/scripts/Invoke-GitHub-API.ps1 diff --git a/eng/common/scripts/Add-Issue-Comment.ps1 b/eng/common/scripts/Add-Issue-Comment.ps1 index b945d70c3fe9..3b68833f0959 100644 --- a/eng/common/scripts/Add-Issue-Comment.ps1 +++ b/eng/common/scripts/Add-Issue-Comment.ps1 @@ -23,12 +23,7 @@ param( ) . "${PSScriptRoot}\logging.ps1" - -$headers = @{ - Authorization = "bearer $AuthToken" -} - -$apiUrl = "https://api.github.com/repos/$RepoOwner/$RepoName/issues/$IssueNumber/comments" +. "${PSScriptRoot}\Invoke-GitHub-API.ps1" $commentPrefixValue = [System.Environment]::GetEnvironmentVariable($CommentPrefix) $commentValue = [System.Environment]::GetEnvironmentVariable($Comment) @@ -38,16 +33,11 @@ if (!$commentPrefixValue) { $commentPrefixValue = $CommentPrefix } if (!$commentValue) { $commentValue = $Comment } if (!$commentPostFixValue) { $commentPostFixValue = $CommentPostFix } -$PRComment = "$commentPrefixValue $commentValue $commentPostFixValue" - -$data = @{ - body = $PRComment -} - try { - $resp = Invoke-RestMethod -Method POST -Headers $headers -Uri $apiUrl -Body ($data | ConvertTo-Json) + $resp = AddIssueComment -IssueNumber $IssueNumber -CommentPrefix $commentPrefixValue ` + -Comment $commentValue -CommentSuffix $commentPostFixValue } catch { - LogError "Invoke-RestMethod [ $apiUrl ] failed with exception:`n$_" + LogError "AddIssueComment failed with exception:`n$_" exit 1 } \ No newline at end of file diff --git a/eng/common/scripts/Delete-Remote-Branches.ps1 b/eng/common/scripts/Delete-Remote-Branches.ps1 new file mode 100644 index 000000000000..f44c8a42f4ff --- /dev/null +++ b/eng/common/scripts/Delete-Remote-Branches.ps1 @@ -0,0 +1,38 @@ +param( + $RepoOwner = "Azure", + $RepoName, + $BranchPrefix = "sync-eng/common", + $AuthToken +) + +. "${PSScriptRoot}\logging.ps1" +. "${PSScriptRoot}\Invoke-GitHub-API.ps1" + +git clone "https://github.com/$RepoOwner/$RepoName" +pushd $RepoName +$syncBranches = (git branch --remote).where{$_ -like "*origin/$BranchPrefix*"} + +Write-Host "Repo Name $RepoName" +foreach ($branch in $syncBranches) +{ + try { + $branchName = $branch.Trim() + $head = "${RepoOwner}/${RepoName}:${branchName}" + $response = ListPullRequests -RepoOwner $RepoOwner -RepoName $RepoName -head $head + } + catch + { + LogError "ListPullRequests failed with exception:`n$_" + exit 1 + } + Write-Host "Response Count $($Response.Count)" + if ($Response.Count -eq 0) + { + # Delete branch here + #git push origin --delete "sync-${{ parameters.DirectoryToSync }}-$(System.PullRequest.SourceBranch)-$(System.PullRequest.PullRequestNumber)" + #if ($lastExitCode -ne 0) { + # Write-Host "Failed to delete [sync-${{ parameters.DirectoryToSync }}-$(System.PullRequest.SourceBranch)-$(System.PullRequest.PullRequestNumber)] branch in ${{ repo }}" + # exit 1 + #} + } +} diff --git a/eng/common/scripts/Invoke-GitHub-API.ps1 b/eng/common/scripts/Invoke-GitHub-API.ps1 new file mode 100644 index 000000000000..fde33a0f0031 --- /dev/null +++ b/eng/common/scripts/Invoke-GitHub-API.ps1 @@ -0,0 +1,72 @@ +param( + $AuthToken +) + +$GithubAPIBaseURI = "https://api.github.com/repos" +function InvokePost($apiURI, $body) { + $resp = Invoke-RestMethod ` + -Method POST ` + -Body ($body | ConvertTo-Json) ` + -Uri $apiURI ` + -Authentication Bearer ` + -Token $AuthToken + -MaximumRetryCount 3 + ($body | Format-List | Write-Output) + $resp | Write-Verbose +} + +function InvokeGet($apiURI) { + $resp = Invoke-RestMethod ` + -Method GET ` + -Uri $apiURI ` + -Authentication Bearer ` + -Token $AuthToken + -MaximumRetryCount 3 + ($body | Format-List | Write-Output) + $resp | Write-Verbose +} + +function ListPullRequests { + param ( + [Parameter(Mandatory = $true)] + $RepoOwner, + [Parameter(Mandatory = $true)] + $RepoName, + [ValidateSet("open","closed","all")] + $state = "open", + $head, + $base, + [ValidateSet("created","updated","popularity","long-running")] + $sort, + [ValidateSet("asc","desc",)] + $direction + ) + + $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/pulls" + 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 InvokeGet -apiURI $uri +} + +function AddIssueComment { + param ( + [Parameter(Mandatory = $true)] + $IssueNumber, + $CommentPrefix, + [Parameter(Mandatory = $true)] + $Comment, + $CommentSuffix, + ) + $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/issues/$IssueNumber/comments" + $PRComment = "$CommentPrefix $Comment $CommentSuffix" + + $data = @{ + body = $PRComment + } + return InvokePost -apiURI $uri -body $data +} \ No newline at end of file From 8f8e8d95d5bd82264416cd325bb365a8a14ada4c Mon Sep 17 00:00:00 2001 From: Chidozie Ononiwu Date: Wed, 7 Oct 2020 15:41:10 -0700 Subject: [PATCH 2/5] Refactor GitHub API Calls --- eng/common/scripts/Add-Issue-Comment.ps1 | 5 +- eng/common/scripts/Delete-Remote-Branches.ps1 | 36 ++--- eng/common/scripts/Invoke-GitHub-API.ps1 | 127 ++++++++++++++++-- 3 files changed, 141 insertions(+), 27 deletions(-) diff --git a/eng/common/scripts/Add-Issue-Comment.ps1 b/eng/common/scripts/Add-Issue-Comment.ps1 index 3b68833f0959..d861b8a8608b 100644 --- a/eng/common/scripts/Add-Issue-Comment.ps1 +++ b/eng/common/scripts/Add-Issue-Comment.ps1 @@ -23,7 +23,7 @@ param( ) . "${PSScriptRoot}\logging.ps1" -. "${PSScriptRoot}\Invoke-GitHub-API.ps1" +. "${PSScriptRoot}\Invoke-GitHub-API.ps1" -AuthToken $AuthToken $commentPrefixValue = [System.Environment]::GetEnvironmentVariable($CommentPrefix) $commentValue = [System.Environment]::GetEnvironmentVariable($Comment) @@ -34,7 +34,8 @@ if (!$commentValue) { $commentValue = $Comment } if (!$commentPostFixValue) { $commentPostFixValue = $CommentPostFix } try { - $resp = AddIssueComment -IssueNumber $IssueNumber -CommentPrefix $commentPrefixValue ` + $resp = AddIssueComment -RepoOwner $RepoOwner -RepoName $RepoName ` + -IssueNumber $IssueNumber -CommentPrefix $commentPrefixValue ` -Comment $commentValue -CommentSuffix $commentPostFixValue } catch { diff --git a/eng/common/scripts/Delete-Remote-Branches.ps1 b/eng/common/scripts/Delete-Remote-Branches.ps1 index f44c8a42f4ff..0a7286fb408b 100644 --- a/eng/common/scripts/Delete-Remote-Branches.ps1 +++ b/eng/common/scripts/Delete-Remote-Branches.ps1 @@ -1,23 +1,26 @@ param( - $RepoOwner = "Azure", + $RepoOwner, $RepoName, - $BranchPrefix = "sync-eng/common", + $BranchPrefix, + $WorkingDirectory, $AuthToken ) . "${PSScriptRoot}\logging.ps1" -. "${PSScriptRoot}\Invoke-GitHub-API.ps1" +. "${PSScriptRoot}\Invoke-GitHub-API.ps1" -AuthToken $AuthToken -git clone "https://github.com/$RepoOwner/$RepoName" +pushd $WorkingDirectory +git clone https://github.com/$RepoOwner/$RepoName.git pushd $RepoName -$syncBranches = (git branch --remote).where{$_ -like "*origin/$BranchPrefix*"} +$syncBranches = (git branch --remote).where{ $_ -like "*origin/$BranchPrefix*" } -Write-Host "Repo Name $RepoName" +LogDebug "Operating on Repo [ $RepoName ]" foreach ($branch in $syncBranches) { try { - $branchName = $branch.Trim() + $branchName = ($branch.Trim()).Replace("origin/","") $head = "${RepoOwner}/${RepoName}:${branchName}" + LogDebug "Operating on branch [ $branchName ]" $response = ListPullRequests -RepoOwner $RepoOwner -RepoName $RepoName -head $head } catch @@ -25,14 +28,17 @@ foreach ($branch in $syncBranches) LogError "ListPullRequests failed with exception:`n$_" exit 1 } - Write-Host "Response Count $($Response.Count)" - if ($Response.Count -eq 0) + + if ($response.Count -eq 0) { - # Delete branch here - #git push origin --delete "sync-${{ parameters.DirectoryToSync }}-$(System.PullRequest.SourceBranch)-$(System.PullRequest.PullRequestNumber)" - #if ($lastExitCode -ne 0) { - # Write-Host "Failed to delete [sync-${{ parameters.DirectoryToSync }}-$(System.PullRequest.SourceBranch)-$(System.PullRequest.PullRequestNumber)] branch in ${{ repo }}" - # exit 1 - #} + LogDebug "Branch [ $branchName ] in repo [ $RepoName ] has no associated Pull Request. Deleting Branch" + git push origin --delete $branchName + if ($lastExitCode -ne 0) { + Write-Host "Failed to delete branch [ $branchName ] in repo [ $RepoName ]" + exit 1 + } } } + +popd +popd diff --git a/eng/common/scripts/Invoke-GitHub-API.ps1 b/eng/common/scripts/Invoke-GitHub-API.ps1 index fde33a0f0031..3c99c8303de0 100644 --- a/eng/common/scripts/Invoke-GitHub-API.ps1 +++ b/eng/common/scripts/Invoke-GitHub-API.ps1 @@ -2,6 +2,7 @@ param( $AuthToken ) +$Token = ConvertTo-SecureString -String $AuthToken -AsPlainText -Force $GithubAPIBaseURI = "https://api.github.com/repos" function InvokePost($apiURI, $body) { $resp = Invoke-RestMethod ` @@ -9,10 +10,22 @@ function InvokePost($apiURI, $body) { -Body ($body | ConvertTo-Json) ` -Uri $apiURI ` -Authentication Bearer ` - -Token $AuthToken + -Token $Token ` -MaximumRetryCount 3 - ($body | Format-List | Write-Output) - $resp | Write-Verbose + + return $resp +} + +function InvokePatch($apiURI, $body) { + $resp = Invoke-RestMethod ` + -Method PATCH ` + -Body ($body | ConvertTo-Json) ` + -Uri $apiURI ` + -Authentication Bearer ` + -Token $Token ` + -MaximumRetryCount 3 + + return $resp } function InvokeGet($apiURI) { @@ -20,10 +33,16 @@ function InvokeGet($apiURI) { -Method GET ` -Uri $apiURI ` -Authentication Bearer ` - -Token $AuthToken + -Token $Token ` -MaximumRetryCount 3 - ($body | Format-List | Write-Output) - $resp | Write-Verbose + + return $resp +} + +function SplitMembers ($membersString) +{ + if (!$membersString) { return $null } + return @($membersString.Split(",") | % { $_.Trim() } | ? { return $_ }) } function ListPullRequests { @@ -38,7 +57,7 @@ function ListPullRequests { $base, [ValidateSet("created","updated","popularity","long-running")] $sort, - [ValidateSet("asc","desc",)] + [ValidateSet("asc","desc")] $direction ) @@ -55,18 +74,106 @@ function ListPullRequests { function AddIssueComment { param ( + [Parameter(Mandatory = $true)] + $RepoOwner, + [Parameter(Mandatory = $true)] + $RepoName, [Parameter(Mandatory = $true)] $IssueNumber, $CommentPrefix, [Parameter(Mandatory = $true)] $Comment, - $CommentSuffix, + $CommentSuffix ) $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/issues/$IssueNumber/comments" $PRComment = "$CommentPrefix $Comment $CommentSuffix" - $data = @{ + $parameters = @{ body = $PRComment } - return InvokePost -apiURI $uri -body $data + return InvokePost -apiURI $uri -body $parameters +} + +# Will add labels to existing labels on the issue +function AddIssueLabels { + param ( + [Parameter(Mandatory = $true)] + $RepoOwner, + [Parameter(Mandatory = $true)] + $RepoName, + [Parameter(Mandatory = $true)] + $IssueNumber, + [ValidateNotNullOrEmpty()] + [Parameter(Mandatory = $true)] + $labels + ) + + $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/issues/$IssueNumber/labels" + $labelAdditions = SplitMembers -membersString $labels + $parameters = @{ + labels = @($labelAdditions) + } + + return InvokePost -apiURI $uri -body $parameters +} + +# Will add assignees to existing assignees on the issue +function AddIssueAssignees { + param ( + [Parameter(Mandatory = $true)] + $RepoOwner, + [Parameter(Mandatory = $true)] + $RepoName, + [Parameter(Mandatory = $true)] + $IssueNumber, + [ValidateNotNullOrEmpty()] + [Parameter(Mandatory = $true)] + $assignees + ) + + $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/issues/$IssueNumber/assignees" + $assigneesAdditions = SplitMembers -membersString $assignees + $parameters = @{ + assignees = @($assigneesAdditions) + } + + return InvokePost -apiURI $uri -body $parameters +} + +# 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 UpdateIssue { + param ( + [Parameter(Mandatory = $true)] + $RepoOwner, + [Parameter(Mandatory = $true)] + $RepoName, + [Parameter(Mandatory = $true)] + $IssueNumber, + [string]$title, + [string]$body, + [string]$state, + [int]$milestome, + [ValidateNotNullOrEmpty()] + [string]$labels, + [ValidateNotNullOrEmpty()] + [string]$assignees + ) + + $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/issues/$IssueNumber" + $parameters = @{} + if ($title) { $parameters["title"] = $title } + 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 ($assignees) { + $assigneesAdditions = SplitMembers -membersString $assignees + $parameters["assignees"] = @($assigneesAdditions) + } + + return InvokePatch -apiURI $uri -body $parameters } \ No newline at end of file From b0c5db1f771818cbb6ff42c467c18161c54309bd Mon Sep 17 00:00:00 2001 From: Chidozie Ononiwu Date: Wed, 7 Oct 2020 17:45:19 -0700 Subject: [PATCH 3/5] Remove Verify an Merge Stage, Add auto-merge label to the Tools PR --- eng/common/README.md | 17 +- eng/common/scripts/Add-Issue-Comment.ps1 | 22 +-- eng/common/scripts/Add-Issue-Labels.ps1 | 28 +++ eng/common/scripts/Delete-Remote-Branches.ps1 | 7 +- eng/common/scripts/Invoke-GitHub-API.ps1 | 175 +++++++++++------- eng/common/scripts/common.ps1 | 1 + 6 files changed, 151 insertions(+), 99 deletions(-) create mode 100644 eng/common/scripts/Add-Issue-Labels.ps1 diff --git a/eng/common/README.md b/eng/common/README.md index 3f279bc7c4a8..761b41534dc4 100644 --- a/eng/common/README.md +++ b/eng/common/README.md @@ -13,13 +13,12 @@ languages repos as they will be overwritten the next time an update is taken fro ### Workflow -The 'Sync eng/common directory' PRs will be created in the language repositories once a pull request that touches the eng/common directory is submitted against the master branch. This will make it easier for changes to be tested in each individual language repo before merging the changes in the azure-sdk-tools repo. The workflow is explained below: +The 'Sync eng/common directory' PRs will be created in the language repositories when a pull request that touches the eng/common directory is submitted against the master branch. This will make it easier for changes to be tested in each individual language repo before merging the changes in the azure-sdk-tools repo. The workflow is explained below: -1. Create a PR against Azure/azure-sdk-tools:master. This is the **Tools PR**. -2. `azure-sdk-tools - sync - eng-common` is run automatically. It creates **Sync PRs** in each of the connected language repositories using the format `Sync eng/common directory with azure-sdk-tools for PR {Tools PR Number}`. Each **Sync PR** will contain a link back to the **Tools PR** that triggered it. -3. More changes pushed to the **Tools PR**, will automatically triggered new pipeline runs in the respective **Sync PRs**. The **Sync PRs** are used to make sure the changes would not break any of the connected pipelines. -4. Once satisfied with the changes; - - First make sure all checks in the **Sync PRs** are green and approved. The **Tools PR** contains links to all the **Sync PRs**. If for some reason the PRs is blocked by a CI gate get someone with permission to override and manually merge the PR. - - To test the state of all the **Sync PRs**, you can download the `PRsCreated.txt` artifact from your `azure-sdk-tools - sync - eng-common` pipeline, then run `./eng/scripts/Verify-And-Merge-PRs.ps1 ` which will output the status of each associated PR. - - Next approve the `VerifyAndMerge` job for the `azure-sdk-tools - sync - eng-common` pipeline triggered by your **Tools PR** which will automatically merge all the **Sync PRs**. You need `azure-sdk` devops contributor permissions to reach the `azure-sdk-tools - sync - eng-common` pipeline. - - Finally merge the **Tools PR**. +1. Create a PR (**Tools PR**) in the `azure - sdk - tools` Repo with changes to eng/common directory. +2. `azure-sdk-tools - sync - eng-common` pipeline is triggered for the **Tools PR** +3. The `azure-sdk-tools - sync - eng-common` pipeline queues test runs using the dotnet, js, java and python template pipelines. This help to test the recent changes in the **Tools PR** +4. If there are changes in the **Tools PR** that will affect the release stage you should approve the release test pipelines by clicking the approval gate. The test (template) pipeline will automatically release the next eligible version without needing manual intervention for the versioning. Please approve your test releases as quickly as possible. A race condition may occur due to someone else queueing the pipeline and going all the way to release using your version while yours is still waiting. If this occurs manually rerun the pipeline that failed. +5. Repeat step 1 - 4 by pushing new changes to your **Tools PR** Do this until you have satisfactory test runs all the way to release of the template package if necessary. +6. Sign off on next stage of the sync pipeline using the approval gate. The CreateSyncPRs stage will create the sync PR in the various language repos. Before doing this you need to be satisfied with the testing from the previous steps. This stage will append the `auto-merge` label to the **Sync PRs** as well as the **Tools PR**. +6. Go review and approve each of your **Sync PRs**. The merging will happen automatically. diff --git a/eng/common/scripts/Add-Issue-Comment.ps1 b/eng/common/scripts/Add-Issue-Comment.ps1 index d861b8a8608b..55ee1e3bfe8d 100644 --- a/eng/common/scripts/Add-Issue-Comment.ps1 +++ b/eng/common/scripts/Add-Issue-Comment.ps1 @@ -9,34 +9,18 @@ param( [Parameter(Mandatory = $true)] [string]$IssueNumber, - [Parameter(Mandatory = $false)] - [string]$CommentPrefix, - [Parameter(Mandatory = $true)] [string]$Comment, - [Parameter(Mandatory = $false)] - [string]$CommentPostFix, - [Parameter(Mandatory = $true)] [string]$AuthToken ) -. "${PSScriptRoot}\logging.ps1" -. "${PSScriptRoot}\Invoke-GitHub-API.ps1" -AuthToken $AuthToken - -$commentPrefixValue = [System.Environment]::GetEnvironmentVariable($CommentPrefix) -$commentValue = [System.Environment]::GetEnvironmentVariable($Comment) -$commentPostFixValue = [System.Environment]::GetEnvironmentVariable($CommentPostFix) - -if (!$commentPrefixValue) { $commentPrefixValue = $CommentPrefix } -if (!$commentValue) { $commentValue = $Comment } -if (!$commentPostFixValue) { $commentPostFixValue = $CommentPostFix } +. "${PSScriptRoot}\common.ps1" try { - $resp = AddIssueComment -RepoOwner $RepoOwner -RepoName $RepoName ` - -IssueNumber $IssueNumber -CommentPrefix $commentPrefixValue ` - -Comment $commentValue -CommentSuffix $commentPostFixValue + AddIssueComment -RepoOwner $RepoOwner -RepoName $RepoName ` + -IssueNumber $IssueNumber -Comment $Comment -AuthToken $AuthToken } catch { LogError "AddIssueComment failed with exception:`n$_" diff --git a/eng/common/scripts/Add-Issue-Labels.ps1 b/eng/common/scripts/Add-Issue-Labels.ps1 new file mode 100644 index 000000000000..eedeba0647c3 --- /dev/null +++ b/eng/common/scripts/Add-Issue-Labels.ps1 @@ -0,0 +1,28 @@ +[CmdletBinding(SupportsShouldProcess = $true)] +param( + [Parameter(Mandatory = $true)] + [string]$RepoOwner, + + [Parameter(Mandatory = $true)] + [string]$RepoName, + + [Parameter(Mandatory = $true)] + [string]$IssueNumber, + + [Parameter(Mandatory = $true)] + [string]$Labels, + + [Parameter(Mandatory = $true)] + [string]$AuthToken +) + +. "${PSScriptRoot}\common.ps1" + +try { + AddIssueLabels -RepoOwner $RepoOwner -RepoName $RepoName ` + -IssueNumber $IssueNumber -Labels $Labels -AuthToken $AuthToken +} +catch { + LogError "AddIssueLabels failed with exception:`n$_" + exit 1 +} \ No newline at end of file diff --git a/eng/common/scripts/Delete-Remote-Branches.ps1 b/eng/common/scripts/Delete-Remote-Branches.ps1 index 0a7286fb408b..71dcf3982eca 100644 --- a/eng/common/scripts/Delete-Remote-Branches.ps1 +++ b/eng/common/scripts/Delete-Remote-Branches.ps1 @@ -6,19 +6,18 @@ param( $AuthToken ) -. "${PSScriptRoot}\logging.ps1" -. "${PSScriptRoot}\Invoke-GitHub-API.ps1" -AuthToken $AuthToken +. "${PSScriptRoot}\common.ps1" pushd $WorkingDirectory git clone https://github.com/$RepoOwner/$RepoName.git pushd $RepoName -$syncBranches = (git branch --remote).where{ $_ -like "*origin/$BranchPrefix*" } +$syncBranches = git branch -r --list origin/$BranchPrefix* | % { $_ -replace "origin/", "" } LogDebug "Operating on Repo [ $RepoName ]" foreach ($branch in $syncBranches) { try { - $branchName = ($branch.Trim()).Replace("origin/","") + $branchName = $branch.Trim() $head = "${RepoOwner}/${RepoName}:${branchName}" LogDebug "Operating on branch [ $branchName ]" $response = ListPullRequests -RepoOwner $RepoOwner -RepoName $RepoName -head $head diff --git a/eng/common/scripts/Invoke-GitHub-API.ps1 b/eng/common/scripts/Invoke-GitHub-API.ps1 index 3c99c8303de0..a5e91f302874 100644 --- a/eng/common/scripts/Invoke-GitHub-API.ps1 +++ b/eng/common/scripts/Invoke-GitHub-API.ps1 @@ -1,41 +1,74 @@ -param( - $AuthToken -) - -$Token = ConvertTo-SecureString -String $AuthToken -AsPlainText -Force $GithubAPIBaseURI = "https://api.github.com/repos" -function InvokePost($apiURI, $body) { - $resp = Invoke-RestMethod ` - -Method POST ` - -Body ($body | ConvertTo-Json) ` - -Uri $apiURI ` - -Authentication Bearer ` - -Token $Token ` - -MaximumRetryCount 3 - - return $resp + +function Get-Headers ($token) { + $headers = @{ + Authorization = "bearer $token" + } + return $headers } -function InvokePatch($apiURI, $body) { +function InvokePost { + param ( + [Parameter(Mandatory = $true)] + $apiURI, + [Parameter(Mandatory = $true)] + $body, + [Parameter(Mandatory = $true)] + $token + ) + $resp = Invoke-RestMethod ` - -Method PATCH ` - -Body ($body | ConvertTo-Json) ` - -Uri $apiURI ` - -Authentication Bearer ` - -Token $Token ` - -MaximumRetryCount 3 + -Method POST ` + -Body ($body | ConvertTo-Json) ` + -Uri $apiURI ` + -Headers (Get-Headers -token $token) ` + -MaximumRetryCount 3 return $resp } -function InvokeGet($apiURI) { +function InvokePatch { + param ( + [Parameter(Mandatory = $true)] + $apiURI, + [Parameter(Mandatory = $true)] + $body, + [Parameter(Mandatory = $true)] + $token + ) + $resp = Invoke-RestMethod ` + -Method PATCH ` + -Body ($body | ConvertTo-Json) ` + -Uri $apiURI ` + -Headers (Get-Headers -token $token) ` + -MaximumRetryCount 3 + + return $resp +} + +function InvokeGet { + param ( + [Parameter(Mandatory = $true)] + $apiURI, + $token + ) + + if ($token) + { + $resp = Invoke-RestMethod ` + -Method GET ` + -Uri $apiURI ` + -Headers (Get-Headers -token $token) ` + -MaximumRetryCount 3 + } + else { + $resp = Invoke-RestMethod ` -Method GET ` -Uri $apiURI ` - -Authentication Bearer ` - -Token $Token ` -MaximumRetryCount 3 - + } + return $resp } @@ -52,22 +85,22 @@ function ListPullRequests { [Parameter(Mandatory = $true)] $RepoName, [ValidateSet("open","closed","all")] - $state = "open", - $head, - $base, + $State = "open", + $Head, + $Base, [ValidateSet("created","updated","popularity","long-running")] - $sort, + $Sort, [ValidateSet("asc","desc")] - $direction + $Direction ) $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/pulls" - 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&" } + 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 InvokeGet -apiURI $uri } @@ -80,18 +113,19 @@ function AddIssueComment { $RepoName, [Parameter(Mandatory = $true)] $IssueNumber, - $CommentPrefix, [Parameter(Mandatory = $true)] $Comment, - $CommentSuffix + [Parameter(Mandatory = $true)] + $AuthToken + ) $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/issues/$IssueNumber/comments" - $PRComment = "$CommentPrefix $Comment $CommentSuffix" $parameters = @{ - body = $PRComment + body = $Comment } - return InvokePost -apiURI $uri -body $parameters + + return InvokePost -apiURI $uri -body $parameters -token $AuthToken } # Will add labels to existing labels on the issue @@ -105,16 +139,18 @@ function AddIssueLabels { $IssueNumber, [ValidateNotNullOrEmpty()] [Parameter(Mandatory = $true)] - $labels + $Labels, + [Parameter(Mandatory = $true)] + $AuthToken ) $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/issues/$IssueNumber/labels" - $labelAdditions = SplitMembers -membersString $labels + $labelAdditions = SplitMembers -membersString $Labels $parameters = @{ - labels = @($labelAdditions) + labels = $labelAdditions } - return InvokePost -apiURI $uri -body $parameters + return InvokePost -apiURI $uri -body $parameters -token $AuthToken } # Will add assignees to existing assignees on the issue @@ -128,16 +164,18 @@ function AddIssueAssignees { $IssueNumber, [ValidateNotNullOrEmpty()] [Parameter(Mandatory = $true)] - $assignees + $Assignees, + [Parameter(Mandatory = $true)] + $AuthToken ) $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/issues/$IssueNumber/assignees" - $assigneesAdditions = SplitMembers -membersString $assignees + $assigneesAdditions = SplitMembers -membersString $Assignees $parameters = @{ - assignees = @($assigneesAdditions) + assignees = $assigneesAdditions } - return InvokePost -apiURI $uri -body $parameters + return InvokePost -apiURI $uri -body $parameters -token $AuthToken } # For labels and assignee pass comma delimited string, to replace existing labels or assignees. @@ -150,30 +188,33 @@ function UpdateIssue { $RepoName, [Parameter(Mandatory = $true)] $IssueNumber, - [string]$title, - [string]$body, - [string]$state, - [int]$milestome, + [string]$Title, + [string]$Body, + [ValidateSet("open","closed")] + [string]$State, + [int]$Milestome, [ValidateNotNullOrEmpty()] - [string]$labels, + [string]$Labels, [ValidateNotNullOrEmpty()] - [string]$assignees + [string]$Assignees, + [Parameter(Mandatory = $true)] + $AuthToken ) $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/issues/$IssueNumber" $parameters = @{} - if ($title) { $parameters["title"] = $title } - 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 ($Title) { $parameters["title"] = $Title } + 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 ($assignees) { - $assigneesAdditions = SplitMembers -membersString $assignees - $parameters["assignees"] = @($assigneesAdditions) + if ($Assignees) { + $assigneesAdditions = SplitMembers -membersString $Assignees + $parameters["assignees"] = $assigneesAdditions } - return InvokePatch -apiURI $uri -body $parameters + return InvokePatch -apiURI $uri -body $parameters -token $AuthToken } \ No newline at end of file diff --git a/eng/common/scripts/common.ps1 b/eng/common/scripts/common.ps1 index 4caaacc4e2cf..38501c646c46 100644 --- a/eng/common/scripts/common.ps1 +++ b/eng/common/scripts/common.ps1 @@ -9,6 +9,7 @@ $EngScriptsDir = Join-Path $EngDir "scripts" . (Join-Path $EngCommonScriptsDir ChangeLog-Operations.ps1) . (Join-Path $EngCommonScriptsDir Package-Properties.ps1) . (Join-Path $EngCommonScriptsDir logging.ps1) +. (Join-Path $EngCommonScriptsDir Invoke-GitHub-API.ps1) # Setting expected from common languages settings $Language = "Unknown" From 4219186b100c8746eabb192f43a4337b3f10aa1f Mon Sep 17 00:00:00 2001 From: Chidozie Ononiwu Date: Mon, 12 Oct 2020 10:15:15 -0700 Subject: [PATCH 4/5] Remove Cleanup Pipeline Scripts --- eng/common/scripts/Delete-Remote-Branches.ps1 | 43 ------------------- 1 file changed, 43 deletions(-) delete mode 100644 eng/common/scripts/Delete-Remote-Branches.ps1 diff --git a/eng/common/scripts/Delete-Remote-Branches.ps1 b/eng/common/scripts/Delete-Remote-Branches.ps1 deleted file mode 100644 index 71dcf3982eca..000000000000 --- a/eng/common/scripts/Delete-Remote-Branches.ps1 +++ /dev/null @@ -1,43 +0,0 @@ -param( - $RepoOwner, - $RepoName, - $BranchPrefix, - $WorkingDirectory, - $AuthToken -) - -. "${PSScriptRoot}\common.ps1" - -pushd $WorkingDirectory -git clone https://github.com/$RepoOwner/$RepoName.git -pushd $RepoName -$syncBranches = git branch -r --list origin/$BranchPrefix* | % { $_ -replace "origin/", "" } - -LogDebug "Operating on Repo [ $RepoName ]" -foreach ($branch in $syncBranches) -{ - try { - $branchName = $branch.Trim() - $head = "${RepoOwner}/${RepoName}:${branchName}" - LogDebug "Operating on branch [ $branchName ]" - $response = ListPullRequests -RepoOwner $RepoOwner -RepoName $RepoName -head $head - } - catch - { - LogError "ListPullRequests failed with exception:`n$_" - exit 1 - } - - if ($response.Count -eq 0) - { - LogDebug "Branch [ $branchName ] in repo [ $RepoName ] has no associated Pull Request. Deleting Branch" - git push origin --delete $branchName - if ($lastExitCode -ne 0) { - Write-Host "Failed to delete branch [ $branchName ] in repo [ $RepoName ]" - exit 1 - } - } -} - -popd -popd From 39898f418ab1076c34783e02af9e86f738bf0637 Mon Sep 17 00:00:00 2001 From: Chidozie Ononiwu Date: Mon, 12 Oct 2020 11:12:28 -0700 Subject: [PATCH 5/5] Fix github verb names --- eng/common/README.md | 12 +++-- ...Issue-Comment.ps1 => Add-IssueComment.ps1} | 4 +- ...d-Issue-Labels.ps1 => Add-IssueLabels.ps1} | 4 +- ...ke-GitHub-API.ps1 => Invoke-GitHubAPI.ps1} | 54 +++++++++++-------- eng/common/scripts/common.ps1 | 2 +- 5 files changed, 45 insertions(+), 31 deletions(-) rename eng/common/scripts/{Add-Issue-Comment.ps1 => Add-IssueComment.ps1} (79%) rename eng/common/scripts/{Add-Issue-Labels.ps1 => Add-IssueLabels.ps1} (79%) rename eng/common/scripts/{Invoke-GitHub-API.ps1 => Invoke-GitHubAPI.ps1} (76%) diff --git a/eng/common/README.md b/eng/common/README.md index 761b41534dc4..e63b74367b74 100644 --- a/eng/common/README.md +++ b/eng/common/README.md @@ -15,10 +15,12 @@ languages repos as they will be overwritten the next time an update is taken fro The 'Sync eng/common directory' PRs will be created in the language repositories when a pull request that touches the eng/common directory is submitted against the master branch. This will make it easier for changes to be tested in each individual language repo before merging the changes in the azure-sdk-tools repo. The workflow is explained below: -1. Create a PR (**Tools PR**) in the `azure - sdk - tools` Repo with changes to eng/common directory. +1. Create a PR (**Tools PR**) in the `azure-sdk-tools` repo with changes to eng/common directory. 2. `azure-sdk-tools - sync - eng-common` pipeline is triggered for the **Tools PR** -3. The `azure-sdk-tools - sync - eng-common` pipeline queues test runs using the dotnet, js, java and python template pipelines. This help to test the recent changes in the **Tools PR** +3. The `azure-sdk-tools - sync - eng-common` pipeline queues test runs for template pipelines in various languages. These help you test your changes in the **Tools PR**. 4. If there are changes in the **Tools PR** that will affect the release stage you should approve the release test pipelines by clicking the approval gate. The test (template) pipeline will automatically release the next eligible version without needing manual intervention for the versioning. Please approve your test releases as quickly as possible. A race condition may occur due to someone else queueing the pipeline and going all the way to release using your version while yours is still waiting. If this occurs manually rerun the pipeline that failed. -5. Repeat step 1 - 4 by pushing new changes to your **Tools PR** Do this until you have satisfactory test runs all the way to release of the template package if necessary. -6. Sign off on next stage of the sync pipeline using the approval gate. The CreateSyncPRs stage will create the sync PR in the various language repos. Before doing this you need to be satisfied with the testing from the previous steps. This stage will append the `auto-merge` label to the **Sync PRs** as well as the **Tools PR**. -6. Go review and approve each of your **Sync PRs**. The merging will happen automatically. +5. If you make additional changes to your **Tools PR** repeat steps 1 - 4 until you have completed the necessary testing of your changes. This includes full releases of the template package, if necessary. +6. Sign off on CreateSyncPRs stage of the sync pipeline using the approval gate. This stage will create the **Sync PRs** in the various language repos with the `auto-merge` label applied. A link to each of the **Sync PRs** will show up in the **Tools PR** for you to click and review. +7. Go review and approve each of your **Sync PRs**. The merging will happen automatically. +8. Sign off on VerifyAndMerge stage of the sync pipeline using the approval gate. This stage will merge any remaining open **Sync PRs** and also append `auto-merge` to the **Tools PR** so it will automatically merge once the pipeline finishes. +7. Sign Off on the VerifyAndMerge stage. This will merge any remaining open **Sync PR** and also append `auto-merge` to the **Tools PR**. diff --git a/eng/common/scripts/Add-Issue-Comment.ps1 b/eng/common/scripts/Add-IssueComment.ps1 similarity index 79% rename from eng/common/scripts/Add-Issue-Comment.ps1 rename to eng/common/scripts/Add-IssueComment.ps1 index 55ee1e3bfe8d..7b797a12d418 100644 --- a/eng/common/scripts/Add-Issue-Comment.ps1 +++ b/eng/common/scripts/Add-IssueComment.ps1 @@ -19,10 +19,10 @@ param( . "${PSScriptRoot}\common.ps1" try { - AddIssueComment -RepoOwner $RepoOwner -RepoName $RepoName ` + Add-IssueComment -RepoOwner $RepoOwner -RepoName $RepoName ` -IssueNumber $IssueNumber -Comment $Comment -AuthToken $AuthToken } catch { - LogError "AddIssueComment failed with exception:`n$_" + LogError "Add-IssueComment failed with exception:`n$_" exit 1 } \ No newline at end of file diff --git a/eng/common/scripts/Add-Issue-Labels.ps1 b/eng/common/scripts/Add-IssueLabels.ps1 similarity index 79% rename from eng/common/scripts/Add-Issue-Labels.ps1 rename to eng/common/scripts/Add-IssueLabels.ps1 index eedeba0647c3..7f0debe35610 100644 --- a/eng/common/scripts/Add-Issue-Labels.ps1 +++ b/eng/common/scripts/Add-IssueLabels.ps1 @@ -19,10 +19,10 @@ param( . "${PSScriptRoot}\common.ps1" try { - AddIssueLabels -RepoOwner $RepoOwner -RepoName $RepoName ` + Add-IssueLabels -RepoOwner $RepoOwner -RepoName $RepoName ` -IssueNumber $IssueNumber -Labels $Labels -AuthToken $AuthToken } catch { - LogError "AddIssueLabels failed with exception:`n$_" + LogError "Add-IssueLabels failed with exception:`n$_" exit 1 } \ No newline at end of file diff --git a/eng/common/scripts/Invoke-GitHub-API.ps1 b/eng/common/scripts/Invoke-GitHubAPI.ps1 similarity index 76% rename from eng/common/scripts/Invoke-GitHub-API.ps1 rename to eng/common/scripts/Invoke-GitHubAPI.ps1 index a5e91f302874..e2836856dc9f 100644 --- a/eng/common/scripts/Invoke-GitHub-API.ps1 +++ b/eng/common/scripts/Invoke-GitHubAPI.ps1 @@ -1,13 +1,13 @@ $GithubAPIBaseURI = "https://api.github.com/repos" -function Get-Headers ($token) { +function Get-GitHubHeaders ($token) { $headers = @{ Authorization = "bearer $token" } return $headers } -function InvokePost { +function Invoke-GitHubAPIPost { param ( [Parameter(Mandatory = $true)] $apiURI, @@ -21,13 +21,13 @@ function InvokePost { -Method POST ` -Body ($body | ConvertTo-Json) ` -Uri $apiURI ` - -Headers (Get-Headers -token $token) ` + -Headers (Get-GitHubHeaders -token $token) ` -MaximumRetryCount 3 return $resp } -function InvokePatch { +function Invoke-GitHubAPIPatch { param ( [Parameter(Mandatory = $true)] $apiURI, @@ -41,13 +41,13 @@ function InvokePatch { -Method PATCH ` -Body ($body | ConvertTo-Json) ` -Uri $apiURI ` - -Headers (Get-Headers -token $token) ` + -Headers (Get-GitHubHeaders -token $token) ` -MaximumRetryCount 3 return $resp } -function InvokeGet { +function Invoke-GitHubAPIGet { param ( [Parameter(Mandatory = $true)] $apiURI, @@ -59,7 +59,7 @@ function InvokeGet { $resp = Invoke-RestMethod ` -Method GET ` -Uri $apiURI ` - -Headers (Get-Headers -token $token) ` + -Headers (Get-GitHubHeaders -token $token) ` -MaximumRetryCount 3 } else { @@ -78,7 +78,7 @@ function SplitMembers ($membersString) return @($membersString.Split(",") | % { $_.Trim() } | ? { return $_ }) } -function ListPullRequests { +function List-PullRequests { param ( [Parameter(Mandatory = $true)] $RepoOwner, @@ -102,10 +102,10 @@ function ListPullRequests { if ($Sort) { $uri += "sort=$Sort&" } if ($Direction){ $uri += "direction=$Direction&" } - return InvokeGet -apiURI $uri + return Invoke-GitHubAPIGet -apiURI $uri } -function AddIssueComment { +function Add-IssueComment { param ( [Parameter(Mandatory = $true)] $RepoOwner, @@ -125,11 +125,11 @@ function AddIssueComment { body = $Comment } - return InvokePost -apiURI $uri -body $parameters -token $AuthToken + return Invoke-GitHubAPIPost -apiURI $uri -body $parameters -token $AuthToken } # Will add labels to existing labels on the issue -function AddIssueLabels { +function Add-IssueLabels { param ( [Parameter(Mandatory = $true)] $RepoOwner, @@ -144,17 +144,23 @@ function AddIssueLabels { $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" + } + $uri = "$GithubAPIBaseURI/$RepoOwner/$RepoName/issues/$IssueNumber/labels" $labelAdditions = SplitMembers -membersString $Labels $parameters = @{ - labels = $labelAdditions + labels = @($labelAdditions) } - return InvokePost -apiURI $uri -body $parameters -token $AuthToken + return Invoke-GitHubAPIPost -apiURI $uri -body $parameters -token $AuthToken } # Will add assignees to existing assignees on the issue -function AddIssueAssignees { +function Add-IssueAssignees { param ( [Parameter(Mandatory = $true)] $RepoOwner, @@ -169,18 +175,24 @@ function AddIssueAssignees { $AuthToken ) + if ($Assignees.Trim().Length -eq 0) + { + 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 + assignees = @($assigneesAdditions) } - return InvokePost -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 UpdateIssue { +function Update-Issue { param ( [Parameter(Mandatory = $true)] $RepoOwner, @@ -209,12 +221,12 @@ function UpdateIssue { if ($Milestone) { $parameters["milestone"] = $Milestone } if ($Labels) { $labelAdditions = SplitMembers -membersString $Labels - $parameters["labels"] = $labelAdditions + $parameters["labels"] = @($labelAdditions) } if ($Assignees) { $assigneesAdditions = SplitMembers -membersString $Assignees - $parameters["assignees"] = $assigneesAdditions + $parameters["assignees"] = @($assigneesAdditions) } - return InvokePatch -apiURI $uri -body $parameters -token $AuthToken + return Invoke-GitHubAPIPatch -apiURI $uri -body $parameters -token $AuthToken } \ No newline at end of file diff --git a/eng/common/scripts/common.ps1 b/eng/common/scripts/common.ps1 index 38501c646c46..1f1228fce7f2 100644 --- a/eng/common/scripts/common.ps1 +++ b/eng/common/scripts/common.ps1 @@ -9,7 +9,7 @@ $EngScriptsDir = Join-Path $EngDir "scripts" . (Join-Path $EngCommonScriptsDir ChangeLog-Operations.ps1) . (Join-Path $EngCommonScriptsDir Package-Properties.ps1) . (Join-Path $EngCommonScriptsDir logging.ps1) -. (Join-Path $EngCommonScriptsDir Invoke-GitHub-API.ps1) +. (Join-Path $EngCommonScriptsDir Invoke-GitHubAPI.ps1) # Setting expected from common languages settings $Language = "Unknown"