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
2 changes: 1 addition & 1 deletion .github/workflows/promote.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# All intermediate environments updated with same artifact
# Fails entirely if any step fails (no partial state)
#
# Release states (based on position):
# Release states (role, or position when no role is set):
#
# Breaking changes:
# Breaking changes block at: pre-release → release AND release → prod
Expand Down
31 changes: 21 additions & 10 deletions docs/public/manifest.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@
},
"environments": {
"type": "array",
"items": { "type": "string" },
"description": "Ordered list of promotion environments. Empty means a no-environment setup (library or CLI projects)."
"items": { "$ref": "#/definitions/environmentEntry" },
"description": "Ordered promotion ladder. Each entry is a bare name (sugar) or an object with the environment's name, optional role, and inline settings. Empty means a no-environment setup (library or CLI projects)."
},
"cli_version": {
"type": "string",
Expand Down Expand Up @@ -181,11 +181,6 @@
"description": "Explicit action reference pins keyed by action name."
},
"telemetry": { "$ref": "#/definitions/telemetryConfig" },
"environment_config": {
"type": "object",
"additionalProperties": { "$ref": "#/definitions/environmentConfig" },
"description": "Per-environment settings keyed by environment name."
},
"components": {
"type": "object",
"additionalProperties": { "$ref": "#/definitions/componentConfig" },
Expand Down Expand Up @@ -527,7 +522,7 @@
"properties": {
"path": { "type": "string", "description": "Subtree this component owns within the repo. Required." },
"tag_grammar": { "$ref": "#/definitions/tagGrammarConfig" },
"environments": { "type": "array", "items": { "type": "string" }, "description": "Overrides the shared promotion environments for this component." },
"environments": { "type": "array", "items": { "$ref": "#/definitions/environmentEntry" }, "description": "Overrides the shared promotion ladder for this component (bare names or objects with inline settings); whole-replaces the inherited list." },
"release_trigger": { "type": "string", "enum": ["push", "dispatch"], "description": "Overrides how this component's orchestrate workflow fires." },
"allow_breaking_changes": { "type": "boolean", "description": "Overrides the shared breaking-change promote gate for this component." },
"validate": { "$ref": "#/definitions/validateConfig" },
Expand All @@ -547,7 +542,6 @@
"validate_check": { "$ref": "#/definitions/validateCheckConfig" },
"rollback": { "$ref": "#/definitions/rollbackConfig" },
"deployments": { "$ref": "#/definitions/deploymentsConfig" },
"environment_config": { "type": "object", "additionalProperties": { "$ref": "#/definitions/environmentConfig" }, "description": "Overrides the shared per-environment settings for this component." },
"triggers": { "type": "array", "items": { "type": "string" }, "description": "Overrides the shared orchestrate path filter for this component." },
"extra_paths": { "type": "array", "items": { "type": "string" }, "description": "Repo-relative globs beyond this component's own path that both fire its orchestrate workflow and count toward its version bump, so a change to a shared dependency this component consumes bumps it correctly. Additive to path and to any top-level shared_paths." },
"release_token": { "type": "string", "description": "Overrides the shared release-operations token expression for this component." },
Expand Down Expand Up @@ -822,11 +816,28 @@
"secret_name": { "type": "string", "description": "Name of a GitHub Actions secret holding the auth token (a reference, never an inline token). Reserved." }
}
},
"environmentEntry": {
"oneOf": [
{ "type": "string", "description": "Environment name; sugar for an environment with no inline settings." },
{ "$ref": "#/definitions/environmentConfig" }
],
"description": "One entry in the environments ladder: a bare name or an object carrying the name, an optional role, and inline per-environment settings."
},
"environmentConfig": {
"type": "object",
"additionalProperties": false,
"description": "Per-environment settings block. All fields are optional and additive; the cascade environments command emits these as an operator-appliable GitHub Environments REST config.",
"required": ["name"],
"description": "An environments entry in object form: the environment name, an optional promotion role, and the inline per-environment settings the cascade environments command emits as an operator-appliable GitHub Environments REST config.",
"properties": {
"name": {
"type": "string",
"description": "Environment name. Keys job IDs and expression references and defines this entry's rung on the promotion ladder."
},
"role": {
"type": "string",
"enum": ["prerelease", "release"],
"description": "Optional explicit promotion stage, overriding the positional default (last entry = release, second-from-last = prerelease)."
},
"gha_environment": {
"type": "string",
"description": "Maps this environment to a GitHub Environment (deployment records, required reviewers, wait timers, env-scoped secrets)."
Expand Down
7 changes: 4 additions & 3 deletions docs/src/content/docs/guides/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ and overridden per component only where it differs.
When a `components:` block is present, the top-level config becomes the set of
**shared defaults** every component inherits. Each entry under `components:`
overrides those defaults where it sets a value and inherits them everywhere else.
Overrides are a deep merge: a component that sets only part of a block, such as a
single `environment_config` entry or one `tag_grammar` field, keeps the inherited
siblings rather than dropping them. See the [override
Overrides are a deep merge: a component that sets only part of a block, such as
one `tag_grammar` field, keeps the inherited siblings rather than dropping them.
The `environments` list is the exception, whole-replacing the shared ladder
(inline per-environment settings and all) when a component narrows it. See the [override
matrix](/cascade/reference/manifest/#inheritable-overrides) for the precise
per-field rules.

Expand Down
26 changes: 21 additions & 5 deletions docs/src/content/docs/guides/environments.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This guide covers adding an environment to an existing pipeline, configuring eac

## Add an environment

`environments` is an ordered list; position, not name, carries meaning. The last environment is the release stage, the second-to-last is the prerelease stage. Add a name at the position you want, then regenerate:
`environments` is an ordered list; position defines the promotion ladder. By default the last environment is the release stage and the second-to-last is the prerelease stage. Each entry is a bare name (an environment with no extra settings) or an object carrying that environment's name, optional `role`, and inline settings. Add an entry at the position you want, then regenerate:

```yaml
environments: [dev, staging, prod]
Expand All @@ -17,15 +17,16 @@ environments: [dev, staging, prod]
cascade generate-workflow -f
```

cascade adds the new environment's `state.<env>` entry automatically the next time orchestrate or promote finalizes; you never hand-author `state:`. Appending to the end of the list shifts which environment is the release stage, since that role is always the last position, so reorder deliberately rather than just appending if you want to keep an existing environment as production.
cascade adds the new environment's `state.<env>` entry automatically the next time orchestrate or promote finalizes; you never hand-author `state:`. Appending to the end of the list shifts which environment is the release stage, since that role defaults to the last position, so reorder deliberately rather than just appending if you want to keep an existing environment as production. To pin the release stage regardless of order, set `role: release` on that entry (see [Roles](#pin-a-role-explicitly)).

## Per-environment config

`environment_config.<env>` carries settings for one environment, keyed by its cascade name. All fields are optional and additive.
Per-environment settings live inline on an environment's object entry, replacing the bare string. All fields are optional and additive; a bare-string entry carries none of them.

```yaml
environment_config:
prod:
environments:
- dev
- name: prod
gha_environment: production
required_reviewers: ["octocat", "team/ops"]
wait_timer: 10
Expand Down Expand Up @@ -53,6 +54,21 @@ A few more fields round out the block, mostly for the `custom` branch policy or

GitHub Environment support is shipped: `gha_environment` drives native GitHub deployments and `environment_url`, and the fields above feed the `environments` command below. It lands in generated output today, not a "modeled but not emitted" state.

## Pin a role explicitly

By default the release and prerelease stages are positional: the last environment is the release stage, the second-to-last is prerelease. Set `role: release` or `role: prerelease` on an entry to declare that stage explicitly, so reordering the list no longer silently changes which environment publishes.

```yaml
environments:
- name: dev
- name: prod
role: release # prod publishes even if it is not last
- name: canary
role: prerelease
```

`role` is optional; when omitted the positional default applies unchanged. At most one entry may declare `role: release` and at most one `role: prerelease`.

## Apply GitHub Environment settings with the `environments` command

`cascade environments` reads your manifest and emits a per-environment configuration file for an operator to apply. cascade never calls the GitHub API itself:
Expand Down
4 changes: 2 additions & 2 deletions docs/src/content/docs/internals/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,9 @@ See [Security](/cascade/security/) for the full trust model, action-pinning poli
- **Custom release**: override with `release.tag` to hand releases to an external tool.
- **Custom inputs**: pass arbitrary values into a callback via `inputs` and `env_inputs`.
- **Output chaining**: a callback's outputs are auto-discovered and passed to whatever depends on it.
- **GitHub Environments**: `environment_config` lets a manifest express required reviewers, wait timers, and branch policy per environment; `cascade environments` emits that as a file for an operator to apply. Cascade never calls the Environments REST API itself, so applying the config stays a deliberate operator step. See [the manifest reference](/cascade/reference/manifest/) for the field shape.
- **GitHub Environments**: the inline settings on an `environments` entry let a manifest express required reviewers, wait timers, and branch policy per environment; `cascade environments` emits that as a file for an operator to apply. Cascade never calls the Environments REST API itself, so applying the config stays a deliberate operator step. See [the manifest reference](/cascade/reference/manifest/) for the field shape.

New fields under `environment_config` and similar blocks are additive by design: a manifest that omits them is valid and behaves exactly as it does today, so this extension point can grow without a schema version bump.
New inline fields on the `environments` entries and similar blocks are additive by design: a manifest that omits them is valid and behaves exactly as it does today, so this extension point can grow without a schema version bump.

## Wayfinding

Expand Down
11 changes: 6 additions & 5 deletions docs/src/content/docs/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -1068,14 +1068,15 @@ cascade environments | jq -c '.environments[] | {gha_environment, environment}'
done
```

The per-environment settings come from the manifest under
`config.environment_config.<env>`:
The per-environment settings come from the inline fields on each
`config.environments` entry:

```yaml
config:
environments: [dev, test, prod]
environment_config:
prod:
environments:
- dev
- test
- name: prod
gha_environment: production
required_reviewers: [team/ops]
wait_timer: 10
Expand Down
Loading