Skip to content

Commit 029bdfc

Browse files
Copilotwallstop
andauthored
fix(ci): clarify protected-branch auto-merge failure and add regression tests
Agent-Logs-Url: https://github.com/wallstop/fortress-rollback/sessions/3206be6d-571a-4ff3-ae8f-d4d55f409f31 Co-authored-by: wallstop <[email protected]>
1 parent 5b986b3 commit 029bdfc

3 files changed

Lines changed: 57 additions & 1 deletion

File tree

.llm/context.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ Pre-commit validates registration only, NOT that proofs pass. Run affected proof
159159

160160
Also: `ci-rust.yml` (Miri), `ci-security.yml` (cargo-geiger, cargo-deny).
161161

162-
Dependabot auto-merge policy: this repository is squash-only and the auto-merge job MUST wait for every non-self CI gate on the PR head SHA to reach an explicitly accepted state (`success`, `skipped`, `neutral`) before enabling merge. Anything else -- including `failure`, `timed_out`, `cancelled`, `action_required`, `startup_failure`, `stale`, missing/`null` conclusions, or future GitHub-added states -- refuses the merge (allow-list semantics). Use `scripts/ci/enable-dependabot-automerge.sh` -- never inline `gh pr merge` in workflows, never re-introduce a "one-shot" / bypass path, never wrap the script in a sub-job-level `timeout`. Regression-tested in `scripts/tests/test_enable_dependabot_automerge.py`.
162+
Dependabot auto-merge policy: this repository is squash-only and the auto-merge job MUST wait for every non-self CI gate on the PR head SHA to reach an explicitly accepted state (`success`, `skipped`, `neutral`) before enabling merge. Anything else -- including `failure`, `timed_out`, `cancelled`, `action_required`, `startup_failure`, `stale`, missing/`null` conclusions, or future GitHub-added states -- refuses the merge (allow-list semantics). GitHub also requires protected-branch rules (for example, requiring pull requests before merge) on the PR base branch before `enablePullRequestAutoMerge` can succeed. Use `scripts/ci/enable-dependabot-automerge.sh` -- never inline `gh pr merge` in workflows, never re-introduce a "one-shot" / bypass path, never wrap the script in a sub-job-level `timeout`. Regression-tested in `scripts/tests/test_enable_dependabot_automerge.py`.
163163

164164
**CI fails on:** unformatted code, clippy warnings, broken doc links, markdown lint errors, workflow syntax errors, unregistered Kani proofs.
165165

scripts/ci/enable-dependabot-automerge.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ attempt_automerge() {
102102
return 0
103103
fi
104104
echo "Auto-merge attempt failed for squash strategy: $output" >&2
105+
if [[ "$output" == *"enablePullRequestAutoMerge"* ]] && [[ "$output" == *"required protected branch rules"* ]]; then
106+
echo "GitHub auto-merge requires protected branch rules on the PR base branch (for example, require pull requests before merging)." >&2
107+
fi
105108
return 1
106109
}
107110

scripts/tests/test_enable_dependabot_automerge.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,11 @@ def _write_stub_gh(path: Path) -> None:
124124
if [[ "$cmd" == "pr" && "$subcmd" == "merge" ]]; then
125125
printf '%s\\n' "pr merge $*" >> "${GH_LOG_PATH:?GH_LOG_PATH is required}"
126126
success_flag="${GH_MERGE_SUCCESS_FLAG:-__none__}"
127+
error_message="${GH_MERGE_ERROR_MESSAGE:-}"
128+
if [[ -n "$error_message" ]]; then
129+
printf '%s\\n' "$error_message" >&2
130+
exit 1
131+
fi
127132
if [[ "$success_flag" == "__none__" ]]; then
128133
if [[ "$*" == *"--squash"* || "$*" == *"--rebase"* || "$*" == *"--merge"* ]]; then
129134
exit 1
@@ -291,6 +296,54 @@ def test_fails_on_merge_policy_drift(tmp_path: Path) -> None:
291296
assert not log_path.exists()
292297

293298

299+
def test_reports_branch_protection_requirement_when_automerge_api_rejects(tmp_path: Path) -> None:
300+
result = _run_script(
301+
tmp_path,
302+
{
303+
"GH_MERGE_ERROR_MESSAGE": (
304+
"GraphQL: Pull request Branch does not have required protected branch rules "
305+
"(enablePullRequestAutoMerge)"
306+
),
307+
"GH_ALLOW_SQUASH": "true",
308+
"GH_ALLOW_REBASE": "false",
309+
"GH_ALLOW_MERGE": "false",
310+
},
311+
)
312+
assert result.returncode == 1
313+
assert "required protected branch rules" in result.stderr
314+
assert "GitHub auto-merge requires protected branch rules" in result.stderr
315+
log_lines = (tmp_path / "gh.log").read_text(encoding="utf-8").splitlines()
316+
assert len(log_lines) == 3
317+
assert "--required --json name --jq length" in log_lines[0]
318+
assert "--required --json name,state,link" in log_lines[1]
319+
assert "--squash" in log_lines[2]
320+
321+
322+
def test_does_not_report_branch_protection_requirement_for_other_automerge_errors(
323+
tmp_path: Path,
324+
) -> None:
325+
result = _run_script(
326+
tmp_path,
327+
{
328+
"GH_MERGE_ERROR_MESSAGE": (
329+
"GraphQL: Auto-merge is disabled for this pull request "
330+
"(enablePullRequestAutoMerge)"
331+
),
332+
"GH_ALLOW_SQUASH": "true",
333+
"GH_ALLOW_REBASE": "false",
334+
"GH_ALLOW_MERGE": "false",
335+
},
336+
)
337+
assert result.returncode == 1
338+
assert "enablePullRequestAutoMerge" in result.stderr
339+
assert "GitHub auto-merge requires protected branch rules" not in result.stderr
340+
log_lines = (tmp_path / "gh.log").read_text(encoding="utf-8").splitlines()
341+
assert len(log_lines) == 3
342+
assert "--required --json name --jq length" in log_lines[0]
343+
assert "--required --json name,state,link" in log_lines[1]
344+
assert "--squash" in log_lines[2]
345+
346+
294347
def test_falls_back_to_all_checks_when_required_checks_count_is_zero(
295348
tmp_path: Path,
296349
) -> None:

0 commit comments

Comments
 (0)