From 28de064abad030bc82848346ef6b999297fb4538 Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Wed, 15 Jul 2026 01:05:14 +0200 Subject: [PATCH 1/2] docs(merge-strategy): document merge-queue enablement via ruleset The skill covered merge-queue behavior and troubleshooting but not how to turn one on. Adds an 'Enabling a merge queue' section: the ruleset REST payload (classic branch-protection cannot toggle it; the merge_queue rule is repo-level only), the merge_queue parameters with their gotchas (SQUASH/MERGE signed vs REBASE unsigned, ALLGREEN vs HEADGREEN, the check-response timeout as an eject trigger, min_entries_to_merge_wait being inert when the minimum is 1), integration_id pinning of required checks, single-surface enablement with strict dropped as redundant, and evaluate-mode dry-run plus one-call rollback. Signed-off-by: Sebastian Mendel --- .../references/merge-strategy.md | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/skills/github-project/references/merge-strategy.md b/skills/github-project/references/merge-strategy.md index 5e09b33..e31c7e9 100644 --- a/skills/github-project/references/merge-strategy.md +++ b/skills/github-project/references/merge-strategy.md @@ -158,6 +158,57 @@ Mitigations, in increasing strength: Neither catches a semantic conflict no test covers. Post-merge push CI on the default branch stays the last line of defence — keep it. +## Enabling a merge queue + +The classic branch-protection REST API does **not** expose a merge-queue toggle, so a repository **ruleset** is the only scriptable path. The `merge_queue` rule is **repository-level only** — an org-level ruleset rejects it, so a queue is always a per-repo decision. + +```bash +gh api -X POST repos/OWNER/REPO/rulesets --input - <<'JSON' +{ + "name": "merge-queue-main", + "target": "branch", + "enforcement": "active", + "bypass_actors": [ + { "actor_id": 5, "actor_type": "RepositoryRole", "bypass_mode": "always" } + ], + "conditions": { "ref_name": { "include": ["refs/heads/main"], "exclude": [] } }, + "rules": [ + { + "type": "merge_queue", + "parameters": { + "merge_method": "SQUASH", + "grouping_strategy": "ALLGREEN", + "check_response_timeout_minutes": 30, + "max_entries_to_build": 5, + "max_entries_to_merge": 5, + "min_entries_to_merge": 1, + "min_entries_to_merge_wait_minutes": 5 + } + }, + { + "type": "required_status_checks", + "parameters": { + "strict_required_status_checks_policy": false, + "required_status_checks": [ + { "context": "Tests (8.2)", "integration_id": 15368 } + ] + } + } + ] +} +JSON +``` + +Parameters and gotchas: + +- `merge_method`: `SQUASH` | `MERGE` | `REBASE`. The queue owns the merge method for every entry, so per-PR choice disappears. `SQUASH`/`MERGE` stay GitHub-signed; `REBASE` re-creates commits **unsigned** — on a signed-commits branch, prefer `SQUASH`/`MERGE`. +- `grouping_strategy`: `ALLGREEN` (every queued entry must pass) or `HEADGREEN` (only the group's head commit — all changes combined — must pass). `ALLGREEN` is the safe default; `HEADGREEN` only saves CI under contention. +- `check_response_timeout_minutes`: a required check that has not reported by then is treated as **failed** and the entry is ejected. Size it above one CI cycle. +- `min_entries_to_merge` + `min_entries_to_merge_wait_minutes`: the wait only holds a smaller-than-minimum group. With `min_entries_to_merge: 1` **the wait value is inert** — a single entry already meets the minimum, so it never batches. Only raise the minimum (and the wait) if you actually want to batch, e.g. a Dependabot burst. +- `required_status_checks[].integration_id: 15368` pins each required context to the **GitHub Actions app**, so another app cannot satisfy (spoof) the context. Every required-check workflow must also carry an `on: merge_group:` trigger, or its checks never report on the queue and every group times out. +- Enable the queue in **one surface only**. If a classic branch-protection rule already gates the branch, leave reviews/conversation-resolution there and put the queue + required checks in the ruleset — then set the classic `strict` ("require branches up to date") flag to **false**: the queue makes it redundant and it otherwise forces author-side update-branch churn. +- `enforcement: "evaluate"` dry-runs the ruleset (logs what it *would* block) without enforcing — a soft launch before `active`. Rollback is one call: delete the ruleset (or set `enforcement: "disabled"`) and restore the classic `strict` flag. + ## Troubleshooting ### Diagnose `mergeStateStatus: BLOCKED` before naming a cause From d190fb4c614243c1a379b16da7194eecbeaefbdb Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Wed, 15 Jul 2026 01:05:56 +0200 Subject: [PATCH 2/2] docs(dependency-management): SHA-pin comment upkeep and deprecation-warning verification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two GitHub Actions facts: - Dependabot rewrites the trailing '# vX.Y.Z' comment together with the SHA, so annotating bare pins once (with API-verified tags) puts them in the format it maintains; without the github-actions ecosystem, pins only drift by hand. - A runtime-deprecation warning (e.g. Node 20) is only cleared by a bump if the newer release changed the runtime — check the target version's action.yml runs.using before claiming a bump fixes it; an action already at latest can still warn. Signed-off-by: Sebastian Mendel --- .../references/dependency-management.md | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/skills/github-project/references/dependency-management.md b/skills/github-project/references/dependency-management.md index 1793b2f..876bbb0 100644 --- a/skills/github-project/references/dependency-management.md +++ b/skills/github-project/references/dependency-management.md @@ -91,6 +91,27 @@ updates: dependency-type: "development" ``` +### SHA-Pinned Actions — Comment Maintenance and Deprecation Warnings + +**Dependabot maintains the version comment, not just the SHA.** With the `github-actions` ecosystem enabled, a bump rewrites both the pinned SHA **and** the trailing `# vX.Y.Z` comment in one diff: + +```diff +- uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 ++ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 +``` + +So annotating bare SHA pins once (with **API-verified** tags — resolve each SHA via `gh api repos/OWNER/ACTION/tags`) puts them in the exact format Dependabot then keeps current. Without the `github-actions` ecosystem declared, action pins are only ever updated by hand and silently drift. + +**A runtime-deprecation warning is not cleared by a version bump unless the newer release changed the runtime.** Before claiming "bumping action X fixes the Node NN deprecation", check the target version's `action.yml`: + +```bash +gh api -H "Accept: application/vnd.github.raw" \ + repos/OWNER/ACTION/contents/action.yml?ref= | grep -A1 '^runs:' +# runs.using: 'node20' → still deprecated; the bump does NOT clear the warning +``` + +An action already pinned at its latest release can still emit the warning if upstream ships no newer-runtime build — the fix is then an upstream change or a replacement action, not a bump. Don't assert the warning is fixed off the version number alone. + ## Renovate ### Auto-merge Configuration (Recommended)