diff --git a/.github/workflows/renovate-auto-approve.yml b/.github/workflows/renovate-auto-approve.yml new file mode 100644 index 0000000..9b50826 --- /dev/null +++ b/.github/workflows/renovate-auto-approve.yml @@ -0,0 +1,85 @@ +name: renovate-auto-approve + +# Reusable workflow. A consuming repo triggers it on pull_request and calls it: +# +# jobs: +# approve: +# uses: opendefensecloud/dev-kit/.github/workflows/renovate-auto-approve.yml@ +# permissions: +# pull-requests: write +# +# It approves a Renovate PR that carries the automerge label and not the block +# label (security). If a PR later gains the block label, it revokes its own +# earlier approval so a human is required again. The merge itself always stays +# gated on the repo's required status checks. +# +# Which update types are eligible (the automerge label) is decided by the +# renovate-config presets, not here: github>opendefensecloud/renovate-config. + +on: + workflow_call: + inputs: + automerge-label: + description: Label that marks a Renovate PR as safe to auto-approve. + type: string + default: automerge + block-label: + description: Label that blocks auto-approval, and revokes an earlier one. + type: string + default: security + renovate-actor: + description: Login of the Renovate app that authors the pull requests. + type: string + default: renovate[bot] + +permissions: + pull-requests: write + +concurrency: + group: renovate-auto-approve-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + auto-approve: + runs-on: ubuntu-latest + if: >- + github.event_name == 'pull_request' && + github.event.pull_request.user.login == inputs.renovate-actor && + (contains(github.event.pull_request.labels.*.name, inputs.automerge-label) || + contains(github.event.pull_request.labels.*.name, inputs.block-label)) + steps: + - name: Approve, or revoke a prior approval if the block label appears + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + PR_NUMBER: ${{ github.event.pull_request.number }} + LABEL: ${{ inputs.automerge-label }} + BLOCK_LABEL: ${{ inputs.block-label }} + HAS_BLOCK: ${{ contains(github.event.pull_request.labels.*.name, inputs.block-label) }} + run: | + set -euo pipefail + # Latest review state left by this workflow's identity (github-actions[bot]). + latest_state=$(gh api "repos/$GH_REPO/pulls/$PR_NUMBER/reviews" \ + --jq 'map(select((.user.login // "" | ascii_downcase) | startswith("github-actions"))) | last | .state // empty') + if [ "$HAS_BLOCK" = "true" ]; then + if [ "$latest_state" = "APPROVED" ]; then + echo "PR now carries the $BLOCK_LABEL label; revoking the earlier automated approval." + gh pr review "$PR_NUMBER" --request-changes \ + --body "Revoked: this PR is now labeled \`$BLOCK_LABEL\` and needs a human review." + else + echo "PR carries the $BLOCK_LABEL label; no automated approval to revoke." + fi + exit 0 + fi + if [ "$latest_state" = "APPROVED" ]; then + echo "Already approved by github-actions; nothing to do." + exit 0 + fi + # Re-read labels right before approving: the block label may have been + # added after this run started, concurrently with this approval. + if gh pr view "$PR_NUMBER" --json labels --jq '.labels[].name' | grep -qxF "$BLOCK_LABEL"; then + echo "PR now carries the $BLOCK_LABEL label; not approving." + exit 0 + fi + gh pr review "$PR_NUMBER" --approve \ + --body "Auto-approved: Renovate \`$LABEL\` update. Merge remains gated on required status checks." diff --git a/docs/NEW_REPO.md b/docs/NEW_REPO.md index 951169c..c19a922 100644 --- a/docs/NEW_REPO.md +++ b/docs/NEW_REPO.md @@ -76,6 +76,17 @@ preCommitHooks = { }; ``` +### Renovate auto-approve (optional) + +To let Renovate auto-merge digest, patch, and minor PRs without a manual approval, copy `example/.github/workflows/renovate-auto-approve.yml` into your project and pin the `uses:` ref to a dev-kit release tag or commit SHA. It calls dev-kit's reusable `renovate-auto-approve.yml`, which approves Renovate PRs labeled `automerge` and skips (and revokes) anything labeled `security`. + +Two more things are needed: + +- **Settings > Actions > General > Workflow permissions:** enable ["Allow GitHub Actions to create and approve pull requests"](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#preventing-github-actions-from-creating-or-approving-pull-requests), otherwise the approval is rejected. +- The `protect-main` ruleset from `make repo-settings` already requires 1 approval and status checks. Put your CI/e2e checks in `REPO_STATUS_CHECKS` so the merge stays gated on them. + +Which update types are eligible is defined by the [renovate-config](https://github.com/opendefensecloud/renovate-config) presets. Major and security updates never get the `automerge` label, so they still need a human. + ## 6. Add the pull request template Copy `.github/pull_request_template.md` from this repository into your project. It provides a @@ -103,6 +114,7 @@ If Renovate is not enabled, check that the Renovate GitHub App is installed for - [ ] `make help` lists all available targets - [ ] `make repo-settings` ran successfully - [ ] GitHub workflows are in place and passing +- [ ] Renovate auto-approve workflow added and "Allow GitHub Actions to approve pull requests" enabled (if using automerge) - [ ] Renovate onboarding PR has been merged - [ ] Organization secrets are whitelisted for the repo - [ ] Private runners are whitelisted (if applicable) diff --git a/example/.github/workflows/renovate-auto-approve.yml b/example/.github/workflows/renovate-auto-approve.yml new file mode 100644 index 0000000..9c762a4 --- /dev/null +++ b/example/.github/workflows/renovate-auto-approve.yml @@ -0,0 +1,15 @@ +# Auto-approve Renovate digest/patch/minor PRs so they can automerge. +# Calls the reusable workflow in opendefensecloud/dev-kit. The automerge policy +# (which update types are eligible) comes from the renovate-config presets. +name: renovate-auto-approve +on: + pull_request: + types: [opened, reopened, synchronize, labeled, unlabeled] +permissions: + pull-requests: write +jobs: + approve: + # Pin @ to a dev-kit release tag or commit SHA before using this. + uses: opendefensecloud/dev-kit/.github/workflows/renovate-auto-approve.yml@ + permissions: + pull-requests: write