Skip to content

Auto-trigger CD when CI passes and the gem version is bumped#171

Open
perryqh wants to merge 1 commit into
mainfrom
auto-cd-on-version-bump
Open

Auto-trigger CD when CI passes and the gem version is bumped#171
perryqh wants to merge 1 commit into
mainfrom
auto-cd-on-version-bump

Conversation

@perryqh

@perryqh perryqh commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

What & why

Today cd.yml only runs via workflow_dispatch (manual). This wires it to fire automatically after CI succeeds on main, when the version in lib/code_ownership/version.rb isn't already on RubyGems.

It follows the rubyatscale shared-config convention — a workflow_run trigger, with CD reading its secrets directly — the same pattern used by code_teams, packs-specification, rubocop-packs, etc.

We can't simply call shared-config's reusable cd.yml, because this gem builds cross-platform native binaries (the oxidize-rb matrix) rather than a pure-Ruby gem. So CD stays bespoke — but the trigger shape now matches the ecosystem.

Changes (all in cd.yml; ci.yml untouched)

  • Trigger on workflow_run (workflows: [CI], types: [completed], branches: [main]) instead of workflow_call; keep workflow_dispatch.
  • check-release gate job — reads CodeOwnership::VERSION and asks the RubyGems API whether it's published (curl -sf), proceeding only when the version is unpublished. This is our one deliberate deviation from shared-config: it avoids running the expensive cross-compile matrix on every main merge (shared-config doesn't need it because its publish action no-ops cheaply). Manual dispatch bypasses the gate to support dry-run testing / forced runs. Uses a sparse, shallow checkout (only version.rb).
  • Gate ci-data/build/release on check-release and on the triggering CI run's conclusion == 'success'.
  • dry_run input on workflow_dispatch that skips the irreversible gem push (logs "would push"), making the full pipeline testable manually without publishing. The Release step is already gated on new_version, so it skips automatically in dry-run.
  • notify_on_release — Slack "Released v" on success.

Consistency with shared-config

Aspect shared-config convention This PR
CI->CD trigger on: workflow_run same
Secrets read directly via secrets.* same (read directly; no inherit)
Version-bump gate none (publish action no-ops) check-release -- justified by binary build cost
Build internals discourse/publish-rubygems-action oxidize-rb matrix -- the binary special case

Secrets note: both workflows read secrets.RUBYGEMS_API_KEY / GITHUB_TOKEN / SLACK_WEBHOOK_URL directly. secrets: inherit only applies when one workflow calls another via uses: -- which this approach doesn't do -- so there's nothing to inherit or declare.

Testing (no real publish required)

  1. Gate, locally -- curl -sf the RubyGems API: 2.1.3 succeeds (published), 99.99.99 fails (unpublished).
  2. Full chain, dry-run -- dispatch cd.yml with dry_run: true: builds the gem matrix and runs the whole job graph without publishing.
  3. First real release -- happens on the first version-bump merge to main; idempotent (skip-if-exists), with workflow_dispatch as fallback.

Known follow-up (not in this PR)

notify_on_release fires whenever the release job succeeds, including a manual dry_run dispatch where nothing was actually published (spurious "Released" ping). Gating it on the push step's new_version would require exposing that as a job output -- left for a follow-up.

🤖 Generated with Claude Code

@perryqh perryqh requested a review from a team as a code owner June 18, 2026 16:12
@github-project-automation github-project-automation Bot moved this to Triage in Modularity Jun 18, 2026
@perryqh perryqh force-pushed the auto-cd-on-version-bump branch from 4a7d6f8 to 7934e58 Compare June 18, 2026 16:30
Previously CD only ran via workflow_dispatch. Wire it to fire
automatically after CI succeeds on main, following the rubyatscale
shared-config convention (workflow_run trigger, secrets read directly
by CD) used by code_teams, packs-specification, rubocop-packs, etc.

We can't call shared-config's reusable cd.yml because this gem builds
cross-platform native binaries (oxidize-rb matrix) rather than a pure
Ruby gem, so CD stays bespoke — but the trigger shape now matches.

cd.yml:
- Trigger on workflow_run (workflows: [CI], types: [completed],
  branches: [main]) instead of workflow_call; keep workflow_dispatch.
- Add a check-release gate job: reads CodeOwnership::VERSION and queries
  the RubyGems API, proceeding only when the version is unpublished.
  This gate is our one deviation from shared-config — it avoids running
  the expensive cross-compile matrix on every main merge (shared-config
  doesn't need it because its publish action no-ops cheaply). Manual
  dispatch bypasses the gate to support dry-run testing / forced runs.
- Gate ci-data/build/release on check-release and on the triggering CI
  run's conclusion == 'success'.
- Add a dry_run input to workflow_dispatch that skips the irreversible
  gem push (logs "would push"), making the full pipeline testable
  manually without publishing. The Release step is already gated on
  new_version, so it skips automatically in dry-run.
- Add a notify_on_release Slack notification on successful release.

ci.yml is left untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@perryqh perryqh force-pushed the auto-cd-on-version-bump branch from 7934e58 to a94c2dd Compare June 18, 2026 17:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Triage

Development

Successfully merging this pull request may close these issues.

1 participant