Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/public/manifest.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@
"properties": {
"disabled": { "type": "boolean", "description": "Disable cascade-managed releases." },
"tag": { "type": "string", "description": "callback.output reference for releases created by an external tool." },
"workflow": { "type": "string", "description": "Path to a reusable release-build workflow dispatched after a release is published." },
"version_overrides": { "$ref": "#/definitions/versionOverridesConfig" }
}
},
Expand Down
14 changes: 14 additions & 0 deletions e2e/harness/scenario.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,20 @@ type Config struct {
// can declare any reserved release field without the harness needing to know
// its structure.
Release map[string]any `yaml:"release,omitempty"`
// ExtraTriggers carries the optional extra orchestrate triggers (schedule,
// repository_dispatch, workflow_run, merge_group) through to the generated
// manifest untouched, so a scenario can assert each extra on: entry is
// emitted into the orchestrate workflow. A generic map keeps the harness
// decoupled from the generator's ExtraTriggers shape.
ExtraTriggers map[string]any `yaml:"extra_triggers,omitempty"`
// PinMode carries the action pin mode (tag or sha) through to the generated
// manifest so a scenario can assert the sha-pinned uses: form versus the
// default tag form.
PinMode string `yaml:"pin_mode,omitempty"`
// ActionPins carries per-action ref overrides through to the generated
// manifest so a scenario can assert an overridden uses: ref is honored
// regardless of pin mode.
ActionPins map[string]string `yaml:"action_pins,omitempty"`
}

// PublishConfig defines a publish callback invoked after a release is published
Expand Down
65 changes: 65 additions & 0 deletions e2e/scenarios/34-extra-orchestrate-triggers.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: "Extra orchestrate triggers"
description: |
Verifies that declaring extra_triggers in the manifest emits each extra
on: entry into the generated orchestrate workflow alongside the baseline
push and workflow_dispatch triggers (#324).

Covers all four extra trigger kinds in one manifest:
- schedule with cron expressions
- repository_dispatch with event types
- workflow_run with workflows and types
- merge_group (bare presence)

Generator-output verification only.

config:
trunk_branch: main
environments: [dev]
builds:
- name: app
workflow: build.yaml
triggers: ["src/**"]
deploys: []
extra_triggers:
schedule:
- cron: "0 2 * * *"
repository_dispatch:
types:
- external-update
- redeploy
workflow_run:
workflows:
- Upstream CI
types:
- completed
merge_group: {}

steps:
- name: "Initial commit; assert every extra trigger is emitted in orchestrate.yaml"
action: commit
commit:
message: "feat: add app"
files:
src/app.go: |
package main
func main() {}
expect:
workflow_files:
- path: ".github/workflows/orchestrate.yaml"
contains:
# Baseline triggers remain present.
- " push:\n"
- " workflow_dispatch:\n"
# schedule extra trigger.
- " schedule:\n"
- " - cron: '0 2 * * *'\n"
# repository_dispatch extra trigger with both types.
- " repository_dispatch:\n"
- " - external-update\n"
- " - redeploy\n"
# workflow_run extra trigger with workflow name and type.
- " workflow_run:\n"
- " - 'Upstream CI'\n"
- " - completed\n"
# merge_group extra trigger (bare presence).
- " merge_group:\n"
40 changes: 40 additions & 0 deletions e2e/scenarios/35-action-pins-sha-mode.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: "Action pins: sha mode pins to an immutable commit"
description: |
Verifies that pin_mode: sha rewrites third-party action refs to a 40-hex
commit SHA with a trailing version comment, instead of the default mutable
major tag (#327).

Covers:
- pin_mode: sha emits actions/checkout@<40hex> # v6.0.3
- the default mutable major tag (v6) no longer appears once sha-pinned

Generator-output verification only.

config:
trunk_branch: main
environments: [dev]
builds:
- name: app
workflow: build.yaml
triggers: ["src/**"]
deploys: []
pin_mode: sha

steps:
- name: "Initial commit; assert the sha-pinned uses: form in orchestrate.yaml"
action: commit
commit:
message: "feat: add app"
files:
src/app.go: |
package main
func main() {}
expect:
workflow_files:
- path: ".github/workflows/orchestrate.yaml"
contains:
# sha mode pins checkout to its 40-hex SHA with a version comment.
- "uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3"
not_contains:
# the mutable major tag must not appear once sha-pinned.
- "uses: actions/checkout@v6\n"
40 changes: 40 additions & 0 deletions e2e/scenarios/36-action-pins-default-tag.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: "Action pins: default mode emits the mutable major tag"
description: |
Verifies the default pin behavior (no pin_mode): third-party action refs
are emitted at their built-in mutable major tag, with no sha pin (#327).
This is the baseline the sha mode in 35-action-pins-sha-mode.yaml contrasts
against.

Covers:
- the default emits actions/checkout@v6 with no sha comment
- no 40-hex sha pin is emitted for checkout when pin_mode is unset

Generator-output verification only.

config:
trunk_branch: main
environments: [dev]
builds:
- name: app
workflow: build.yaml
triggers: ["src/**"]
deploys: []

steps:
- name: "Initial commit; assert the default mutable major tag in orchestrate.yaml"
action: commit
commit:
message: "feat: add app"
files:
src/app.go: |
package main
func main() {}
expect:
workflow_files:
- path: ".github/workflows/orchestrate.yaml"
contains:
# default behavior emits the built-in mutable major tag, no sha comment.
- "uses: actions/checkout@v6\n"
not_contains:
# without pin_mode: sha, no 40-hex sha pin for checkout is emitted.
- "uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10"
53 changes: 53 additions & 0 deletions e2e/scenarios/37-release-breaking-gate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: "Release workflow breaking-change gate, dry-run, concurrency"
description: |
Verifies that the single-environment release workflow emits its
breaking-change gate, the dry_run skip wiring, and the serialized
non-cancelling concurrency block (#322).

A single-environment manifest generates a Release workflow into
promote.yaml (see 09-single-env-repo.yaml). This asserts the generated
shape of that workflow.

Covers:
- allow_breaking_changes workflow_dispatch input
- the Check Breaking Changes preflight step and its can_proceed outputs
- the dry_run workflow_dispatch input and the release-job skip guard
- the top-level concurrency block with cancel-in-progress: false

Generator-output verification only.

config:
trunk_branch: main
environments: [prod]
deploys:
- name: app
workflow: .github/workflows/deploy.yaml
triggers: ["src/**"]

steps:
- name: "Initial commit generates release-flavored promote.yaml; assert the breaking gate"
action: commit
commit:
message: "feat: add app source"
files:
src/app.go: |
package main
func main() {}
expect:
workflow_files:
- path: ".github/workflows/promote.yaml"
contains:
# Breaking-change gate input and detection step.
- " allow_breaking_changes:\n"
- " - name: Check Breaking Changes\n"
- " ALLOW_BREAKING: ${{ github.event.inputs.allow_breaking_changes }}\n"
- " echo \"has_breaking=$HAS_BREAKING\" >> \"$GITHUB_OUTPUT\"\n"
# The gate proceeds only when allowed, and blocks otherwise.
- " echo \"can_proceed=true\" >> \"$GITHUB_OUTPUT\"\n"
- " echo \"can_proceed=false\" >> \"$GITHUB_OUTPUT\"\n"
# dry_run input and the release-job skip guard.
- " dry_run:\n"
- " if: ${{ github.event.inputs.dry_run != 'true' }}\n"
# Serialized, non-cancelling concurrency block.
- "concurrency:\n"
- " cancel-in-progress: false\n"
51 changes: 51 additions & 0 deletions e2e/scenarios/38-promote-breaking-gate-release-build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: "Promote breaking-change gate and release-build dispatch"
description: |
Verifies that the multi-environment promote workflow emits its
CLI-driven breaking-change gate and the follow-on release-build dispatch
when release.workflow is configured (#322).

Covers:
- allow_breaking_changes workflow_dispatch input
- the cascade promote preflight run with the --allow-breaking flag
- the dry_run input and the promote-job skip guard
- the Trigger Release Build step dispatching the configured release-build
workflow after a final-env publication

Generator-output verification only.

config:
trunk_branch: main
environments: [dev, test, prod]
deploys:
- name: app
workflow: .github/workflows/deploy.yaml
triggers: ["src/**"]
release:
workflow: .github/workflows/release-build.yaml

steps:
- name: "Initial commit generates promote.yaml; assert gate and release-build dispatch"
action: commit
commit:
message: "feat: add app source"
files:
src/app.go: |
package main
func main() {}
expect:
workflow_files:
- path: ".github/workflows/promote.yaml"
contains:
# Breaking-change gate input and CLI-driven preflight.
- " allow_breaking_changes:\n"
- " cascade promote preflight \\\n"
- " --allow-breaking=\"${ALLOW_BREAKING:-false}\" \\\n"
# dry_run input and the promote-job skip guard.
- " dry_run:\n"
- " if: ${{ github.event.inputs.dry_run != 'true' }}\n"
# Follow-on release-build dispatch against the published tag.
- " - name: Trigger Release Build\n"
- " gh workflow run ./.github/workflows/release-build.yaml \\\n"
not_contains:
# The promote path uses the CLI gate, not the release bash step.
- " - name: Check Breaking Changes\n"
43 changes: 43 additions & 0 deletions e2e/scenarios/39-action-pins-override.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: "Action pins: per-action override is honored over the pin mode"
description: |
Verifies that a per-action action_pins override wins over the active pin
mode, emitting the override ref verbatim. This is both the per-action
override and the mutable-ref escape hatch: even under pin_mode: sha, an
override ref (here a mutable major tag) is emitted unchanged (#327).

Covers:
- action_pins[actions/checkout] override wins under pin_mode: sha
- the override ref is emitted verbatim, not the built-in sha pin

Generator-output verification only.

config:
trunk_branch: main
environments: [dev]
builds:
- name: app
workflow: build.yaml
triggers: ["src/**"]
deploys: []
pin_mode: sha
action_pins:
actions/checkout: "v6"

steps:
- name: "Initial commit; assert the override ref wins over the sha pin"
action: commit
commit:
message: "feat: add app"
files:
src/app.go: |
package main
func main() {}
expect:
workflow_files:
- path: ".github/workflows/orchestrate.yaml"
contains:
# the override ref is emitted verbatim, as a mutable-ref opt-in.
- "uses: actions/checkout@v6\n"
not_contains:
# the built-in sha pin must not appear when overridden.
- "uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10"
1 change: 1 addition & 0 deletions internal/schema/manifest.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@
"properties": {
"disabled": { "type": "boolean", "description": "Disable cascade-managed releases." },
"tag": { "type": "string", "description": "callback.output reference for releases created by an external tool." },
"workflow": { "type": "string", "description": "Path to a reusable release-build workflow dispatched after a release is published." },
"version_overrides": { "$ref": "#/definitions/versionOverridesConfig" }
}
},
Expand Down
1 change: 1 addition & 0 deletions schema/manifest.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@
"properties": {
"disabled": { "type": "boolean", "description": "Disable cascade-managed releases." },
"tag": { "type": "string", "description": "callback.output reference for releases created by an external tool." },
"workflow": { "type": "string", "description": "Path to a reusable release-build workflow dispatched after a release is published." },
"version_overrides": { "$ref": "#/definitions/versionOverridesConfig" }
}
},
Expand Down
Loading