IMPORTANT: Developer documentation for the current development branch. This content is unreleased, may change without notice, and must not be treated as Buildish release documentation.
Direct Release
Direct Release
The direct lifecycle turns one exact source revision into the final tag and final GitHub Release in one manually dispatched workflow. It does not create a candidate, require a vote, or introduce a candidate-shaped placeholder in final release state.
“One click” means one workflow dispatch. The workflow still separates resolution, source checks, tag creation, staging, verification, publication, and manifest attachment so a component can place policy boundaries between those jobs.
Minimal configuration
1component:
2 id: example
3 display_name: Example
4versioning:
5 scheme: semver
6 final_tag_template: "v{version}"
7source:
8 selection: explicit-ref-or-default-branch
9 default_branch: main
10 require_default_branch_ancestor: true
11 snapshot:
12 mode: platform-generated
13 checks:
14 platform: github
15 trusted_workflow_path: .github/workflows/ci.yml
16 trusted_event: push
17 trusted_branch: main
18 required:
19 - Required Checks
20lifecycle:
21 mode: direct
22# Optional. Omit this block to publish without custom notes.
23release_notes:
24 path_template: release-notes/{version}.md
25artifacts:
26 produced: []
27 checksums: []
28publication:
29 authoritative:
30 kind: github-release
31 repository: example/example
32tags:
33 final_mode: exact-source-commit
34 moving: []
35policy_profiles: {}
This example treats GitHub as authoritative and relies on the source archives GitHub generates from
the immutable final tag. It publishes no separately built source artifact. Because release_notes
is configured, the selected source commit must contain a non-empty UTF-8 Markdown fragment at the
rendered path. If the block is omitted, the release body contains only generated identity and asset
information.
Dispatch
The repository’s generic reference workflow lives at
buildish-release-tooling/harness/workflows/release-direct.yml. A component can copy that fixture
into its own .github/workflows/release-direct.yml and dispatch it with:
version: the exact final version, for example1.2.3;source_ref: an optional exact branch, tag, or commit allowed by the configured source-selection policy.
When source_ref is omitted, the example configuration resolves main. Resolution records the
exact commit; later jobs use that commit identity rather than re-resolving a moving branch.
With the ancestry policy above, an explicitly supplied commit must also already be reachable from
main. The trusted-workflow fields prevent a same-name check from another workflow or event from
satisfying the source gate.
Workflow phases
resolvecreatesDirectReleaseStatewith the release identity, exact source commit, final tag, artifact policy, and any configured release notes read from that commit.verify-sourcechecks the configured GitHub check-run/status requirement on that exact commit.create-final-tagcreates or revalidates the immutable final tag.stagecreates or completes the draft final GitHub Release.verify-finalcompares the observed tag, release metadata, and assets with the resolved state.publishmakes the exact release public or confirms that an identical publication already exists.manifestcreatesrelease-manifest-v1.json, validates both workflow handoff digests, attaches the manifest without clobbering an existing asset, and revalidates the release.
Same-run JSON files move through GitHub workflow artifacts. Every privilege-bearing consumer checks the SHA-256 emitted by the producing job before acting.
Reruns and conflicts
The mutation commands are convergent for identical state:
- an identical tag, draft release, public release, or manifest attachment reports an
already-completeoutcome where applicable; - an existing tag at another commit, mismatched release body, unexpected asset, size mismatch, or digest mismatch fails closed;
- asset upload never uses clobber behavior.
The workflow uses non-canceling concurrency keyed by repository and version. A second run waits instead of cancelling a run that may already have changed external release state.
Variations
- Use a separately built and signed source artifact when the hosting-platform snapshot is not sufficient.
- Add
environment:to the jobs selected by project policy; see Workflow composition. - Create a release branch separately with
create-release-branchwhen a component needs maintained release lines. The direct lifecycle itself does not require one. - Use the candidate lifecycle when publication must wait for an external approval or vote over an exact candidate.
The repository’s release-testpypi.yml is another direct-lifecycle composition. It resolves and
retains DirectReleaseState, but deliberately exercises only the secondary TestPyPI publication:
it creates no final tag or GitHub Release. It is a package-publication rehearsal, not a substitute
for the generic direct GitHub workflow’s final-tag and final-manifest phases.