Versioning¶
How the workflows are versioned, which ref to pin, what counts as breaking and how a release is cut.
Many repositories call these reusable workflows. When all of them used @main, one bad commit here broke every
one of them at once. Versioning exists so that does not happen again.
Scheme¶
- Release tags are immutable semver tags:
v1.0.0,v1.1.0,v1.1.1, and so on. - The moving major tag (
v1) always points at the newestv1.x.yrelease. - Callers pin the major tag:
They receive fixes and new optional inputs automatically, never a breaking
change. A caller that needs to be fully reproducible can pin an exact tag
(@v1.2.0) or a commit SHA.
- @main is the development line. Its first users are the self-tests in this
repository.
What is breaking¶
Anything that can make an existing, correct caller fail:
| Change | Why it breaks |
|---|---|
| A reusable workflow removed or renamed | uses: no longer resolves |
| An input removed | Callers that pass it get startup_failure |
| An input's type changed | Callers that pass the old type get startup_failure |
| An input or secret made required, or a new required one added | Callers that do not pass it get startup_failure |
| An output removed | Callers that read it get empty values |
| A job needs a permission it did not need before | Callers that grant the old set get startup_failure |
A breaking change needs a major bump (v1 → v2). It is listed under
### Breaking in the Unreleased section of the changelog.
On pull requests, the self-CI (.github/scripts/check_contract.py) compares
each ru-*.yml with the base branch. It fails if it finds one of these
changes and that heading is missing.
Everything else is a minor release (new workflow, new optional input, new output) or a patch release (bug fix, action bump, documentation).
Deprecating instead of removing¶
To retire an input within a major:
- Keep declaring it, so callers that pass it keep starting.
- Prefix its description with
Deprecated:and say what replaces it. - Ignore it, or map it onto the replacement. When it is set, emit a
::warning::that names the replacement. - List it under
### Deprecatedin the changelog. - Remove it in the next major, and list the removal under
### Breaking.
Cutting a release (maintainers)¶
Releases of this repository are cut by hand: a merge to main does not tag anything, so @v1 callers get a fix
when a maintainer tags it. (hf-general-ci-tools releases a patch automatically on every push to main; this
repository's release.yml runs on tags only.)
- Move the Unreleased entries in
CHANGELOG.mdunder a new## [X.Y.Z] - YYYY-MM-DDheading, and merge that tomain. - Tag the merge commit and push the tag:
release.ymlthen creates the GitHub Release with generated notes. If the tag is the highestv1.*.*release, it also force-updatesv1to the same commit. A pre-release tag (v1.1.0-rc.1) gets a pre-release and leavesv1alone. A patch to an older minor does not movev1backwards.
The release workflow pushes v1 with the workflow token. If a tag ruleset
protects v*, allow GitHub Actions to update it, or move the tag by hand.
Re-runs use the old revision¶
Re-run failed jobs reruns the workflow at the revision the original run
resolved, including the revision of each reusable workflow. After a fix lands
here, or after v1 moves, start a new run instead: push a commit, use
Run workflow, or close and reopen the pull request.
Keeping callers current¶
Callers pinned to @v1 need nothing more for minor and patch releases. For
majors, and for callers that pin exact tags or SHAs, Dependabot with
package-ecosystem: github-actions proposes the update, because it also
tracks uses: references to reusable workflows.
Inside this repository¶
The workflows in this repository pin third-party actions to full commit SHAs
with a # vX.Y.Z comment. Dependabot (.github/dependabot.yml) keeps both
current.
A reusable workflow cannot refer to an action in its own repository at
the caller's ref. A uses: hardfoc/hf-espidf-ci-tools/.github/actions/...@main
inside ru-build.yml would run main's copy even for callers pinned to @v1.
ru-build.yml therefore inlines the ensure-tools-directory script, and the
self-CI checks that the two copies match.