Repository navigation
feat: automate collection releases with semantic-release - #1
Merged
Merged
Conversation
Mearman
marked this pull request as ready for review
September 25, 2026 20:14
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Root-level tooling for automating collection releases: semantic-release plus the changelog, exec, git, and github plugins, and commitlint with the conventional-commits config. Not published; the package itself is private and excluded from the built collection tarball.
Replaces build-runner-image.yml, which only ever built the runner image and could not push a version-matched tag for a release. release.yml now builds and pushes the runner, heartbeat, and autoscaler images together, once per published release, each tagged with the exact version, the floating major version, and latest on the same manifest, using docker/metadata-action's semver patterns against the version semantic- release just decided. The image build stays on the fleet's own dedicated exadev-image-builder profile rather than routing through the ordinary CI fallback: it is a privileged Docker-in-Docker workload with no GitHub-hosted fallback that reliably schedules for this org (see closed issue #10), the same reasoning build-runner-image.yml already documented.
.releaserc.json drives the release from Conventional Commits: a breaking change is major, feat is minor, every other conventional type (fix, perf, refactor, docs, and so on) is patch, matching commitlint.config.js's own accepted types one for one. Its exec step runs scripts/release/stamp_version.py, which writes the new version into galaxy.yml's version field and into the arc role's two published-image tag defaults (github_runner_arc_heartbeat_image, github_runner_arc_autoscaler_image), matched by variable name rather than line number so it stays correct against concurrent edits to that file, then builds the collection tarball. The git step commits the changelog and both stamped files back to main with a skip-ci release commit; the github step attaches the tarball to the GitHub Release; the exec publish step pushes to Ansible Galaxy only when a GALAXY_API_KEY is actually configured.
galaxy.yml's build_ignore already excluded everything that isn't collection content; node_modules, the two package manifests, the semantic-release config, and the commitlint config belong in that same list, not in the tarball ansible-galaxy publishes. .gitignore gets the matching entries for node_modules and the tarball itself, plus .ansible (ansible-lint's own local collection cache, created as a side effect of running it against this checkout).
commitlint runs against every commit in a pull request (wagoid/ commitlint-github-action) and against the pull request's own title (amannn/action-semantic-pull-request) separately, since either one can carry a conventional-commit violation the other wouldn't catch; both are pull-request-only, since there's nothing to validate on an ordinary push to main. ansible-lint runs at its min profile, not the default: the default profile already flags real, pre-existing findings across roles/ (task naming casing, Jinja templates placed mid-name) that are a separate, already-owned concern for whoever next touches that role, not something this change should turn into a blocking failure for every unrelated pull request. min still catches genuine errors. The collection build check builds the tarball, installs it into a temp path, and lists what actually shipped (roles, filter plugins) - catching a build_ignore mistake that silently drops or includes the wrong content before it reaches a release. All four are added to required-checks' own needs list alongside the existing lint jobs.
…laim Adds a Releases section covering what triggers a release, what each release step does, the [skip ci] release commit's own reasoning, the version this repo will start from with no prior tags, and the exact secrets the release push and the optional Galaxy publish need. Also corrects two passages that still described build-runner-image.yml as running on GitHub-hosted ubuntu-latest and failing outright (true when written, per closed issue #10): that workflow is gone, and the image build it used to attempt now happens from release.yml on the fleet's own exadev-image-builder profile.
v6 is the action's current release; there's no existing pin to match here since this action is new to the workflow, unlike the other docker/* actions in the same job, which intentionally keep the exact versions build-runner-image.yml already ran in production.
Three comments (actionlint's own self-hosted-runner label config, and two fleet configs describing why the image-builder scale-set profile is separately labelled) still named the workflow file this change deletes. All three now point at release.yml's build-images job, which does the same job on the same profile.
The release commit and tag go over SSH with a write-enabled deploy key scoped to this repository; the GitHub API calls keep using GITHUB_TOKEN.
The Docker-based commitlint action could not pull its image on the self-hosted runners, and the PR-title action lacked permission to read the pull request, so both now run the pinned commitlint with npx. pip installed ansible-lint outside PATH, which failed the lint job with exit 127.
Comments and the README cited issue numbers and a values file from the private repository this history came from, which don't exist here. They now state the constraint itself: GitHub-hosted runners can't be relied on for this org, and image builds run on the fleet's builder profile.
ansible-lint's production profile applies yamllint's comment spacing to every YAML file, workflows included, and failed on these three.
The release job and the three multi-arch image builds move to ubuntu-latest like the rest of the repository's CI, with QEMU building the arm64 half, so a release never depends on the fleet it ships images for. actionlint no longer needs to know the builder profile's label.
Mearman
force-pushed
the
feat/semantic-release
branch
from
September 25, 2026 20:48
8c2ee74 to
daa49e4
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds semantic-release, so a push to main that warrants a release cuts a version, builds the collection tarball, and builds and pushes all three container images tagged with that version.
package.json/package-lock.json: semantic-release with the changelog, exec, git and github plugins, and commitlint with the conventional-commits config. Private, devDependencies only, and excluded from the built collection bygalaxy.yml'sbuild_ignore..releaserc.json: a breaking change is major,featis minor, and every other conventional type is a patch, so almost every push releases. The exec plugin runsscripts/release/stamp_version.py, which writes the version intogalaxy.ymland into the ARC role's heartbeat and autoscaler image defaults (matched by variable name), then builds the tarball. The git plugin commits the changelog and both stamped files aschore(release): <version> [skip ci]; the github plugin attaches the tarball to the release; Ansible Galaxy publishing runs only ifGALAXY_API_KEYis set..github/workflows/release.yml: runs semantic-release on push to main and, when a release is published, builds the runner, heartbeat and autoscaler images multi-arch on GitHub-hostedubuntu-latest(QEMU for arm64), tagged with the exact version, the floating major andlatest. It replacesbuild-runner-image.yml, which only built the runner image. The release commit and tag are pushed over SSH with a write deploy key (RELEASE_DEPLOY_KEY); the GitHub API calls use the job's own token..github/workflows/ci.yml: commitlint on every commit in a PR and on the PR title (run from the repo's own devDependencies), and a collection build check that builds the tarball, installs it and lists what shipped. Both joinrequired-checks.The deploy key and
RELEASE_DEPLOY_KEYsecret are set on this repository. No tag exists yet, so the first release will be computed from the commit history.