Update whats-happening-azure-data-studio.md #20
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Allow signoff for files | |
| permissions: | |
| pull-requests: write | |
| statuses: write | |
| on: | |
| issue_comment: | |
| types: [created] | |
| pull_request_target: | |
| types: [opened] | |
| jobs: | |
| build: | |
| name: Run Script | |
| if: github.repository_visibility == 'private' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Script | |
| shell: pwsh | |
| env: | |
| PayloadJson: ${{ toJSON(github) }} | |
| AccessToken: ${{ secrets.GITHUB_TOKEN }} | |
| # For testing set to a little used folder as the only target | |
| BlockedFilesAndFolders: '[ | |
| "ssms/f1-help/connect-to-microsoft-azure-storage.md", | |
| "ssms/f1-help/connect-to-any-sql-server-component-from-sql-server-management-studio.md" | |
| ]' | |
| run: | | |
| # Print out current date and time | |
| $currentDateTime = Get-Date | |
| $currentDateTimeString = "{0:yyyy-MM-dd HH:mm:ss}" -f $currentDateTime | |
| Write-Output "Run start: $currentDateTimeString" | |
| # Get GitHub data and event | |
| $GitHubData = $env:PayloadJson | ConvertFrom-Json -Depth 50 | |
| $GitRequestEvent = $GitHubData.event_name | |
| if ($GitRequestEvent -eq "issue_comment") | |
| { | |
| $PrGitHubLink = $GitHubData.event.issue.html_url | |
| } | |
| $AccessToken = $env:AccessToken | |
| $BlockedFilesAndFolders = $env:BlockedFilesAndFolders | ConvertFrom-Json | |
| $DefaultBranch = $GitHubData.event.repository.default_branch | |
| If ($GitRequestEvent -eq "issue_comment") {$GitHubState = $GitHubData.event.issue.state} ElseIf ($GitRequestEvent -eq "pull_request_target") {$GitHubState = $GitHubData.event.pull_request.state} | |
| $GitHubAction = $GitHubData.event.action | |
| $GitHubSender = $GitHubData.event.sender.login | |
| $GitHubRepoName = $GitHubData.event.repository.name | |
| $CommentUser = $GitHubData.event.comment.user.login | |
| $PullRequestOpener = $GitHubData.event.pull_request.user.login | |
| If ($GitRequestEvent -eq "issue_comment") | |
| { | |
| $PrIssueNumber = $GitHubData.event.issue.number | |
| $PrUrl = $GitHubData.event.issue.pull_request.url | |
| $IssueUrl = $GitHubData.event.issue.url | |
| $CommentsUrl = $GitHubData.event.issue.comments_url | |
| } | |
| ElseIf ($GitRequestEvent -eq "pull_request_target") | |
| { | |
| $PrIssueNumber = $GitHubData.event.pull_request.number | |
| $PrUrl = $GitHubData.event.pull_request.html_url | |
| $IssueUrl = $GitHubData.event.pull_request.issue_url | |
| $CommentsUrl = $GitHubData.event.pull_request.comments_url | |
| } | |
| If ($GitRequestEvent -eq "issue_comment") {$PrUrl = $GitHubData.event.issue.pull_request.url} ElseIf ($GitRequestEvent -eq "pull_request_target") {$PrUrl = $GitHubData.event.pull_request.url} | |
| $UserPermissionUrl = $GitHubData.event.repository.collaborators_url.Replace("{/collaborator}", "/$CommentUser/permission" ) | |
| $UserPermissionPROpenerUrl = $GitHubData.event.repository.collaborators_url.Replace("{/collaborator}", "/$PullRequestOpener/permission" ) | |
| $RepoLabelUrl = $GitHubData.event.repository.labels_url | |
| $GitHubHeaders = @{} | |
| $GitHubHeaders.Add("Authorization","token $($AccessToken)") | |
| $GitHubHeaders.Add("User-Agent", "OfficeDocs") | |
| $StatusHelpUrl = "https://dev.azure.com/msft-skilling/Content/_wiki/wikis/Database%20Docs/2358/Partner-publishing-workflow-pilot" | |
| $StatusCheckName = "Allow sign-off of PR files" | |
| $Status = @{} | |
| $Status.Add("context", $StatusCheckName) | |
| $Status.Add("target_url", $StatusHelpUrl) | |
| $CatastrophicError = $False | |
| $SignoffApprovalMessage = "Signoff approved by content team." | |
| $SignoffBlockedMessage = "PR contains files under temporary content freeze." | |
| $SignOffString = "#sign-off" | |
| $ApprovedString = "#approve-files" | |
| $SignOffRegex = "\s*$SignOffString\s*" | |
| $ApprovedRegex = "\s*$ApprovedString\s*" | |
| $EscalationEmail = "[Data Docs Team](mailto:[email protected]?subject=[PR%20REVIEW]%20Question%20on%20$GitHubRepoName%20PR%20$PrIssueNumber&body=$PrGitHubLink)" | |
| $ContentLeadsUrl = "[the content lead in your area](https://dev.azure.com/msft-skilling/Content/_dashboards/dashboard/b25043af-cab3-4b2c-8aac-9e8da15a796b)" | |
| $PRContainsBlockedFilesMessage = "This PR contains files that are temporarily blocked from edits due to a conference-related file-specific content freeze. You can attempt to merge this PR after the upcoming conference. If you have any questions, please reach out to $ContentLeadsUrl or email the $EscalationEmail." | |
| $CheckFailed = $False | |
| $ContentApprovedLabelColor = "2A8000" | |
| $ContentApprovedLabelDescription = "Changes are permitted to the files in this PR." | |
| $ContentApprovedLabel = "pr-files-approved" | |
| $FilesBlockedForConfLabelColor = "eeee88" | |
| $FilesBlockedForConfLabelDescription = "Files in PR were blocked from sign off due to upcoming conference." | |
| $FilesBlockedForConfLabel = "files-blocked-for-conference" | |
| Write-Host "Repo: $GitHubRepoName" | |
| Write-Host "Sender: $GitHubSender" | |
| Write-Host "Request event: $GitRequestEvent" | |
| Write-Host "GitHub action: $GitHubAction" | |
| Write-Host "GitHub state: $GitHubState" | |
| Write-Host "Default branch: $DefaultBranch" | |
| Write-Host "PR number: $PrIssueNumber" | |
| Write-Host "Issue URL: $IssueUrl" | |
| Write-Host "PR URL: $PrGitHubLink" | |
| Write-Host "User Permission URL: $UserPermissionUrl" | |
| Write-Host "User Permission URL (PR Opener): $UserPermissionPROpenerUrl" | |
| Write-Host "Commenter user name: $CommentUser" | |
| Write-Host "Pull request opener name: $PullRequestOpener" | |
| # Make the job summary section show up so the job always looks consistent. | |
| echo "" >> $env:GITHUB_STEP_SUMMARY | |
| ##################### | |
| ##################### | |
| # Initialize-Labels | |
| Function Initialize-Labels | |
| { | |
| Write-Host "Initialize labels needed by the workflow" | |
| Initialize-Label -LabelName $ContentApprovedLabel -LabelColor $ContentApprovedLabelColor -LabelDescription $ContentApprovedLabelDescription | |
| Initialize-Label -LabelName $FilesBlockedForConfLabel -LabelColor $FilesBlockedForConfLabelColor -LabelDescription $FilesBlockedForConfLabelDescription | |
| } | |
| ##################### | |
| ##################### | |
| # Initialize-Label | |
| Function Initialize-Label { | |
| [CmdletBinding()] | |
| param( | |
| $LabelName, | |
| $LabelColor, | |
| $LabelDescription | |
| ) | |
| # Check if label exists on the *REPO*. | |
| $LabelExists = Test-RepoLabel -RepoUri $RepoLabelUrl -Name $LabelName | |
| If (!$LabelExists) | |
| { | |
| # Create label on the *REPO* if it doesn't exist. | |
| New-RepoLabel -RepoUri $RepoLabelUrl -Name $LabelName -Color $LabelColor -Description $LabelDescription | |
| } | |
| } | |
| ##################### | |
| ##################### | |
| # Test-RepoLabel | |
| Function Test-RepoLabel { | |
| [CmdletBinding()] | |
| param( | |
| $Name, | |
| $RepoUri | |
| ) | |
| # Replace placeholder text in the URL retrieved from the GitHub API with the name of the label we're looking for | |
| $LabelUri = $RepoUri.Replace("{/name}","/$Name") | |
| # Check to see if the label we want exists in the repo | |
| Try { | |
| Write-Host "Checking to see if label $Name exists in repo URL $LabelUri." | |
| $LabelResults = Invoke-WebRequest -UseBasicParsing -Uri $LabelUri -Headers $GitHubHeaders -ErrorAction Stop | |
| $LabelFound = $True | |
| } Catch { | |
| # OK if label doesn't exist. Just means we need to create it. | |
| $LabelFound = $False | |
| } | |
| # Return boolean to calling statement | |
| $LabelFound | |
| } | |
| ##################### | |
| ##################### | |
| # New-RepoLabel | |
| Function New-RepoLabel { | |
| [CmdletBinding()] | |
| param( | |
| $Name, | |
| $Color, | |
| $Description, | |
| $RepoUri | |
| ) | |
| # Remove placeholder text from repo URL | |
| $RepoUri = $RepoUri.Replace("{/name}","") | |
| $Result = $Null | |
| # Construct the JSON statement that will be sent to GitHub as the body of the web request. Include the name of the label, its color, and description. | |
| # Convert hash table to JSON | |
| $Body = @{} | |
| $Body.Add("name", $Name) | |
| $Body.Add("color", $Color) | |
| $Body.Add("description", $description) | |
| $Body = $Body | ConvertTo-Json | |
| # Try to submit the request to GitHub API to create the label | |
| Try { | |
| Write-Host "Creating label $Name in repo $RepoUri." | |
| $Result = Invoke-RestMethod -Uri $RepoUri -Headers $GitHubHeaders -Body $Body -Method POST | |
| } Catch { | |
| Write-Error "ERROR: Failed to create new label $Name on repo $RepoUri. Error: $($Error[0].Exception.Message)." | |
| } | |
| } | |
| ##################### | |
| ##################### | |
| # Test-PrLabel | |
| Function Test-PrLabel { | |
| [CmdletBinding()] | |
| param( | |
| $LabelArray, | |
| $IssueUrl | |
| ) | |
| # Replace placeholder text in the URL retrieved from the GitHub API with the name of the label we're looking for | |
| $IssueLabelUrl = "$IssueUrl/labels" | |
| $LabelHashTable = @{} | |
| $LabelResults = $Null | |
| # Get list of labels on issue/PR | |
| Try | |
| { | |
| $LabelResults = Invoke-RestMethod -Uri $IssueLabelUrl -Headers $GitHubHeaders -ErrorAction Stop | |
| } | |
| Catch | |
| { | |
| Write-Error "ERROR: Failed to get list of labels on $IssueLabelUrl. Error: $($Error[0].Exception.Message)." | |
| } | |
| ForEach ($Label in $LabelArray) { | |
| If ($LabelResults -ne $Null) { | |
| If ($LabelResults.name.Contains($Label)) { | |
| $LabelHashTable.Add($Label, $True) | |
| } Else { | |
| $LabelHashTable.Add($Label, $False) | |
| } | |
| } Else { | |
| $LabelHashTable.Add($Label, $False) | |
| } | |
| } | |
| # Return array of labels on Issue/PR | |
| Return $LabelHashTable | |
| } | |
| ##################### | |
| ##################### | |
| # Set-PrLabel | |
| Function Set-PrLabel { | |
| param( | |
| $IssueUrl, | |
| $LabelName | |
| ) | |
| # Check to see if the label exists on the *PR*. | |
| $LabelResultsArray = Test-PrLabel -LabelArray $LabelName -IssueUrl $IssueUrl | |
| # Only add the label if it doesn't already exist on the *PR* | |
| If (!$LabelResultsArray.$LabelName) | |
| { | |
| # Construct label URL based on issue or pull request URL | |
| $IssueLabelUrl = "$IssueUrl/labels" | |
| # Construct JSON statement that will be sent to GitHub as the body of the web request. Includes only the label name. GitHub expects an array even thought it's a single value | |
| # Convert array to JSON | |
| $Body = @() | |
| $Body += $LabelName | |
| $Body = ConvertTo-Json -InputObject $Body | |
| # Try to submit the request to GitHub API to apply they label to the issue or pull request | |
| Try | |
| { | |
| Write-Host "Setting label $LabelName on URL $IssueLabelUrl." | |
| $Result = Invoke-RestMethod -Uri $IssueLabelUrl -Body $Body -Headers $GitHubHeaders -Method POST | |
| } | |
| Catch | |
| { | |
| Write-Error "ERROR: Failed to set label $LabelName on URL $IssueLabelUrl. Error: $($Error[0].Exception.Message)." | |
| } | |
| } | |
| Else | |
| { | |
| Write-Host "Label $LabelName already exists on PR" | |
| } | |
| } | |
| ##################### | |
| ##################### | |
| Function Remove-Label | |
| { | |
| param( | |
| $IssueUrl, | |
| $LabelName | |
| ) | |
| Write-Host "Remove $LabelName" | |
| # Check to see if the approved label exists on the *PR* and remove it | |
| $LabelResultsArray = Test-PrLabel -LabelArray $LabelName -IssueUrl $IssueUrl | |
| if ($LabelResultsArray.$LabelName) | |
| { | |
| Write-Host "Removing "$LabelName" label from PR." | |
| $LabelUrlName = $LabelName.Replace(" ", "%20") | |
| $LabelUrl = "$IssueUrl/labels/$LabelUrlName" | |
| Write-Host "$LabelUrl" | |
| $Result = Invoke-WebRequest -UseBasicParsing -Uri $LabelUrl -Headers $GitHubHeaders -Method Delete -ErrorAction Stop | |
| Write-Host "Successfully removed $LabelName label." | |
| } | |
| } | |
| ##################### | |
| ##################### | |
| # Test-BlockedFilesAndFolders | |
| Function Test-BlockedFilesAndFolders | |
| { | |
| [CmdletBinding()] | |
| Param( | |
| $PrFileList, | |
| $BlockedFilesAndFoldersList | |
| ) | |
| $FoundFilesAndFolders = @() | |
| Write-Host "Files in PR:" | |
| Write-Host "-------------------" | |
| ForEach ($PRFile in $PrFileList) | |
| { | |
| $File = $PRFile.filename | |
| Write-Host "$File" | |
| } | |
| ForEach ($BlockedFile in $BlockedFilesAndFoldersList) | |
| { | |
| Write-Host "Checking for file: $BlockedFile" | |
| $MatchedFile = $PrFileList | Where-Object { $_.filename -like "*$BlockedFile*" } | |
| if ($MatchedFile) | |
| { | |
| $File = $MatchedFile.filename | |
| Write-Host "Found blocked file = $File" | |
| $FoundFilesAndFolders += $File | |
| } | |
| } | |
| Return $FoundFilesAndFolders | |
| } | |
| ##################### | |
| ##################### | |
| # Set-PrComment | |
| Function Set-PrComment | |
| { | |
| [cmdletbinding()] | |
| Param( | |
| [Parameter(Mandatory=$True)] | |
| $Message | |
| ) | |
| Write-Host "Adding comment in pr..." | |
| $BodyHash = @{} | |
| $BodyHash.body = $Message | |
| $BodyJson = $BodyHash | ConvertTo-Json | |
| Try | |
| { | |
| $Result = Invoke-WebRequest -UseBasicParsing -Uri $CommentsUrl -Body $BodyJson -Headers $GitHubHeaders -Method POST -ErrorAction Stop | |
| $PostCommentSuccess = $True | |
| } | |
| Catch | |
| { | |
| $PostCommentSuccess = $False | |
| Write-Host "ERROR: Failed to submit message to PR conversation. Error: $($error[0].Exception.Message)." | |
| } | |
| Return $PostCommentSuccess | |
| } | |
| ##################### | |
| ##################### | |
| # Workflow # | |
| ##################### | |
| ##################### | |
| Try | |
| { | |
| # Get PR data so we can get the base branch of the PR. Doing this here so we don't need to do unnecessary calls if other criteria fail. | |
| $PrData = Invoke-RestMethod -Method GET -Headers $GitHubHeaders -Uri $PrUrl | |
| $TargetBranch = $PrData.base.ref | |
| $StatusUrl = $PrData.statuses_url | |
| $PrHtmlUrl = $PrData.html_url | |
| Write-Host "PR status url: $StatusUrl" | |
| # Only run checks if target is default branch. Otherwise let it pass. | |
| # Check to see if this is a branch that is being monitored: | |
| Write-Host "Target branch: $TargetBranch" | |
| $TargetingMonitoredBranch = ($TargetBranch -eq $DefaultBranch) | |
| Write-Host "Branch is targeted for monitoring: $TargetingMonitoredBranch" | |
| # Check to see if this is an actionable comment | |
| Write-Host "GitHub Request Event: $GitRequestEvent" | |
| Write-Host "GitHub Action: $GitHubAction" | |
| $SignOffFound = $false | |
| $ApprovedFound = $false | |
| $ActionableComment = $false | |
| $PROpenEvent = $false | |
| $EventIsCommentCreated = (($GitRequestEvent -eq "issue_comment") -and (($GitHubAction -eq "created"))) | |
| If ($EventIsCommentCreated) | |
| { | |
| Write-Host "Comment added on PR." | |
| # Get the contents of the comment that was added to the PR | |
| $CommentBody = $GitHubData.event.comment.body | |
| Write-Host "Comment:" | |
| Write-Host "--------------------------" | |
| Write-Host "$CommentBody" | |
| Write-Host "--------------------------" | |
| # Check to see if comment includes #sign-off, or #approve-files | |
| $SignOffFound = $CommentBody -match $SignOffRegex | |
| $ApprovedFound = $CommentBody -match $ApprovedRegex | |
| $ActionableComment = ($SignOffFound -or $ApprovedFound) | |
| } | |
| ElseIf (($GitRequestEvent -eq "pull_request_target") -and (($GitHubAction -eq "opened") -or ($GitHubAction -eq "reopened") -or ($GitHubAction -eq "synchronize"))) | |
| { | |
| Write-Host "Non-comment GitHub Event" | |
| Write-Host "Pull request action $GitHubAction. Setting sign off check to pending." | |
| $PROpenEvent = $true | |
| $Status.state = "pending" | |
| $Status.description = "Evaluating whether signoff is allowed on files." | |
| } | |
| else | |
| { | |
| Write-Host "GitHub event not a PR comment" | |
| } | |
| if ($PROpenEvent) | |
| { | |
| # This runs when the PR is first opened | |
| # Check to see if any of the files are under a content freeze and blocked from edits | |
| # Get the list of files on the PR. | |
| Write-Host "Checking for blocked files in PR" | |
| $PrFiles = Invoke-RestMethod -Method GET -Headers $GitHubHeaders -Uri "$PrUrl/files" | |
| # Check to see if any files are blocked. | |
| # Return all of the blocked files in the PR | |
| $BlockedFilesAndFoldersList = Test-BlockedFilesAndFolders -PrFileList $PrFiles -BlockedFilesAndFoldersList $BlockedFilesAndFolders | |
| $BlockedFilesFound = $BlockedFilesAndFoldersList.Count -gt 0 | |
| if ($BlockedFilesFound) | |
| { | |
| Write-Host "Blocked files found!" | |
| $Status.state = "pending" | |
| $Status.description = $SignoffBlockedMessage | |
| $PRContainsBlockedFilesMessage += "`n" | |
| ForEach ($BlockedFile in $BlockedFilesAndFoldersList) | |
| { | |
| $PRContainsBlockedFilesMessage += "- $BlockedFile`n" | |
| } | |
| Set-PrLabel -IssueUrl $IssueUrl -LabelName $FilesBlockedForConfLabel | |
| Set-PrComment $PRContainsBlockedFilesMessage | |
| } | |
| else | |
| { | |
| $Status.state = "success" | |
| $Status.description = "No blocked files in PR." | |
| } | |
| $ActionableComment = $True | |
| } | |
| else | |
| { | |
| # This was a comment on the PR so look for action tags | |
| Write-Host "Regex result found $SignOffString : $SignOffFound." | |
| Write-Host "Regex result found $ApprovedString : $ApprovedFound." | |
| # Check to see if any of the files are under a content freeze and blocked from edits | |
| # Get the list of files on the PR. | |
| Write-Host "Checking for blocked files in PR" | |
| $PrFiles = Invoke-RestMethod -Method GET -Headers $GitHubHeaders -Uri "$PrUrl/files" | |
| # Check to see if any files are blocked. | |
| # Return all of the blocked files in the PR | |
| $BlockedFilesAndFoldersList = Test-BlockedFilesAndFolders -PrFileList $PrFiles -BlockedFilesAndFoldersList $BlockedFilesAndFolders | |
| $BlockedFilesFound = $BlockedFilesAndFoldersList.Count -gt 0 | |
| if ($BlockedFilesFound) | |
| { | |
| Write-Host "Blocked files found!" | |
| } | |
| # Check to see what labels are already on the PR | |
| Initialize-Labels | |
| $LabelApprovedArray = Test-PrLabel -LabelArray $ContentApprovedLabel -IssueUrl $IssueUrl | |
| $ApprovedLabelSet = $LabelApprovedArray.$ContentApprovedLabel | |
| # Workflow processing: | |
| If (-not $TargetingMonitoredBranch) | |
| { | |
| Write-Host "Approving as $TargetBranch branch is not being monitored." | |
| $ActionableComment = $True | |
| $Status.state = "success" | |
| $Status.description = "Target branch not $DefaultBranch, so approving by default." | |
| } | |
| ElseIf (-not $BlockedFilesFound) | |
| { | |
| Write-Host "Approving as no blocked files or folders found." | |
| $ActionableComment = $True | |
| $Status.state = "success" | |
| $Status.description = "No blocked files or folders found. Allowing sign off." | |
| } | |
| ElseIf (-not $ActionableComment) | |
| { | |
| Write-Host "Comment not sign off or approval." | |
| # Check to see if the content team has approved this yet | |
| # If so, always return success. If not, always keep at pending until approved. | |
| if ($ApprovedLabelSet) | |
| { | |
| $ActionableComment = $True | |
| Write-Host "Content team already approved. Returning success." | |
| $Status.state = "success" | |
| $Status.description = $SignoffApprovalMessage | |
| } | |
| else | |
| { | |
| # The comment was not one to take action on | |
| } | |
| } | |
| Else | |
| { | |
| # The branch is targeted, the files are blocked, and the comment contains an action | |
| Initialize-Labels | |
| Write-Host "String $SignOffString or $ApprovedString or found on PR/Issue #$PrIssueNumber." | |
| # Get permission level of user who created the comment. Need to use .role_name instead of .permission because .permission provides only legacy values. | |
| # .role_name provides legacy plus triage, maintain, and custom roles like write-elevated. | |
| $UserPermission = $(Invoke-RestMethod -Method GET -Headers $GitHubHeaders -Uri $UserPermissionUrl).role_name | |
| Write-Host "User $CommentUser permission level: $UserPermission." | |
| # If user has write or above, allow check to pass. If not, add content team review label. | |
| If (($UserPermission -like "write*") -or ($UserPermission -eq "maintain") -or ($UserPermission -eq "admin") -or ($UserPermission -eq "triage")) | |
| { | |
| Write-Host "User $CommentUser has the permission level: $UserPermission. Pass check." | |
| If ($SignOffFound -or $ApprovedFound) | |
| { | |
| # Set the properties on the $Status object to allow the check to pass. $Status will be sent to GitHub at the end of the workflow. | |
| $Status.state = "success" | |
| $Status.description = $SignoffApprovalMessage | |
| Write-Host "Adding $ContentApprovedLabel label to the PR" | |
| Set-PrLabel -IssueUrl $IssueUrl -LabelName $ContentApprovedLabel | |
| } | |
| } | |
| Else | |
| { | |
| # If the content team has already approved, report success. | |
| # Technically, this means that once approved they could sneak other changes in, but maybe that is ok as we would see. | |
| If ($ApprovedLabelSet) | |
| { | |
| Write-Host "Content team already approved. Returning success." | |
| $Status.state = "success" | |
| $Status.description = $SignoffApprovalMessage | |
| } | |
| Else | |
| { | |
| # Check failed. Add label. | |
| Write-Host "One or more files are under content freeze and user $CommentUser has the permission level: $UserPermission. Fail check." | |
| # Even though the check failed, leave the status as pending. | |
| # It is always pending until the content team has approved. | |
| $Status.state = "pending" | |
| $Status.description = $SignoffBlockedMessage | |
| $PRContainsBlockedFilesMessage += "`n" | |
| ForEach ($BlockedFile in $BlockedFilesAndFoldersList) | |
| { | |
| $PRContainsBlockedFilesMessage += "- $BlockedFile`n" | |
| } | |
| Set-PrLabel -IssueUrl $IssueUrl -LabelName $FilesBlockedForConfLabel | |
| Set-PrComment $PRContainsBlockedFilesMessage | |
| $CheckFailed = $True | |
| } | |
| } | |
| } | |
| if ($Status.state -ne "success") | |
| { | |
| # If the state is anything other than success, attempt to remove the ready-to-merge label | |
| # and add the do-not-merge label | |
| Write-Host "Removing ready-to-merge label" | |
| Remove-Label -LabelName "ready-to-merge" -IssueUrl $IssueUrl | |
| Write-Host "Adding the do-not-merge label" | |
| Set-PrLabel -LabelName "do-not-merge" -IssueUrl $IssueUrl | |
| } | |
| } | |
| } | |
| Catch | |
| { | |
| # Capture and display detailed exception information | |
| Write-Host "An error occurred: $($_.Exception.Message)" | |
| Write-Host "Exception type: $($_.Exception.GetType().FullName)" | |
| Write-Host "Line number: $($_.InvocationInfo.ScriptLineNumber)" | |
| Write-Host "Position: $($_.InvocationInfo.OffsetInLine)" | |
| Write-Host "Script name: $($_.InvocationInfo.ScriptName)" | |
| Write-Host "Error line: $($_.InvocationInfo.Line)" | |
| # Read and display the line of code that caused the error | |
| $scriptPath = $($_.InvocationInfo.ScriptName) | |
| if ($scriptPath) { | |
| $lines = Get-Content -Path $scriptPath | |
| $errorLine = $_.InvocationInfo.ScriptLineNumber | |
| Write-Host "Code at error line $errorLine : $($lines[$errorLine - 1])" | |
| } | |
| # For catastrophic failure, make sure to not block PRs | |
| $Status.state = "success" | |
| $Status.description = "Unexpected error in workflow. Allowing sign off." | |
| $CatastrophicError = $True | |
| } | |
| # Get ready to send $Status to GitHub. First need to convert the $Status object to JSON. Then set a couple variables to prepare for an attempt loop | |
| # to deal with transient communication failures that may prevent the workflow from setting the status. | |
| $StatusJson = $Status | ConvertTo-Json | |
| $SuccessfulPost = $False | |
| $RetryCount = 0 | |
| Write-Host "Reporting Status:" | |
| Write-Host "$StatusJson" | |
| # Loop to try set the status on the PR. Keep trying until either the status is successfully posted or we run out of attempts. | |
| # In the unlikely event of a water landing or failure of all six attempts, the status will not set and the user will need to | |
| # submit a new sign off request. | |
| if ($ActionableComment) | |
| { | |
| # Only post a status back if an actionable comment was provided. | |
| # Otherwise leave as expected with no result. | |
| # This keeps the previous status unless explicitly changed. | |
| Do | |
| { | |
| Try | |
| { | |
| # Send POST request to GitHub | |
| Invoke-RestMethod -Headers $GitHubHeaders -Uri $StatusUrl -Method POST -Body $StatusJson -ErrorAction Stop | |
| $SuccessfulPost = $True | |
| } | |
| Catch | |
| { | |
| # If the request fails for any reason, retry it after a delay, up to six times. | |
| $RetryCount++ | |
| Start-Sleep 1 | |
| } | |
| } Until (($SuccessfulPost) -or ($RetryCount -gt 5)) | |
| } | |
| # Print out current date and time | |
| $currentDateTime = Get-Date | |
| $currentDateTimeString = "{0:yyyy-MM-dd HH:mm:ss}" -f $currentDateTime | |
| Write-Output "Run end: $currentDateTimeString" | |
| If ($CheckFailed) | |
| { | |
| # Populates the job summary if a user doesn't have permissions to sign off. | |
| echo "# Pull request validation error" >> $env:GITHUB_STEP_SUMMARY | |
| echo "" >> $env:GITHUB_STEP_SUMMARY | |
| echo "The user $CommentUser with permission level $UserPermission tried to sign off PR: $PrHtmlUrl but doesn't have the necessary permissions to do so. Please contact the content team to request sign off." >> $env:GITHUB_STEP_SUMMARY | |
| } | |
| ElseIf ($CatastrophicError) | |
| { | |
| # Makes sure the workflow looks failed so we can investigate the bug | |
| echo "# Pull request validation error" >> $env:GITHUB_STEP_SUMMARY | |
| echo "" >> $env:GITHUB_STEP_SUMMARY | |
| echo "The user $CommentUser with permission level $UserPermission tried to sign off PR: $PrHtmlUrl. There was an unexpected error in the workflow, so sign-off was allowed to prevent blocking PRs. Please contact the developer of the workflow to investigate." >> $env:GITHUB_STEP_SUMMARY | |
| # Force the workflow to fail so the validation failure can be tracked in Actions. In this workflow, this has no effect other than logging the failure. | |
| Throw "User $CommentUser signed off but an unexpected error occurred. Please contact contact team to investigate the workflow. Sign off allowed to prevent blocking PRs." | |
| } |