flow: squash into dev, fast-forward the promotions
All checks were successful
PR build (required check) / changes (pull_request) Successful in 8s
shell-lint / shellcheck (pull_request) Successful in 7s
secrets-guard / encrypted (pull_request) Successful in 10s
PR build (required check) / build-backend (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Has been skipped
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / gate (pull_request) Successful in 3s
All checks were successful
PR build (required check) / changes (pull_request) Successful in 8s
shell-lint / shellcheck (pull_request) Successful in 7s
secrets-guard / encrypted (pull_request) Successful in 10s
PR build (required check) / build-backend (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Has been skipped
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / gate (pull_request) Successful in 3s
Forgejo cannot scope merge styles per branch — they live on the repo's pull-request unit, and BranchProtection carries no merge-style or linear-history field in 9.0.3. So the chain is enforced repo-wide by allowing exactly two styles: squash and fast-forward-only. Merge commits and rebase merges are off. Squash belongs on the short-lived hop. Squashing dev into main would put a commit on main that does not have dev's commits as ancestors, freezing merge-base(dev, main); every later promotion would then list all commits since that stale point and re-apply changes main already has. Fast-forwarding the promotions instead means a promotion creates no commit at all, so the three branches keep identical history rather than merely identical trees, and `release ⊆ main ⊆ dev` holds permanently. Rebase-updates stay enabled. They are a different setting from rebase merges, and BRANCHING.md is right that the merge queue 403s without them. Also adds `release` to pr-build.yml's pull_request branches. This is step one of the order BRANCHING.md prescribes for closing the missing check on release: teach the workflow to fire there, confirm on a real PR that the context appears, and only then require it. Requiring a context nothing produces is what makes a production promotion unmergeable with a 405 that names no cause.
This commit is contained in:
parent
e9e9512155
commit
ea613e33ca
3 changed files with 24 additions and 3 deletions
|
|
@ -71,8 +71,14 @@ correct" rather than erroring.
|
||||||
is a divergence to reconcile deliberately, not to overwrite.
|
is a divergence to reconcile deliberately, not to overwrite.
|
||||||
2. **`dev` is the default branch.**
|
2. **`dev` is the default branch.**
|
||||||
`forge_repo_settings(apply_flow_defaults=true)` — sets the default branch and
|
`forge_repo_settings(apply_flow_defaults=true)` — sets the default branch and
|
||||||
permits every merge style the chain uses, including `fast-forward-only`, plus
|
permits the merge styles the chain uses, plus rebase-updates (without which
|
||||||
rebase-updates (without which the merge queue's core primitive 403s).
|
the merge queue's core primitive 403s).
|
||||||
|
|
||||||
|
The chain uses exactly two: **squash** for `feat/*` → `dev`, and
|
||||||
|
**fast-forward-only** for both promotions. Merge commits and rebase merges
|
||||||
|
are disabled deliberately — see the merge-style table in the root
|
||||||
|
`CLAUDE.md`. If `apply_flow_defaults` re-enables them, that is the tool
|
||||||
|
disagreeing with the policy, not permission to use them.
|
||||||
3. **Protection.** `forge_branch_protection(branch="dev", apply=true)`, then
|
3. **Protection.** `forge_branch_protection(branch="dev", apply=true)`, then
|
||||||
`main`, then `release`.
|
`main`, then `release`.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ name: PR build (required check)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [dev, main]
|
branches: [dev, main, release]
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: pr-build-${{ github.event.pull_request.number }}
|
group: pr-build-${{ github.event.pull_request.number }}
|
||||||
|
|
|
||||||
15
CLAUDE.md
15
CLAUDE.md
|
|
@ -22,6 +22,21 @@ every change, so a stale one is a correctness bug, not a documentation bug.
|
||||||
`dev`, `main` and `release` are protected: **everything is a PR**, for humans and
|
`dev`, `main` and `release` are protected: **everything is a PR**, for humans and
|
||||||
agents alike. Promotion is one PR per hop, `dev` → `main` → `release`.
|
agents alike. Promotion is one PR per hop, `dev` → `main` → `release`.
|
||||||
|
|
||||||
|
**Merge style is part of the contract**, and Forgejo enforces it repo-wide —
|
||||||
|
it cannot scope styles per branch, so these are the only two enabled:
|
||||||
|
|
||||||
|
| Hop | Style |
|
||||||
|
|---|---|
|
||||||
|
| `feat/*` → `dev` | **squash** |
|
||||||
|
| `dev` → `main`, `main` → `release` | **fast-forward only** |
|
||||||
|
|
||||||
|
Merge commits and rebase merges are disabled. A promotion therefore never
|
||||||
|
creates a commit, which keeps `release ⊆ main ⊆ dev` true permanently: the
|
||||||
|
three branches hold identical history, never merely identical trees. Squashing
|
||||||
|
into `main` instead would strand `merge-base(dev, main)` and make every later
|
||||||
|
promotion re-apply work already there. Rebase-*updates* stay enabled — the
|
||||||
|
merge queue 403s without them.
|
||||||
|
|
||||||
`.claude/BRANCHING.md` is the orchestrator's runbook for that flow — the
|
`.claude/BRANCHING.md` is the orchestrator's runbook for that flow — the
|
||||||
serialised merge queue, promotions, hotfix down-merges — and
|
serialised merge queue, promotions, hotfix down-merges — and
|
||||||
`.claude/ownership.md` is the module map saying which tasks may run
|
`.claude/ownership.md` is the module map saying which tasks may run
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue