Skip to content

ci: check nix pins and repin the gemset after release - #2

Merged
ajmarkow merged 2 commits into
masterfrom
ci/nix-pins-and-overlay
Sep 15, 2026
Merged

ajmarkow merged 2 commits into
masterfrom
ci/nix-pins-and-overlay

Conversation

@ajmarkow

Copy link
Copy Markdown
Owner

Makes the flake easier to consume, and stops it silently serving a stale gem.

Overlay

The flake only exposed packages.<system>.default, so a consumer had to thread system through a module to reach it. overlays.default lets them apply the overlay once and then write a bare snippet_cli in environment.systemPackages or home.packages.

Maintainer metadata

meta.maintainers was empty. Filled in as an inline attrset rather than lib.maintainers.ajmarkow, because that attribute does not exist until an entry lands in nixpkgs' maintainer-list.nix — a separate PR. Comment notes to swap it if the package is ever upstreamed.

The pre-commit nixfmt hook also reformatted nix/default.nix (function args expanded, aligned = padding dropped). That churn is the hook's, not hand-made.

The gemset problem

nix/gemset.nix pins the published gem, so it lags lib/snippet_cli/version.rb until bundix reruns. While it lags, nix run github:ajmarkow/snippet_cli silently installs the previous release. Nothing caught that before.

gemset-check

Compares nix/gemset.nix and nix/Gemfile.lock to version.rb on every push and PR. Plain Ruby, no Nix, so it is fast.

A version RubyGems has not indexed yet is a release in flight rather than drift, so that case passes with a ::notice. Keying off RubyGems instead of a commit marker keeps this correct on pull_request events, where github.event.head_commit is null and a marker-based skip would never fire.

Verified against live RubyGems in all three states:

State Result
Pins in sync exit 0, silent
version.rb ahead, unpublished exit 0 + ::notice "release in flight"
Pins behind a published version exit 1 + ::error on both files

update-gemset

Runs after publish. Waits for RubyGems to index the new version, regenerates with bundix, then opens a PR on chore/repin-gemset-v<version> and enables auto-merge.

Two details worth knowing:

  • bundle lock --update is scoped to --update snippet_cli. Unscoped, it bumped an unrelated transitive gem (bigdecimal 4.1.1 → 4.1.3) during testing.
  • nix fmt nix/gemset.nix runs afterwards. bundix emits compact lists (["default"]) while the checked-in file is nixfmt style ([ "default" ]); without this the job would commit unformatted output and churn the file every release.

With both fixes a full regeneration produces zero drift.

It opens a PR rather than pushing, because the master ruleset requires a pull request and has no bypass actors.

Before merging

  • Add a GEMSET_BOT_TOKEN secret — a fine-grained PAT scoped to this repo with Contents: read/write and Pull requests: read/write. GITHUB_TOKEN will not work: GitHub does not start check runs for PRs it opens, so the required contexts would never report and auto-merge would wait forever.

Merging without it is safe. gemset-check works standalone, and update-gemset only runs after publish, so the repin half simply stays inert.

Optional follow-ups

  • Add nix pins match version.rb to the ruleset's required contexts. Until then gemset-check reports but cannot block a merge.
  • delete_branch_on_merge is off, so chore/repin-gemset-v* branches will accumulate.

Release flow reminder

publish reads github.event.head_commit.message. Under the PR-only ruleset that is the squash commit, whose message comes from the PR title — so gem-release-ready must be in the release PR title.

🤖 Generated with Claude Code

ajmarkow and others added 2 commits September 15, 2026 11:42
The flake only exposed packages.<system>.default, so consumers had to thread `system` through a module to reach it. An overlay lets them refer to snippet_cli by bare name instead.

maintainers is inline rather than lib.maintainers.ajmarkow, which does not exist until an entry lands in nixpkgs' maintainer-list.nix.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
nix/gemset.nix pins the published gem, so it lags version.rb until bundix reruns. While it lags, installing from the flake silently gets the previous release.

gemset-check compares the pins to version.rb and fails when they drift. A version RubyGems has not indexed yet is a release in flight rather than drift, so that case passes. Keying off RubyGems rather than a commit marker keeps this correct on pull_request events, where github.event.head_commit is null.

update-gemset runs after publish, waits for indexing, regenerates with bundix, and opens a PR. The master ruleset requires a pull request and has no bypass actors, so it cannot push to master itself. GEMSET_BOT_TOKEN must be a PAT: GitHub does not start check runs for pull requests opened with GITHUB_TOKEN, so the required contexts would never report.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ajmarkow
ajmarkow merged commit 7d71a76 into master Sep 15, 2026
27 checks passed
ajmarkow added a commit that referenced this pull request Sep 15, 2026
The overlay landed in flake.nix (#2) but the README's system-config section never mentioned it, so it still only showed inputs.snippet_cli.packages.${pkgs.system}.default -- the exact thing the overlay exists to replace.

Verified pkgs.snippet_cli resolves once the overlay is applied.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ajmarkow added a commit that referenced this pull request Sep 15, 2026
* chore(release): 0.6.0

Minor rather than patch because this narrows supported Ruby to 3.2 and newer. Semver exempts 0.x from its rules, but the 0.x convention puts compatibility changes in MINOR, and anyone pinned at `~> 0.5.3` should opt in rather than receive it silently.

RubyGems enforces required_ruby_version when resolving, so Ruby 3.1 users are held on 0.5.3 with a working install rather than broken.

Adds CHANGELOG.md, covering 0.6.0 back to 0.5.0. The gemspec already advertised a changelog_uri pointing at a file that did not exist.

nix/gemset.nix and nix/Gemfile.lock stay on 0.5.3 deliberately. They pin the published gem; update-gemset repins them after publish. The nix/Gemfile constraint `~> 0.5` still covers 0.6.0, so it needs no change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs: correct the semver guidance in the release runbook

The runbook claimed that raising required_ruby_version stops users on the dropped Ruby from installing at all. That overstates it. RubyGems enforces required_ruby_version while resolving, so those users stay on the last version that supported them and keep a working install. What they lose is future updates, silently.

Also notes that semver exempts 0.x, so the minor-bump rule is convention here rather than a requirement, and explains what the bump actually buys: visibility, and a clean opt-in for anyone pinned at a patch-level constraint.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(readme): show the overlay as the simplest system-config install

The overlay landed in flake.nix (#2) but the README's system-config section never mentioned it, so it still only showed inputs.snippet_cli.packages.${pkgs.system}.default -- the exact thing the overlay exists to replace.

Verified pkgs.snippet_cli resolves once the overlay is applied.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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