Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR and issue automation #1370

Merged
merged 5 commits into from
Jun 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ updates:
timezone: "America/New_York"
ignore:
# Ignore the libraries which are pinned
- dependency-name: "System.ComponentModel.Annotations"
- dependency-name: "System.Threading.Tasks.Extensions"
- dependency-name: "System.ValueTuple"
- dependency-name: "Microsoft.Extensions.Options"
- dependency-name: "Microsoft.Extensions.Logging.Abstractions"
- dependency-name: "Microsoft.Bcl.AsyncInterfaces"
- dependency-name: "Microsoft.Extensions.Logging"
- dependency-name: "Microsoft.Extensions.Logging.Abstractions"
- dependency-name: "Microsoft.Extensions.Options"
- dependency-name: "System.ComponentModel.Annotations"
- dependency-name: "System.Diagnostics.DiagnosticSource"
- dependency-name: "System.Threading.RateLimiting"
- dependency-name: "Microsoft.Bcl.AsyncInterfaces"
- dependency-name: "System.Threading.Tasks.Extensions"
- dependency-name: "System.ValueTuple"
56 changes: 56 additions & 0 deletions .github/workflows/dependabot-approve.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: dependabot-approve

on: pull_request_target

permissions:
contents: read

jobs:
review:
runs-on: ubuntu-latest
if: ${{ github.event.repository.fork == false && github.event.pull_request.user.login == 'dependabot[bot]' }}

steps:

- name: Get dependabot metadata
uses: dependabot/fetch-metadata@cd6e996708b8cfe0b639401134a3b9a3177be7b2 # v1.5.1
id: dependabot-metadata

- name: Generate GitHub application token
id: generate-application-token
uses: peter-murray/workflow-application-token-action@8e1ba3bf1619726336414f1014e37f17fbadf1db # v2.1.0
with:
application_id: ${{ secrets.POLLY_REVIEWER_BOT_APP_ID }}
application_private_key: ${{ secrets.POLLY_REVIEWER_BOT_KEY }}
permissions: "contents:write, pull_requests:write, workflows:write"

- name: Checkout code
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3

- name: Approve pull request and enable auto-merge
shell: bash
if: |
contains(steps.dependabot-metadata.outputs.dependency-names, 'actions/cache') ||
contains(steps.dependabot-metadata.outputs.dependency-names, 'actions/checkout') ||
contains(steps.dependabot-metadata.outputs.dependency-names, 'actions/dependency-review-action') ||
contains(steps.dependabot-metadata.outputs.dependency-names, 'actions/download-artifact') ||
contains(steps.dependabot-metadata.outputs.dependency-names, 'actions/setup-dotnet') ||
contains(steps.dependabot-metadata.outputs.dependency-names, 'actions/stale') ||
contains(steps.dependabot-metadata.outputs.dependency-names, 'actions/upload-artifact') ||
contains(steps.dependabot-metadata.outputs.dependency-names, 'codecov/codecov-action') ||
contains(steps.dependabot-metadata.outputs.dependency-names, 'dependabot/fetch-metadata') ||
contains(steps.dependabot-metadata.outputs.dependency-names, 'github/codeql-action') ||
contains(steps.dependabot-metadata.outputs.dependency-names, 'Microsoft.NET.Test.Sdk') ||
contains(steps.dependabot-metadata.outputs.dependency-names, 'Polly') ||
contains(steps.dependabot-metadata.outputs.dependency-names, 'Polly.Core') ||
contains(steps.dependabot-metadata.outputs.dependency-names, 'Polly.Extensions') ||
contains(steps.dependabot-metadata.outputs.dependency-names, 'xunit') ||
contains(steps.dependabot-metadata.outputs.dependency-names, 'xunit.runner.visualstudio')
env:
GH_TOKEN: ${{ steps.generate-application-token.outputs.token }}
PR_URL: ${{ github.event.pull_request.html_url }}
run: |
gh pr checkout "$PR_URL"
if [ "$(gh pr status --json reviewDecision -q .currentBranch.reviewDecision)" != "APPROVED" ];
then gh pr review --approve "$PR_URL" && gh pr merge --auto --squash "$PR_URL"
fi
21 changes: 21 additions & 0 deletions .github/workflows/dependency-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: dependency-review

on:
pull_request:
branches: [ main ]

permissions:
contents: read

jobs:
dependency-review:
runs-on: ubuntu-latest
if: ${{ github.event.repository.fork == false }}

steps:

- name: Checkout code
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3

- name: Review dependencies
uses: actions/dependency-review-action@1360a344ccb0ab6e9475edef90ad2f46bf8003b1 # v3.0.6
28 changes: 28 additions & 0 deletions .github/workflows/stale.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: stale

on:
schedule:
- cron: '30 1 * * *'
workflow_dispatch:

permissions:
issues: read
pull-requests: read

jobs:
stale:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@1160a2240286f5da8ec72b1c0816ce2481aabf84 # v8.0.0
with:
days-before-close: 14
days-before-stale: 60
stale-issue-label: 'stale'
stale-issue-message: "This issue is stale because it has been open for 60 days with no activity. It will be automatically closed in 14 days if no further updates are made."
close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale."
stale-pr-label: 'stale'
stale-pr-message: "This pull request is stale because it has been open for 60 days with no activity. It will be automatically closed in 14 days if no further changes are made."
close-pr-message: "This pull request was closed because it has been inactive for 14 days since being marked as stale."
34 changes: 19 additions & 15 deletions .github/workflows/update-dotnet-sdk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,29 @@ on:

permissions:
contents: read
pull-requests: read

jobs:
update-dotnet-sdk:
name: Update .NET SDK
runs-on: ubuntu-latest
if: ${{ github.event.repository.fork == false }}
uses: martincostello/update-dotnet-sdk/.github/workflows/update-dotnet-sdk.yml@ff9a6f247704ef1b77eb3c478070d8fa69c2360e # v2.2.3
with:
labels: "dependencies,.NET"
update-nuget-packages: false
user-email: '138034000+polly-updater-bot[bot]@users.noreply.github.com'
user-name: 'polly-updater-bot[bot]'
secrets:
application-id: ${{ secrets.POLLY_UPDATER_BOT_APP_ID }}
application-private-key: ${{ secrets.POLLY_UPDATER_BOT_KEY }}

add-security-label:
needs: update-dotnet-sdk
permissions:
contents: write
pull-requests: write

runs-on: ubuntu-latest
if : |
needs.update-dotnet-sdk.outputs.sdk-updated =='true' &&
needs.update-dotnet-sdk.outputs.security == 'true'
steps:

- name: Checkout code
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3

- name: Update .NET SDK
uses: martincostello/update-dotnet-sdk@ff9a6f247704ef1b77eb3c478070d8fa69c2360e # v2.2.3
with:
labels: "dependencies,.NET"
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Add security label
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh pr edit "${{ needs.update-dotnet-sdk.outputs.pull-request-html-url }}" --add-label security
144 changes: 144 additions & 0 deletions .github/workflows/updater-approve.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
name: updater-approve

on:
pull_request:
branches: [ main ]

permissions:
contents: read

jobs:
review:
runs-on: ubuntu-latest
if: ${{ github.event.repository.fork == false && github.event.pull_request.user.login == 'polly-updater-bot[bot]' }}

env:
REVIEWER_LOGIN: "polly-reviewer-bot[bot]"
UPDATER_LOGIN: "polly-updater-bot[bot]"

steps:

- name: Generate GitHub application token
id: generate-application-token
uses: peter-murray/workflow-application-token-action@8e1ba3bf1619726336414f1014e37f17fbadf1db # v2.1.0
with:
application_id: ${{ secrets.POLLY_REVIEWER_BOT_APP_ID }}
application_private_key: ${{ secrets.POLLY_REVIEWER_BOT_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:
INCLUDE_NUGET_PACKAGES: "Microsoft.AspNetCore.,Microsoft.EntityFrameworkCore.,Microsoft.Extensions.,System.Text.Json"
GH_TOKEN: ${{ steps.generate-application-token.outputs.token }}
shell: pwsh
run: |
$commits = gh api `
/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/commits `
--jq '.[] | { author: .author.login, message: .commit.message }' | ConvertFrom-Json

$expectedUser = $env:UPDATER_LOGIN
$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@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3

- 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.";
}

- 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.";
}