Skip to content

Commit bc489c4

Browse files
xerialclaude
andcommitted
Add: auto-merge workflow for Dependabot and Scala Steward PRs
Mirrors the wvlet/uni auto-merge pattern, adapted for this repo: - Uses pull_request_target so GITHUB_TOKEN gets the declared write permissions on Dependabot-authored PRs (avoids needing a GitHub App). - Skips Dependabot major-version bumps via dependabot/fetch-metadata. - Skips Scala Steward PRs labeled semver-major. - Squash-merges via --auto, so GitHub waits for required checks and reviews before merging. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent ca3fa54 commit bc489c4

2 files changed

Lines changed: 102 additions & 0 deletions

File tree

.github/workflows/auto-merge.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: auto-merge
2+
# pull_request_target runs in the base-branch context, which is required so
3+
# that GITHUB_TOKEN gets the write permissions declared below even for PRs
4+
# opened by Dependabot (which would otherwise receive a read-only token on
5+
# regular pull_request events). This workflow never checks out PR head code,
6+
# so the usual pull_request_target injection risk does not apply.
7+
on: pull_request_target
8+
9+
permissions:
10+
contents: write
11+
pull-requests: write
12+
13+
jobs:
14+
auto-merge-dependabot:
15+
name: Auto-Merge Dependabot PRs
16+
runs-on: ubuntu-latest
17+
if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }}
18+
steps:
19+
- name: Dependabot metadata
20+
id: metadata
21+
uses: dependabot/fetch-metadata@v2
22+
- name: Enable auto-merge for non-major updates
23+
if: ${{ steps.metadata.outputs.update-type != 'version-update:semver-major' }}
24+
run: gh pr merge --squash --auto "${{ github.event.pull_request.html_url }}"
25+
env:
26+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27+
28+
auto-merge-scala-steward:
29+
name: Auto-Merge Scala Steward PRs
30+
runs-on: ubuntu-latest
31+
if: ${{ github.event.pull_request.user.login == 'scala-steward' }}
32+
steps:
33+
- name: Enable auto-merge for non-major updates
34+
if: ${{ !contains(github.event.pull_request.labels.*.name, 'semver-major') }}
35+
run: gh pr merge --squash --auto "${{ github.event.pull_request.html_url }}"
36+
env:
37+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

plans/2026-05-05-auto-merge.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Add auto-merge GitHub Actions workflow
2+
3+
## Goal
4+
5+
Add a workflow that automatically enables auto-merge on PRs from trusted bots
6+
(Dependabot and Scala Steward) for non-major version bumps, mirroring the
7+
pattern used in `wvlet/uni/.github/workflows/auto-merge.yml`.
8+
9+
## Context
10+
11+
- Recent PR history shows the repo regularly receives many bot PRs:
12+
- `dependabot[bot]` — for GitHub Actions version bumps
13+
- `scala-steward` — for Scala/sbt/Java library updates
14+
- These currently require manual merge from the maintainer.
15+
- Repo settings already allow auto-merge (`allow_auto_merge: true`) and squash
16+
is the default merge method.
17+
- CI passes branch-protection checks on PRs; once a PR is approved and CI is
18+
green, GitHub will merge it automatically.
19+
20+
## Differences from wvlet/uni
21+
22+
- **No GitHub App token.** wvlet/uni uses a GitHub App (`APP_ID` +
23+
`APP_PRIVATE_KEY`) to bypass the read-only `GITHUB_TOKEN` that GitHub
24+
hands to `pull_request` workflows triggered by Dependabot. msgpack/msgpack-java
25+
doesn't have that App configured, so this workflow uses
26+
`on: pull_request_target` instead — that event runs in the base-branch
27+
context where the workflow's declared `permissions:` block actually grants
28+
write access to `GITHUB_TOKEN`. We never check out PR head code, so the
29+
usual `pull_request_target` injection risk does not apply.
30+
- **Scala Steward actor is `scala-steward`**, not wvlet/uni's
31+
`scala-steward-wvlet[bot]` or `xerial-bot` (visible in `gh pr list`).
32+
- **Filter on `github.event.pull_request.user.login`**, not `github.actor`,
33+
because under `pull_request_target` the latter can resolve to the merger
34+
rather than the PR author.
35+
36+
## Plan
37+
38+
1. Add `.github/workflows/auto-merge.yml` with two jobs:
39+
- **auto-merge-dependabot**: triggers when `github.actor == 'dependabot[bot]'`,
40+
uses `dependabot/fetch-metadata@v3` to read the update type, and runs
41+
`gh pr merge --squash --auto` only when the update is **not**
42+
`version-update:semver-major`.
43+
- **auto-merge-scala-steward**: triggers when `github.actor == 'scala-steward'`
44+
and runs `gh pr merge --squash --auto` for all such PRs (Scala Steward
45+
does not surface a structured "major" signal the way Dependabot's
46+
fetch-metadata action does, so we rely on Scala Steward's own
47+
`pullRequests.allowedUpdates` config — already filtered upstream — and
48+
skip if the PR has a `semver-major` label).
49+
2. Set workflow-level `permissions` to the minimum required:
50+
`contents: write` and `pull-requests: write`.
51+
3. Use `GITHUB_TOKEN` directly via `env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}`.
52+
53+
## Out of scope
54+
55+
- Setting up a GitHub App for elevated bot identity.
56+
- Auto-approving PRs (a human approval may still be required by branch
57+
protection — auto-merge will simply wait for it).
58+
- Changing branch protection rules.
59+
60+
## Validation
61+
62+
- Lint the YAML by checking the file parses (visual review + actionlint if
63+
available).
64+
- After merge, watch the next dependabot/scala-steward PR to confirm
65+
auto-merge gets enabled.

0 commit comments

Comments
 (0)