Skip to content
Open
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
95 changes: 55 additions & 40 deletions src/docs/Capabilities/release-management/design.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
title: Design
description: How release management is built — effective defaults, owned overrides, source-bound notes, and build-once publication.
description: How release management is built — effective defaults, owned overrides, keyed release types, source-bound notes, and build-once publication.
---

# Release Management — Design

The behavior in the [spec](spec.md) is delivered by shared release mechanics,
through a reusable workflow or a native producer pipeline. A repository's
effective release pipeline establishes which target routes are managed. The
optional `.github/release.config.yml` file refines those settings; it does not
optional `.github/release.settings.yml` file refines those settings; it does not
create a release pipeline, and its absence does not opt a managed route out.
Documented defaults make a managed route usable without per-PR bump labels;
repository settings, supported caller inputs, and owned labels provide overrides.
Expand All @@ -21,7 +21,7 @@ immutable output that another system consumes by version.

- When a shared workflow or native producer pipeline delivers that release
behavior, evaluate its release decision and require the pre-merge check. This
remains true when `.github/release.config.yml` is absent or the route does not
remains true when `.github/release.settings.yml` is absent or the route does not
call a named shared workflow.
- When the route has no versioned release behavior, Release Management does not
apply. Omit the `Release decisions` block and every `release:*` label,
Expand All @@ -40,29 +40,41 @@ a successful skip.

## Branching model

A **release branch** is any branch configured as a release target, each with a
**release type** — `stable` or `prerelease`.

- **Single branch (zero-config).** One release branch (the default branch)
produces stable releases. Prereleases are opt-in via a PR label.
- **Multi-branch.** `dev` (prerelease) collects PRs and publishes a prerelease
on every merge; `main` (stable) receives `dev`. Merging `dev → main` computes
the stable version from the **latest stable release** plus the merge PR's
resolved bump — the prerelease counter does not carry over.
- **One production authority.** At most one branch is `release-type: stable`;
every other release branch is `prerelease`. The single stable branch
(typically `main`) owns the production version — a prerelease branch can never
cut a stable release.
A **release branch** is a branch assigned to one key in the `ReleaseType`
configuration object. The fixed keys are `Stable`, `Prerelease`, and
`ReleaseCandidate`; each key owns the properties for that release type,
including its `Branch`.

- **Single branch (zero-config).** `ReleaseType.Stable.Branch` always resolves:
when `ReleaseType` or its `Stable` key is omitted, it uses the default branch.
`Prerelease` and `ReleaseCandidate` are optional. Prereleases remain available
from an open pull request through the mode label.
- **Multi-branch.** A full promotion path uses
`ReleaseType.Prerelease.Branch` for early testing,
`ReleaseType.ReleaseCandidate.Branch` for the promotable candidate, and
`ReleaseType.Stable.Branch` for production. Each configured branch publishes
only its keyed release type. Promotion to `ReleaseType.Stable.Branch` computes
from the latest stable release plus the merge pull request's resolved bump;
prerelease and release-candidate counters do not carry over.
- **One branch per type.** Each release-type key has at most one `Branch`, and
the same branch MUST NOT appear under more than one key. Unknown keys and
duplicate branch assignments are rejected.
- **One production authority.** `Stable.Branch` is the only branch that cuts a
stable release. A prerelease or release-candidate branch can never publish the
production version.
- **Bundled releases.** A **staging branch** collects feature PRs; merging it to
a release branch produces **exactly one** release for all bundled changes.

```yaml
# .github/release.config.yml
release-branches:
- branch: main
release-type: stable
- branch: dev
release-type: prerelease
# .github/release.settings.yml
DefaultBump: patch
ReleaseType:
Stable:
Branch: main
Prerelease:
Branch: dev
ReleaseCandidate:
Branch: rc
```

## The pipeline
Expand Down Expand Up @@ -107,7 +119,7 @@ that supplied each decision before Build.

Follow [Smart defaults, local overrides](../../Ways-of-Working/Principles/Software-Design.md#smart-defaults-local-overrides):
shared defaults are overridden by repository settings in the optional
`.github/release.config.yml`, then by explicitly supplied supported caller
`.github/release.settings.yml`, then by explicitly supplied supported caller
inputs for that invocation. Omitted caller inputs preserve repository settings;
they do not overwrite them with an input's default. The implementing workflow
or action documents its exact supported caller surface and validates it through
Expand All @@ -121,13 +133,13 @@ even when a narrower override or bump label exists.

| Setting | Shared default | Repository override | Supported caller override |
| --- | --- | --- | --- |
| `DefaultBump` | `patch` | `DefaultBump` in `.github/release.config.yml` | Explicitly supplied caller override supported and documented by the invoked producer for this setting. |
| `DefaultBump` | `patch` | `DefaultBump` in `.github/release.settings.yml` | Explicitly supplied caller override supported and documented by the invoked producer for this setting. |

For example, a repository can select minor as its normal level without requiring
a minor label on every publishing PR:

```yaml
# .github/release.config.yml
# .github/release.settings.yml
DefaultBump: minor
```

Expand Down Expand Up @@ -240,23 +252,26 @@ happen. Retrying failed validation or publication is not an ad hoc release
either: rerun the existing release with the same artifact and version under the
[recovery rule](#the-pipeline).

## Prereleases

- **Branch-level** — a prerelease-type branch publishes on every push, using the
branch name as the identifier: `v1.3.0-dev.1`, `v1.3.0-dev.2`, …
- **PR-level** — `release:prerelease` with a resolved explicit or default bump publishes
`v<base>-<identifier>.<counter>`: `base` is the next version from that bump,
`identifier` is the normalized branch name, and `counter`
auto-increments per push.
## Prereleases and release candidates

- **Prerelease branch** — `ReleaseType.Prerelease.Branch` publishes on every
push, using the branch name as the identifier: `v1.3.0-dev.1`,
`v1.3.0-dev.2`, …
- **Release-candidate branch** — `ReleaseType.ReleaseCandidate.Branch` publishes
`v1.3.0-rc.1`, `v1.3.0-rc.2`, … and never promotes one to latest.
- **PR-level** — `release:prerelease` on an open PR publishes
`v<base>-<identifier>.<counter>`: `base` is the next version from one explicit
owned bump label when present, otherwise from the resolved `DefaultBump`;
`identifier` is the normalized branch name, and `counter` auto-increments per
push.
- Artifact-specific conventions replace the SemVer suffix where they exist
(`-alpha.N` for npm, `.devN` for Python). Release candidates use `-rc.N`,
auto-incrementing.
(`-alpha.N` for npm, `.devN` for Python).
- **Cleanup** deletes prerelease tags, releases, and artifacts after the PR
closes (configurable); stable releases are never touched.

## Path filtering

When present, `.github/release.config.yml` declares `release-paths` as ordered
When present, `.github/release.settings.yml` declares `release-paths` as ordered
include/exclude globs (excludes win). On an invoked route, the workflow
**always runs** so validation executes on every merge; only the release step is
skipped when no artifact-affecting path changed.
Expand Down Expand Up @@ -486,20 +501,20 @@ Serialisation is provided once by the reusable workflow so every repository
inherits it; the mechanism is the
[GitHub Actions standard](../../Coding-Standards/GitHub-Actions.md#concurrency).
The single-stable-branch rule above is what keeps the production version under
one authority — the stable branch is the only ref that ever cuts a production
release, and its runs are serialised like any other.
one authority — `ReleaseType.Stable.Branch` is the only ref that ever cuts a
production release, and its runs are serialised like any other.

## Configuration surface

| Surface | Where |
| --- | --- |
| Release Management applicability | effective target-route pipeline, including shared workflows and native producers |
| Release branches + type | optional `.github/release.config.yml`; the default branch is stable when omitted |
| Release types + branch mapping | `ReleaseType` in `.github/release.settings.yml` |
| Default bump and overrides | documented shared `DefaultBump: patch`, repository settings, then supported caller inputs |
| Explicit bump / prerelease / skip | `release:` PR label on an invoked route |
| Pre-merge decision validation | named PR check required by the branch ruleset or protection |
| Optional ad hoc release | `workflow_dispatch` inputs |
| Path filter | `.github/release.config.yml` |
| Path filter | `.github/release.settings.yml` |
| Prerelease cleanup toggle | release config / workflow input |
| Publishing targets | reusable-workflow input + GitHub environment; see [Publishing Targets](design-publishing-targets.md) |

Expand Down
10 changes: 5 additions & 5 deletions src/docs/Capabilities/release-management/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ description: How a source change becomes a versioned, immutable artifact, driven

Turning a merged change into a versioned, immutable artifact — a container
image, a GitHub Action or reusable workflow, a language package, a Terraform
module — paired with a GitHub Release and a git tag, normally driven by
pull-request labels. An implementation may add a GitHub-native ad hoc release
path when its product needs one. No release CLI, no hand-edited version file,
no tagging ritual.
module — paired with a GitHub Release and a git tag, driven by a configured
default and pull-request label overrides. An implementation may add a
GitHub-native ad hoc release path when its product needs one. No release CLI,
no hand-edited version file, no tagging ritual.

<!-- INDEX:START -->

| Page | Description |
| --- | --- |
| [Spec](spec.md) | Requirements for release management — validated defaults, reviewed overrides, immutable artifacts, and complete consumer release records. |
| [Design](design.md) | How release management is built — effective defaults, owned overrides, source-bound notes, and build-once publication. |
| [Design](design.md) | How release management is built — effective defaults, owned overrides, keyed release types, source-bound notes, and build-once publication. |
| [Publishing Targets](design-publishing-targets.md) | The contract every publishing destination documents, with GitHub Releases as the reference target. |

<!-- INDEX:END -->
Loading
Loading