Skip to content

ci: publish from the release-please workflow, not from a tag trigger - #29

Closed
tas50 wants to merge 1 commit into
mainfrom
ci/publish-from-release-please
Closed

tas50 wants to merge 1 commit into
mainfrom
ci/publish-from-release-please

Conversation

@tas50

@tas50 tas50 commented Aug 24, 2026 •

Copy link
Copy Markdown
Member

The gem has never been published. Two releases exist and publish.yml has not run once.

$ gh run list --workflow=publish.yml
(no runs)

$ gh release list
v0.3.0  Latest  2026-08-24T19:44:57Z
v0.2.0          2026-08-24T17:10:56Z

$ curl -s https://rubygems.org/api/v1/versions/docker-api-ng.json
This rubygem could not be found.

Why

release-please pushes its tag using the default GITHUB_TOKEN. GitHub deliberately does not start workflow runs from events that token creates — it is the documented guard against a workflow triggering itself forever.

publish.yml listened on:

"on":
  push:
    tags: ["v*"]

…so it could never fire for the only thing that creates those tags. Both releases show github-actions[bot] as the author, which is the tell.

The fix

The publish job moves into release-please.yml, gated on the action's release_created output rather than on an event. That sidesteps the token question entirely — no PAT, so trusted publishing stays secretless.

Two details worth calling out:

  • The checkout pins ref: to the tag release-please just created, so the gem is built from the released commit rather than from whatever main has moved to in the meantime. The old workflow got this for free from the tag trigger; gating on an output means asking for it explicitly.
  • Permissions are now per-job. release-please keeps contents: write / pull-requests: write; publish gets only contents: read plus the id-token: write that OIDC needs. The workflow default drops to contents: read.

publish.yml is deleted — it cannot fire, and leaving it would mean two workflows able to publish, which means two trusted publishers to keep configured.


⚠️ Needs a matching change on RubyGems.org

Trusted publishing identifies the workflow by filename, so the publisher must name release-please.yml — not publish.yml. Which flow to use depends on whether 0.3.0 gets pushed by hand first.

If the gem is still unpublished — use the pending publisher flow:

RubyGems.org → profile → Trusted Publishers → Create

Field Value
Gem name docker-api-ng
Repository owner test-kitchen
Repository name docker-api-ng
Workflow filename release-please.yml
Environment rubygems

It converts to a normal trusted publisher after the first successful push.

If 0.3.0 has already been pushed manually — the gem exists, so add the publisher to it instead: gem page → Trusted Publishers → Create, same fields minus the gem name.

Publishing 0.3.0 itself

This change only takes effect for the next release — 0.3.0 is already tagged, so its release_created moment has passed. Either let 0.3.1 carry the first automated publish, or push 0.3.0 by hand once:

$ gem signin          # tas50, plus MFA OTP
$ gem build docker-api-ng.gemspec
$ gem push docker-api-ng-0.3.0.gem

Pre-flight on that artifact: builds at 78,848 bytes, installs into a clean GEM_HOME, requires, and drives a request through Transport::Fake end to end. Neither this PR nor #30 touches a packaged file — .github/ and spec/ are not in spec.files — so merging them later does not change what 0.3.0 would ship.

Verification

YAML parses; job graph is release-please → publish with the gate on needs.release-please.outputs.release_created == 'true'. bundle exec rake — 360 runs, 0 failures. I cannot exercise the publish path without cutting a real release, so the trusted-publisher step above is the part to check by eye.

The gem has never reached RubyGems. v0.2.0 and v0.3.0 were both tagged and
released, and publish.yml has not run once:

    $ gh run list --workflow=publish.yml
    (no runs)
    $ curl https://rubygems.org/api/v1/versions/docker-api-ng.json
    This rubygem could not be found.

release-please pushes its tag with the default GITHUB_TOKEN, and GitHub
does not start workflow runs from events that token creates -- that is the
documented guard against recursive runs. publish.yml listened on
`push: tags: ["v*"]`, so it could never fire for the only thing that
creates those tags. Both releases show github-actions[bot] as the author,
which is the tell.

Moving the publish into the same workflow sidesteps the token: the job is
gated on the action's release_created output rather than on an event. No
PAT, so trusted publishing stays secretless.

The checkout pins ref: to the tag release-please just created, so the gem
is built from the released commit rather than from whatever main has moved
to since. Permissions are now per-job: release-please keeps contents:write
and pull-requests:write, publish gets only contents:read plus the
id-token:write that OIDC needs.

Needs a matching change on RubyGems: trusted publishing identifies the
workflow by filename, so the publisher has to name release-please.yml.

Signed-off-by: Tim Smith <tim@mondoo.com>
@damacus

damacus commented Aug 25, 2026

Copy link
Copy Markdown

Claude is half right. You can start workflows from GitHub tokens, you just need to enable it.

@damacus damacus left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is only a settings page change?

It works everywhere else without this

@tas50 tas50 closed this Aug 26, 2026
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.

2 participants