A vX.Y.Z tag releases two artifacts at one version:
| Artifact | Published to | Install |
|---|---|---|
decdn.node Ansible collection |
Ansible Galaxy | ansible-galaxy collection install decdn.node:==X.Y.Z |
decdn-node Helm chart |
oci://ghcr.io/decdn/charts, signed with cosign (keyless) |
helm install <release> oci://ghcr.io/decdn/charts/decdn-node --version X.Y.Z |
.github/workflows/release.yml does the work. Its
build job runs on every matching tag push. It gates the tag, re-runs
make galaxy-check and make lint-helm, packages both, and uploads them with a
SHA256SUMS as a workflow artifact. The publish job pushes to Galaxy and ghcr.io and
creates the GitHub Release, but only when the repository variable
PUBLISH_ENABLED is true. Until then, a tag push is a dry run. So is a manual
Run workflow (workflow_dispatch) with a tag, which is the way to rehearse.
-
Versions. Set the same
X.Y.Zinansible/galaxy/galaxy.yml(version:) andcharts/decdn-node/Chart.yaml(version:). Bump the chart'sappVersionif it now targets a newer decdn release. -
Changelogs. Both
ansible/galaxy/CHANGELOG.mdandcharts/decdn-node/CHANGELOG.mdcollect changes under## [Unreleased]. At release time, move those entries under a dated## [X.Y.Z] — YYYY-MM-DDheading and leave an empty[Unreleased]above it. First release only: both files already hold a## [0.1.0] — unreleasedsection describing the initial state; fold[Unreleased]into it and replace "unreleased" with the date. The gate rejects a missing section and one still marked "unreleased". These two sections become the GitHub Release notes. -
Check locally:
scripts/check-release-version.sh vX.Y.Z, thenmake -C ansible galaxy-checkandmake lint-helm. -
Merge that as a PR, then tag the merge commit on
mainand push the tag:git tag -s vX.Y.Z -m "vX.Y.Z" && git push origin vX.Y.Z
-
Watch the Release workflow. With publishing enabled, the
publishjob waits for approval on thereleaseenvironment.
Do these before setting PUBLISH_ENABLED:
- Galaxy namespace. The
decdnnamespace must exist on galaxy.ansible.com and the account behindGALAXY_API_KEYmust be allowed to publish to it. Add the key as the repository secretGALAXY_API_KEY. releaseenvironment. Create it under Settings → Environments with required reviewers, and putGALAXY_API_KEYthere rather than as a repository secret if you want the reviewer gate to guard it too.- GHCR visibility. The first
helm pushcreates thedecdn/charts/decdn-nodepackage as private. Make it public under the org's Packages settings, or nobody outside the org can pull it. - Enable: set the repository variable
PUBLISH_ENABLEDtotrue.
The steps run chart, then Galaxy, then the GitHub Release. The Release is last, so it only appears once both artifacts are live.
- Chart push failed: nothing is public yet. Fix the cause and re-run the job.
- Galaxy publish failed after the chart was pushed: fix the cause and re-run. The
chart push is repeatable for the same version (the tag just moves to an identical
digest), but Galaxy refuses a version that already exists. If Galaxy actually
accepted the upload before the job failed, finish by hand: create the Release with
gh release create vX.Y.Zand the files from therelease-vX.Y.Zworkflow artifact. - Never re-use a version for different content. Cut
vX.Y.Z+1.
# The chart's signature: keyless, tied to this repo's release workflow.
cosign verify ghcr.io/decdn/charts/decdn-node:X.Y.Z \
--certificate-identity-regexp '^https://github.com/decdn/devops/.github/workflows/release.yml@refs/tags/v' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
# The files attached to the GitHub Release.
sha256sum --check SHA256SUMS