feat(pull): require explicit e2e scope on merge_pull_request #15

Merged
Phil merged 1 commit from feat/merge-e2e-gate into main 2026-07-10 20:35:53 +00:00
Owner

Why

Merging a PR left the post-deploy E2E decision to a free-form commit-message token the caller had to remember. Forgetting it — or picking a spec pattern that grep-matched zero specs — let a stray full E2E run occupy the staging-stack / prod-stack deploy concurrency lock, forcing a routine manual cancel. This moves the decision to a required, no-default tool parameter (root-cause, not a workaround: opt-in gating was explicitly rejected).

What

merge_pull_request now takes a required e2e parameter (omission → tool error, never a silent fallback). The tool:

  1. Fetches the PR to resolve its base branch (pr.Base.Ref).
  2. Enforces a per-target policy:
    PR base allowed e2e rejected
    dev (staging) skip · smoke · full · scoped:<pattern>
    master (prod) full · scoped:<pattern> skip, smoke → actionable error (prod always runs E2E)
  3. Generates the commit-message token itself and appends it to the merge commit message (empty message → token becomes the body):
    • skip[skip e2e] (dev only)
    • smoke → no token (staging default is smoke)
    • fulldev: [e2e: full] (reserved keyword → suite=all on staging); master: no token (prod default suite is already all; [e2e: full] there would set tests=full and match zero specs)
    • scoped:<pattern>[e2e: <pattern>]

For a base other than dev/master no deploy fires, so any valid value is accepted and no token is injected.

Tests

TestResolveE2EToken covers the full policy matrix. go test ./operation/pull/ green in golang:1.26-alpine.

Companion PR (lands together)

Workflow-side of the shared token contract — extends parse-selectors so [e2e: full] → staging suite=all, plus the pre-push backstop hook:
Philflow/flow.raven#2744 (Closes flow.raven#2742).

⚠️ Landing order: merge flow.raven#2744 first (so the parser understands [e2e: full]), then this PR, then rebuild + install the new binary. Activating the binary before the parser lands would emit [e2e: full] into a workflow that still greps zero specs.

Closes #13

## Why Merging a PR left the post-deploy E2E decision to a free-form commit-message token the caller had to remember. Forgetting it — or picking a spec pattern that grep-matched zero specs — let a stray full E2E run occupy the `staging-stack` / `prod-stack` deploy concurrency lock, forcing a routine manual cancel. This moves the decision to a **required, no-default tool parameter** (root-cause, not a workaround: opt-in gating was explicitly rejected). ## What `merge_pull_request` now takes a **required `e2e` parameter** (omission → tool error, never a silent fallback). The tool: 1. Fetches the PR to resolve its **base branch** (`pr.Base.Ref`). 2. Enforces a per-target policy: | PR base | allowed `e2e` | rejected | |---|---|---| | `dev` (staging) | `skip` · `smoke` · `full` · `scoped:<pattern>` | — | | `master` (prod) | `full` · `scoped:<pattern>` | `skip`, `smoke` → actionable error (prod always runs E2E) | 3. Generates the commit-message token itself and appends it to the merge commit message (empty message → token becomes the body): - `skip` → `[skip e2e]` (dev only) - `smoke` → no token (staging default is smoke) - `full` → **dev:** `[e2e: full]` (reserved keyword → `suite=all` on staging); **master:** no token (prod default suite is already `all`; `[e2e: full]` there would set `tests=full` and match zero specs) - `scoped:<pattern>` → `[e2e: <pattern>]` For a base other than dev/master no deploy fires, so any valid value is accepted and no token is injected. ## Tests `TestResolveE2EToken` covers the full policy matrix. `go test ./operation/pull/` green in `golang:1.26-alpine`. ## Companion PR (lands together) Workflow-side of the shared token contract — extends `parse-selectors` so `[e2e: full]` → staging `suite=all`, plus the pre-push backstop hook: **Philflow/flow.raven#2744** (Closes flow.raven#2742). > ⚠️ Landing order: merge **flow.raven#2744 first** (so the parser understands `[e2e: full]`), then this PR, then rebuild + install the new binary. Activating the binary before the parser lands would emit `[e2e: full]` into a workflow that still greps zero specs. Closes #13
Merging a PR previously left the post-deploy E2E decision to a free-form
commit-message token the caller had to remember to add. Forgetting it (or
picking a spec pattern that grep-matched zero specs) let a stray full E2E
run occupy the deploy concurrency lock, forcing a routine manual cancel.

Make `e2e` a required, no-default parameter. The tool resolves the PR base
branch and enforces a per-target policy — dev allows skip|smoke|full|
scoped:<pattern>, master allows only full|scoped:<pattern> (skip/smoke
rejected so prod always runs E2E) — then generates the exact commit-message
token itself and injects it into the merge commit message. Omission is a
tool error, not a silent fallback.

Token mapping is verified against flow.raven's run-e2e selector semantics:
`full` on dev emits the reserved `[e2e: full]` (→ suite=all on staging),
while on master it emits no token because the prod default suite is already
the full suite (emitting [e2e: full] there would set tests=full and match
zero specs).

Closes #13
Phil merged commit b98a5e8d1c into main 2026-07-10 20:35:53 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Phil/forgejo-mcp!15
No description provided.