Skip to content
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
22 changes: 14 additions & 8 deletions .github/workflows/dependabot-automerge.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ For repositories **with** required status checks:
```yaml
name: dependabot-automerge
on: pull_request
permissions:
contents: write
pull-requests: write
issues: write
permissions: {}
jobs:
automerge:
uses: bufbuild/base-workflows/.github/workflows/dependabot-automerge.yaml@main
secrets:
DEPENDENCY_AUTOMERGE_APP_ID: ${{ secrets.DEPENDENCY_AUTOMERGE_APP_ID }}
DEPENDENCY_AUTOMERGE_APP_PRIVATE_KEY: ${{ secrets.DEPENDENCY_AUTOMERGE_APP_PRIVATE_KEY }}
with:
github-auto-merge: true
```
Expand All @@ -35,13 +35,13 @@ on:
schedule:
- cron: "0 13 * * *" # 13:00 UTC (8am EST / 9am EDT)
workflow_dispatch:
permissions:
contents: write
pull-requests: write
issues: write
permissions: {}
jobs:
automerge:
uses: bufbuild/base-workflows/.github/workflows/dependabot-automerge.yaml@main
secrets:
DEPENDENCY_AUTOMERGE_APP_ID: ${{ secrets.DEPENDENCY_AUTOMERGE_APP_ID }}
DEPENDENCY_AUTOMERGE_APP_PRIVATE_KEY: ${{ secrets.DEPENDENCY_AUTOMERGE_APP_PRIVATE_KEY }}
with:
github-auto-merge: false
```
Expand Down Expand Up @@ -123,3 +123,9 @@ workflow's approval, that's why.
> merges eligible PRs immediately, without waiting for any checks. Only
> set it to `true` once the branch-protection setup ("required status
> checks" + "Allow auto-merge") is done.

## Secrets

The caller must pass the `DEPENDENCY_AUTOMERGE_APP_ID` and `DEPENDENCY_AUTOMERGE_APP_PRIVATE_KEY` org secrets through explicitly, as in the examples above. Every GitHub API operation (metadata lookup, labeling, approvals, merges) is performed with a GitHub App token minted from them; `GITHUB_TOKEN` is never used, so callers need no `permissions` grants. The app token is necessary because events created with the default `GITHUB_TOKEN` never trigger other workflows, so merging with it would silently skip CI on the default branch after the merge. Reusable workflows don't see org secrets unless the caller passes them through. Both secrets are declared `required`, so a caller that omits them fails immediately at workflow validation rather than at the token minting step.

The two jobs resolve secrets from different stores, so the app ID and key must be registered as both org **Actions secrets** and org **Dependabot secrets**, under the same names. The mark job runs on Dependabot-triggered `pull_request` events, which only see Dependabot secrets ([GitHub Actions secrets are not available](https://docs.github.com/en/code-security/reference/supply-chain-security/troubleshoot-dependabot/dependabot-on-actions) in those runs). The sweep job runs on `workflow_run`, `schedule`, and `workflow_dispatch` events, which see regular Actions secrets. Missing either store breaks one of the two merge paths.
45 changes: 37 additions & 8 deletions .github/workflows/dependabot-automerge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ on:
github-auto-merge:
type: boolean
required: true
permissions:
contents: write
pull-requests: write
issues: write
secrets:
DEPENDENCY_AUTOMERGE_APP_ID:
required: true
DEPENDENCY_AUTOMERGE_APP_PRIVATE_KEY:
required: true
permissions: {} # GITHUB_TOKEN is unused; everything runs on the app token.
jobs:
# Classifies each Dependabot PR with fetch-metadata and records the
# verdict as the label. Re-runs on every Dependabot push, so a PR that
Expand All @@ -32,16 +34,31 @@ jobs:
github.event.pull_request.user.login == 'dependabot[bot]' &&
github.actor == 'dependabot[bot]'
steps:
# Enabling auto-merge must use an app token, not GITHUB_TOKEN,
# so that CI runs post-merge.
# For simplicity, everything uses this token, instead of some steps
# using GITHUB_TOKEN
- name: Create App Token
id: app-token
uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2
with:
app-id: ${{ secrets.DEPENDENCY_AUTOMERGE_APP_ID }}
private-key: ${{ secrets.DEPENDENCY_AUTOMERGE_APP_PRIVATE_KEY }}
permission-contents: write # required to toggle auto-merge
permission-pull-requests: write # required to label and approve PRs
permission-issues: write # required to create repo label
- name: Fetch Dependabot Metadata
id: metadata
uses: dependabot/fetch-metadata@25dd0e34f4fe68f24cc83900b1fe3fe149efef98 # v3.1.0
with:
github-token: ${{ steps.app-token.outputs.token }}
- name: Label Eligible PR
id: label
if: >-
steps.metadata.outputs.update-type == 'version-update:semver-patch' ||
steps.metadata.outputs.update-type == 'version-update:semver-minor'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ steps.app-token.outputs.token }}
PR_URL: ${{ github.event.pull_request.html_url }}
REPO: ${{ github.repository }}
run: |
Expand All @@ -52,15 +69,15 @@ jobs:
steps.metadata.outputs.update-type != 'version-update:semver-patch' &&
steps.metadata.outputs.update-type != 'version-update:semver-minor'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ steps.app-token.outputs.token }}
PR_URL: ${{ github.event.pull_request.html_url }}
run: |
gh pr edit "${PR_URL}" --remove-label "automerge: eligible" || true
gh pr merge --disable-auto "${PR_URL}" || true
- name: Enable Auto-Merge
if: inputs.github-auto-merge && steps.label.outcome == 'success'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ steps.app-token.outputs.token }}
PR_URL: ${{ github.event.pull_request.html_url }}
run: |
gh pr review --approve "${PR_URL}"
Expand All @@ -80,9 +97,21 @@ jobs:
group: dependabot-automerge-sweep
cancel-in-progress: false
steps:
# Merging must use an app token, not GITHUB_TOKEN,
# so that CI runs post-merge.
- name: Create App Token
id: app-token
uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2
with:
app-id: ${{ secrets.DEPENDENCY_AUTOMERGE_APP_ID }}
private-key: ${{ secrets.DEPENDENCY_AUTOMERGE_APP_PRIVATE_KEY }}
permission-contents: write # required to merge PRs
permission-pull-requests: write # required to approve PRs
permission-checks: read # required to read check results
permission-statuses: read # required to read commit statuses
- name: Merge Labeled Dependabot PRs
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ steps.app-token.outputs.token }}
REPO: ${{ github.repository }}
run: |
gh pr list --repo "${REPO}" --author 'app/dependabot' \
Expand Down
Loading