Skip to content

feat: add repository_dispatch trigger to the rollback workflow#242

Merged
joshua-temple merged 1 commit into
mainfrom
feat/rollback-repository-dispatch
Jun 21, 2026
Merged

feat: add repository_dispatch trigger to the rollback workflow#242
joshua-temple merged 1 commit into
mainfrom
feat/rollback-repository-dispatch

Conversation

@joshua-temple

Copy link
Copy Markdown
Collaborator

Problem

The generated cascade-rollback.yaml workflow triggers on workflow_dispatch only. There is no way for an external system (an alerting or incident pipeline) to fire the same N-1 rollback automatically. Closes #181.

Fix

Add an opt-in rollback.repository_dispatch block on TrunkConfig (sibling-pointer pattern, all omitempty). It reuses the existing RepositoryDispatchTrigger shape, so event types are configured exactly like extra_triggers.repository_dispatch.

When enabled, the generated rollback workflow:

  • gains a repository_dispatch: trigger (with the configured event types) under on:, alongside the unchanged workflow_dispatch:.
  • coalesces every rollback parameter read so both paths resolve the same target: ${{ github.event.inputs.<x> || github.event.client_payload.<x> }} in the preflight env block, the deploy-job dry_run/deployable guard, the finalize gate, and the finalize DEPLOYABLE read. Coalesced reads inside comparisons are parenthesized so != 'true' / == '' bind to the whole value.

repository_dispatch carries no inputs; the parameters travel in client_payload, keyed name-for-name with the manual inputs:

client_payload key parameter
environment environment (required)
target prior version/SHA (omit for N-1)
deployable limit to one deployable (omit for whole env)
dry_run resolve and print without deploying

An external system fires it with one dispatches API call:

gh api repos/my-org/my-repo/dispatches \
  -f event_type=rollback-requested \
  -F 'client_payload[environment]=prod' \
  -F 'client_payload[target]=v1.4.2'

OFF-state is byte-identical

Absent the block (or with an empty rollback:), the generated workflow is byte-for-byte unchanged: workflow_dispatch-only, bare github.event.inputs.* reads, no repository_dispatch, no client_payload. schema_version is not bumped; the new fields are additive (omitempty). Guarded by a dedicated unit test plus the existing TestPlan_MatchesGeneratedBytes golden.

Validation

If rollback.repository_dispatch is present, at least one event type is required and each type must contain only [A-Za-z0-9_.-] (safe to emit verbatim into YAML).

Verification

  • go build ./cmd/... ./internal/... clean; go test ./... 1638 passed; golangci-lint run ./... no issues; e2e module build + vet clean.
  • New scenario e2e/scenarios/32-rollback-repository-dispatch.yaml PASSED under Docker: asserts the emitted repository_dispatch trigger + coalesced reads (real contains/not_contains), and regenerates drift-free. The act-based harness cannot synthesize a repository_dispatch event with a client_payload, so the external path is asserted structurally rather than executed; the workflow_dispatch path stays covered by the rollback runtime scenarios.
  • Generated YAML is actionlint-clean (new ENABLED actionlint test); all three manifest.schema.json copies regenerated and content-identical.

Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
@joshua-temple joshua-temple force-pushed the feat/rollback-repository-dispatch branch from f334242 to fa67f01 Compare June 21, 2026 12:49
@joshua-temple joshua-temple enabled auto-merge (squash) June 21, 2026 12:50
@joshua-temple joshua-temple merged commit eda2ffb into main Jun 21, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: external-signal trigger for the rollback workflow

1 participant