Skip to content

Bump actions/upload-artifact from 4.4.3 to 4.5.0 #220

Bump actions/upload-artifact from 4.4.3 to 4.5.0

Bump actions/upload-artifact from 4.4.3 to 4.5.0 #220

name: approve-and-merge
on:
pull_request:
branches: [ main ]
env:
REVIEWER_LOGIN: ${{ vars.REVIEWER_USER_NAME }}
permissions:
contents: read
jobs:
review-pull-request:
runs-on: ubuntu-latest
if: ${{ github.event.pull_request.user.login == vars.UPDATER_COMMIT_USER_NAME }}
steps:
- name: Generate GitHub application token
id: generate-application-token
uses: peter-murray/workflow-application-token-action@8e4e6fbf6fcc8a272781d97597969d21b3812974 # v4.0.0
with:
application_id: ${{ secrets.REVIEWER_APPLICATION_ID }}
application_private_key: ${{ secrets.REVIEWER_APPLICATION_PRIVATE_KEY }}
permissions: "contents:write, pull_requests:write"
- name: Install powershell-yaml
shell: pwsh
run: Install-Module -Name powershell-yaml -Force -MaximumVersion "0.4.7"
- name: Check which dependencies were updated
id: check-dependencies
env:
# This list of trusted package prefixes needs to stay in sync with include-nuget-packages in the update-dotnet-sdk workflow.
INCLUDE_NUGET_PACKAGES: ""
GH_TOKEN: ${{ steps.generate-application-token.outputs.token }}
shell: pwsh
run: |
# Replicate the logic in the dependabot/fetch-metadata action.
# See https://github.com/dependabot/fetch-metadata/blob/aea2135c95039f05c64436f1d14638c300e10b2b/src/dependabot/update_metadata.ts#L29-L68.
# Query the GitHub API to get the commits in the pull request.
$commits = gh api `
/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/commits `
--jq '.[] | { author: .author.login, message: .commit.message }' | ConvertFrom-Json
# We should only approve pull requests that only contain commits from
# the GitHub user we expected and only commits that contain the metadata
# we need to determine what dependencies were updated by the other workflow.
$expectedUser = "${{ vars.UPDATER_COMMIT_USER_NAME }}"
$onlyDependencyUpdates = $True
$onlyChangesFromUser = $True
$dependencies = @()
foreach ($commit in $commits) {
if ($commit.Author -ne $expectedUser) {
# Some other commit is in the pull request
$onlyChangesFromUser = $False
}
# Extract the YAML metadata block from the commit message.
$match = [Regex]::Match($commit.Message, '(?m)^-{3}\s(?<dependencies>[\S|\s]*?)\s^\.{3}$')
if ($match.Success -eq $True) {
# Extract the names and update type from each dependency.
$metadata = ($match.Value | ConvertFrom-Yaml -Ordered)
$updates = $metadata["updated-dependencies"]
if ($updates) {
foreach ($update in $updates) {
$dependencies += @{
Name = $update['dependency-name'];
Type = $update['update-type'];
}
}
}
}
else {
# The pull request contains a commit that we didn't expect as the metadata is missing.
$onlyDependencyUpdates = $False
}
}
# Did we find at least one dependency?
$isPatch = $dependencies.Length -gt 0
$onlyTrusted = $dependencies.Length -gt 0
$trustedPackages = $env:INCLUDE_NUGET_PACKAGES.Split(',')
foreach ($dependency in $dependencies) {
$isPatch = $isPatch -And $dependency.Type -eq "version-update:semver-patch"
$onlyTrusted = $onlyTrusted -And
(
($dependency.Name -eq "Microsoft.NET.Sdk") -Or
(($trustedPackages | Where-Object { $dependency.Name.StartsWith($_) }).Count -gt 0)
)
}
# We only trust the pull request to approve and auto-merge it
# if it only contains commits which change the .NET SDK and
# Microsoft-published NuGet packages that were made by the GitHub
# login we expect to make those changes in the other workflow.
$isTrusted = (($onlyTrusted -And $isPatch) -And $onlyChangesFromUser) -And $onlyDependencyUpdates
"is-trusted-update=$isTrusted" >> $env:GITHUB_OUTPUT
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# As long as it's not already approved, approve the pull request and enable auto-merge.
# Our CI tests coupled with required statuses should ensure that the changes compile
# and that the application is still functional after the update; any bug that might be
# introduced by the update should be caught by the tests. If that happens, the build
# workflow will fail and the preconditions for the auto-merge to happen won't be met.
- name: Approve pull request and enable auto-merge
if: ${{ steps.check-dependencies.outputs.is-trusted-update == 'true' }}
env:
GH_TOKEN: ${{ steps.generate-application-token.outputs.token }}
PR_URL: ${{ github.event.pull_request.html_url }}
shell: pwsh
run: |
$approvals = gh api /repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews | ConvertFrom-Json
$approvals = $approvals | Where-Object { $_.user.login -eq $env:REVIEWER_LOGIN }
$approvals = $approvals | Where-Object { $_.state -eq "APPROVED" }
if ($approvals.Length -eq 0) {
gh pr checkout "$env:PR_URL"
gh pr review --approve "$env:PR_URL"
gh pr merge --auto --squash "$env:PR_URL"
}
else {
Write-Host "PR already approved.";
}
# If something was present in the pull request that isn't expected, then disable
# auto-merge so that a human is required to look at the pull request and make a
# decision to merge it or not. This is to prevent the pull request from being merged
# automatically if there's an unexpected change introduced. Any existing review
# approvals that were made by the bot are also dismissed so human approval is required.
- name: Disable auto-merge and dismiss approvals
if: ${{ steps.check-dependencies.outputs.is-trusted-update != 'true' }}
env:
GH_TOKEN: ${{ steps.generate-application-token.outputs.token }}
PR_URL: ${{ github.event.pull_request.html_url }}
shell: pwsh
run: |
$approvals = gh api /repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews | ConvertFrom-Json
$approvals = $approvals | Where-Object { $_.user.login -eq $env:REVIEWER_LOGIN }
$approvals = $approvals | Where-Object { $_.state -eq "APPROVED" }
if ($approvals.Length -gt 0) {
gh pr checkout "$env:PR_URL"
gh pr merge --disable-auto "$env:PR_URL"
foreach ($approval in $approvals) {
gh api `
--method PUT `
/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews/$($approval.id)/dismissals `
-f message='Cannot approve as other changes have been introduced.' `
-f event='DISMISS'
}
}
else {
Write-Host "PR not already approved.";
}