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
28 changes: 27 additions & 1 deletion .github/workflows/dependabot-auto-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,34 @@ jobs:
steps.meta.outputs.update-type != '' &&
contains(format(',{0},', inputs.allowed-update-types),
format(',{0},', steps.meta.outputs.update-type))
run: gh pr merge --auto --${{ inputs.merge-method }} "$PR_URL"
# Two failure modes this handles, both seen in production on the
# wemove.eu / youmove / wemove-charity.eu inline copies this replaces:
#
# 1. `gh pr merge --auto` intermittently returns a transient GraphQL
# error, which strands the PR until a human notices.
# 2. Auto-merge cannot be enabled on a PR whose required checks have
# ALREADY passed. With fast CI the checks often win the race, and
# the PR then sits green and unmerged forever.
#
# So: retry, and fall back to a direct merge. The direct merge is not a
# bypass — branch protection still refuses it while required checks are
# pending or failing. On a repo with NO required checks it would merge
# immediately, which is exactly why a ruleset is part of the entry bar
# for using this workflow at all (see the note at the top).
#
# merge-method goes through env, not `${{ }}` interpolation into the
# script body, so a caller cannot inject shell through it.
run: |
for attempt in 1 2 3 4 5; do
if gh pr merge --auto --"$MERGE_METHOD" "$PR_URL"; then exit 0; fi
if gh pr merge --"$MERGE_METHOD" "$PR_URL"; then exit 0; fi
echo "attempt $attempt: could not enable auto-merge yet; retrying in 15s..."
sleep 15
done
echo "::error::failed to enable auto-merge after 5 attempts"
exit 1
env:
PR_URL: ${{ github.event.pull_request.html_url }}
MERGE_METHOD: ${{ inputs.merge-method }}
# Falls back to GITHUB_TOKEN when the App token step was skipped.
GH_TOKEN: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }}
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,13 @@ depends on a branch ruleset (require a PR + required checks) on the consuming re
Without that ruleset `gh pr merge --auto` has nothing to wait for and the PR merges
immediately.

Arming is retried five times, and falls back to a direct merge. That covers two real
failure modes: `gh pr merge --auto` intermittently returns a transient GraphQL error, and
auto-merge cannot be enabled at all on a PR whose required checks have *already* gone
green — which fast CI makes common, and which otherwise leaves the PR sitting green and
unmerged. The direct merge is not a bypass: branch protection still refuses it while
required checks are pending or failing.

### Inputs

- **merge-method**: `merge` | `squash` | `rebase`. Default `squash`.
Expand Down Expand Up @@ -261,6 +268,7 @@ jobs:
Version tags `v1`–`v13` predate the current scheme and are frozen point releases. The
floating-major convention (see [`RELEASING.md`](RELEASING.md)) starts at **`v14`**.

- **v14.2** — `dependabot-auto-merge.yml`: arming is now retried (5 attempts) with a direct-merge fallback, so a transient GraphQL error no longer strands a PR and an already-green PR still merges. Consolidates logic that existed only in the inline copies in wemove.eu, youmove, wemove-charity.eu and pubstatic, which this lets them drop.
- **v14.1** — `dependabot-auto-merge.yml`: accepts optional `app-id` / `app-private-key` secrets so the merge is armed with a GitHub App token and fires a real push event (a `GITHUB_TOKEN`-armed merge does not, leaving push-triggered deploys silently unrun). Falls back to `GITHUB_TOKEN` when the secrets are omitted, and warns. The update-type gate is now a whole-token, fail-closed match — previously an empty `update-type` from `fetch-metadata` satisfied `contains()` and could auto-merge a major.
- **v14** — First release under the semver + floating-major scheme. Ships the `docker-smoke` composite action (build + run + production-Host-header probe, with a `build-only` mode).
- **v13** — Adds a reusable Dependabot auto-merge workflow and an actionlint CI gate.
Expand Down