Releasing cafaye
Releasing cafaye
Section titled “Releasing cafaye”A tag is the release. Pushing vX.Y.Z runs .github/workflows/release.yml,
which gates, builds the gem, creates the GitHub Release, and pushes to
rubygems.org when it can. There is no other release path.
The shape is the fleet uniform — cafaye-ts and cafaye-py follow the same
file. What is written here is what this repository actually built.
Cutting a release
Section titled “Cutting a release”-
Move the
Unreleasedsection ofCHANGELOG.mdtoX.Y.Zand date it, built from the repo’s actual history and never invented. Leave an empty## [Unreleased]at the top for the permanent discipline. -
Set
Cafaye::VERSIONinlib/cafaye/version.rb. It is the single version source:cafaye.gemspecrequire_relatives it, so the manifest, the built gem and the changelog header all move with this one constant. There is no second file to keep in step. -
Commit, merge, then cut and push the tag:
git tag -a vX.Y.Z -m "cafaye X.Y.Z"git push origin vX.Y.ZThe tag and the version constant must agree — the workflow checks
v0.1.0againstCafaye::VERSIONand stops the release if they differ. Never create the tag before the bump commit is merged; never move a tag after pushing it.
0.1.0 is already set and is the intended first release, so the first run needs
no bump commit — only the tag.
What the workflow does
Section titled “What the workflow does”- Checks out this repository at full depth, plus
cafaye/core. - Installs Ruby 4.0.1 — the pin in
mise.tomland.ruby-version— never a floating version. Compiles thepgextension against that interpreter. - Points
CORE_PATHat thecorecheckout before gating, becausetest/contract/core_specs_test.rbreads core’s own event-envelope schema rather than a copy. Without core the gate is red, and a release must not ship one. - Runs
./bin/prime:bundle install,rake db:prepareagainst a real PostgreSQL service,rubocop,bundler-audit, and the full minitest suite. A release that skips the gate is not a release. - Runs
gem build cafaye.gemspec. The artifact iscafaye-X.Y.Z.gem. - Reads the release notes out of
CHANGELOG.md— the## [X.Y.Z]section, nothing else. The notes ARE the changelog section, not a generated commit dump. A missing section stops the release. - Creates the GitHub Release titled
vX.Y.Zwith the.gemattached, using the runner’sghand the job’scontents: writepermission. - Pushes to rubygems.org only when the credential exists (below).
Publishing: the one credential
Section titled “Publishing: the one credential”The account currently has no rubygems credential configured, so releases
ship as GitHub Releases with the .gem attached, and the publish step logs that
it skipped. That is the designed behaviour, not a failure.
To enable publishing, add a rubygems.org API key with push scope for the
cafaye gem as the repository secret RUBYGEMS_API_KEY (repo Settings →
Secrets and variables → Actions). Nothing else changes: the next tag run pushes
with no workflow edit.
The push form is gem push "$GEM_FILE" reading the key from the
GEM_HOST_API_KEY environment variable the step sets from that secret. That is
deliberate: it keeps the credential in the environment rather than writing it to
~/.gem/credentials, which is what --key would require.
One thing to know when the key is created: cafaye.gemspec sets
rubygems_mfa_required, so the rubygems.org account must have MFA enabled, and
the API key must be created with the push_rubygem scope under an account that
allows API pushes. If the account is set to require an OTP for every API push,
gem push will need --otp and the workflow will need the code passed in —
set the account to allow a scoped push key instead, which is the arrangement
this step assumes.
A second secret is needed only if cafaye/core is private: a fine-grained
read-only token (Contents: read, limited to cafaye/core) stored as
SIBLING_REPOS_READ_TOKEN, so the core checkout above can be read. If
core is public, the run’s default token suffices and this secret can stay
unset.
Semver here
Section titled “Semver here”Pre-1.0: 0.x.y releases may break the API on a minor bump, and every break is
listed in the changelog with the commit that caused it. 0.1.0 (2026-10-15) is
the first release; lib/cafaye/version.rb read 0.1.0 from the start and no tag
had ever been cut.