Skip to content

Publishes to Hex from a workflow on tag push - #42

Merged
johnnyt merged 1 commit into
mainfrom
sd-t8y-release-workflow-on-tag
Oct 5, 2026
Merged

johnnyt merged 1 commit into
mainfrom
sd-t8y-release-workflow-on-tag

Conversation

@johnnyt

@johnnyt johnnyt commented Oct 5, 2026

Copy link
Copy Markdown
Member

What this does

Adds a GitHub Actions workflow, .github/workflows/release.yml, that publishes this package to Hex when a version tag is pushed, and only when three things hold at the tagged commit: it is on the default branch, the tag names the @version that mix.exs states there, and the full quality gate is green there. The move to publishing on the tag push was ruled by the operator, 2026-10-04.

  • Trigger: push of tags matching v*.*.*, nothing else (no branch push, no pull request, no workflow_dispatch). permissions: contents: read. One job, concurrency keyed by the tag, cancel-in-progress: false.
  • Checks, before any toolchain is installed: full-history checkout; the default branch fetched under the name the push event gives (github.event.repository.default_branch, passed through env:, never a literal); git merge-base --is-ancestor of the tagged commit against it; the tag without its v against @version in mix.exs; and a check that stops the run when hex.pm already shows the version (reported, never published again; this also answers a re-run of a run that did publish).
  • Gate: the toolchain, cache, dependency and gate steps are copied from ci.yml (byte-identical to its block from the toolchain comment to the gate step's last line), so the gate is gate.full from .claude/wurk.json, today mix quality, run exactly as CI runs it. A red gate publishes nothing.
  • Publish: mix hex.publish --yes with HEX_API_KEY: ${{ secrets.HEX_API_KEY }} in that one step's env: and nowhere else; the docs publish with the package (Hex's default). The last step prints the hex.pm and HexDocs addresses of the published version.

CLAUDE.md (the release-prep row's publish clause, the relay paragraph's last clause, and the publish sentence of the "Release preps" paragraph, in the same edit) and the closing paragraph of .claude/wurk/release.md now say, in the maintainers' words: an agent or a session never runs mix hex.publish; the release workflow publishes on the tag push the release-prep row already allows; a failed workflow is re-run from its Actions page, never worked round by a local publish.

ADR-0003 records the decision at proposed, with its index row in docs/adr/README.md.

No file under lib/ changes, no package behaviour changes, no version bump, no tag. No changelog fragment: changelog.d/README.md excludes "documentation, ADRs, or plans" and "quality gate, CI, or agent tooling changes".

Provenance

  • Run the gate itself, read the default branch from the push event, read the version from mix.exs at the tagged commit, copy the toolchain from ci.yml rather than share it, no manual trigger: decided by the conductor under a standing consent, 2026-10-03.
  • Docs publish with the package; no automatic retry, one hand re-run of a publish step that failed on a registry or network error; the check that reports a version Hex already shows: decided by the conductor under a standing consent, 2026-10-04.
  • Rewording the authority row and the release-recipe sentence: ruled by the operator, 2026-10-04.
  • The ADR states the Hex rule as Hex documents it: an existing package's version can be replaced or reverted only within one hour of publication, then only retired. The brief's shorthand ("replaceable within one hour, then only revertable") is corrected to that.
  • docs/adr/README.md asks new records for the typespecs and worked-example sections this family's records carry; this record decides no data shape and has neither, keeping the three sections (Context, Decision, Consequences).

Checks

  • Gate: full mix quality green on this exact tree (format, compile with warnings as errors, credo, dependencies, 137 of 137 tests at 99.1% coverage, Docs with the new ADR as an ExDoc extra, doc links, dialyzer; doctor, gettext and sobelow skipped as not installed). The repo's carve-out for changes touching no Elixir code was not taken: the Docs stage builds docs/adr/0*.md.
  • Workflow: actionlint was not run (not installed on the machine this was written on). The file was checked against GitHub's workflow-syntax reference, parses as YAML, and every run: script passes bash -n. The four check steps were run under bash, outside any runner, in a scratch clone at v0.5.0: fetch and ancestry passed, the version check passed, the Hex check stopped with "already on Hex"; a mismatched tag name stopped the version check; an extra commit off main stopped the ancestry check. No step from the toolchain on, and no publish, has executed.
  • Firewall: the terminology scan over the tree and the outbound diff is clean, with a constructed positive control that fired; the planning-id scan over the diff and over this body is clean.

Direction check of the record

Every claim in ADR-0003 was verified against the branch: the trigger, permissions and concurrency lines; the three condition steps and the Hex check by step name; the gate step reading gate.full from .claude/wurk.json; the publish step as the only reader of HEX_API_KEY; the printed addresses; the authority-row and release-recipe wording in CLAUDE.md and .claude/wurk/release.md; and the Docs stage building the record (mix.exs docs extras). The record cites the workflow by step name, since that file exists only on this branch until merge. git diff origin/main -- docs/adr/ shows zero removed lines (one record added, one index row added).

Adds .github/workflows/release.yml: on the push of a v*.*.* tag, and
on nothing else, it checks that the tagged commit is on the default
branch read from the push event, that the tag names the @Version in
mix.exs there, and that Hex does not already show that version; then
it runs the full gate on the toolchain ci.yml provisions (the steps
copied from ci.yml) and publishes with mix hex.publish --yes, the
HEX_API_KEY secret read by that one step only. A red gate or a failed
check publishes nothing.

CLAUDE.md's release-prep row, relay paragraph and Release preps
paragraph, and .claude/wurk/release.md, now say an agent or a session
never runs the publish: the workflow publishes on the tag push, and a
failed workflow is re-run from its Actions page. Ruled by the
operator, 2026-10-04. ADR-0003 records the decision at proposed.

No lib/ change, no version bump, no changelog fragment
(changelog.d/README.md excludes CI and ADR changes). The full gate
ran green on this exact tree.

Refs: sd-t8y
@johnnyt
johnnyt merged commit 5597696 into main Oct 5, 2026
1 check passed
@johnnyt
johnnyt deleted the sd-t8y-release-workflow-on-tag branch October 5, 2026 00:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant