Rework release into a reusable workflow with one job per run kind#678
Merged
Conversation
Fold release-prepare.yml into release.yml and drive every step from a
single RUN_KIND decided up front:
RELEASE - workflow_dispatch, first attempt: bump examples, tag,
push, then publish.
RELEASE_RETRY - workflow_dispatch whose tag is already on origin: skip
bump/push and republish the tag, so a release whose
ci-release failed on an intermittent error can be re-run.
DRY_RUN - pull_request: run the full ci-release graph with an
ephemeral signing key and dummy credentials, assembling
the bundle locally (sonaBundle) instead of uploading.
SNAPSHOT - push to main: publish a snapshot.
The old two-workflow split existed only so a tag push via the GitHub App
token would trigger release.yml; publishing inline removes that need, so
the tags: trigger is dropped to avoid double-publishing. The commit and
tag are pushed before ci-release: a release promoted without its tag
pushed is worse than a pushed tag whose publish can simply be re-run.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extract the shared publish pipeline into _publish.yml (workflow_call) and turn release.yml into orchestration: a determine job outputs the run kind, then one thin caller job per kind (release, release-retry, dry-run, snapshot) selects the reusable workflow. No pipeline logic is duplicated; kind-specific steps stay single-sourced in _publish.yml, gated on inputs.kind. Each kind is now its own job in the UI and gets least-privilege permissions: a deny-all default with contents: read on every job. The GitHub App token still pushes the bump commit and tag to main (it is the sole bypass actor on the main ruleset), so no job needs contents: write. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
'Publish' overstated it: the dry-run kind assembles a bundle locally and never uploads. Name the shared pipeline after what it is -- one run of the release for a given kind -- as _run.yml (name 'Release run', job 'run'). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces the
release-prepare.yml+release.ymlsplit with a single pipeline that also dry-runs the full publish graph on every PR, then fans it out into one job per run kind via a reusable workflow.Structure
release.ymlis orchestration only. Adeterminejob decides what the run is and outputskind; four thin caller jobs gate on it and delegate to the shared reusable workflow:workflow_dispatch, first attempt: bump example versions, commit, tag, push, then publish.workflow_dispatchwhosev$VERSIONtag is already on origin from a prior attempt: skip bump/push, check out the existing tag and republish, so a release whoseci-releasefailed on an intermittent error can be re-run.pull_request: run the fullci-releasegraph with an ephemeral GPG key and dummy credentials, assembling the bundle locally (CI_SONATYPE_RELEASE=sonaBundle) instead of uploading. Needs no secrets, so it works on fork PRs.main: publish a snapshot._run.yml(workflow_call, inputkind) holds the entire pipeline once — checkout, credentials, sbt setup, bump/tag, push,ci-release— gated oninputs.kind. No pipeline logic is duplicated; the four jobs are a few lines each. Each run kind shows up as its own job in the Actions UI.Why
The old two-workflow split existed only so a tag push via the GitHub App token would trigger
release.yml. Publishing inline removes that need, so thetags:trigger is dropped to avoid double-publishing.The commit and tag are pushed before
ci-release: a release promoted without its tag pushed (an intermittent push failure after a successful publish) is worse than a pushed tag whose publish failed and can simply be re-run.The dry run exercises
exampleVersionWrite/exampleVersionCheck, signing, and theci-releasetask graph on every PR without touching Sonatype.Permissions
Deny-all default (
permissions: {}) withcontents: readon every job. No job needswrite: the bump-commit and tag are pushed tomainwith the GitHub App token, whose ability to push comes from the App installation and its bypass entry on themainruleset, not fromGITHUB_TOKEN. The App is still required — it is the sole bypass actor on the protectedmainruleset, which the defaultgithub-actions[bot]is not.Validation
The
DRY_RUNpath is confirmed green on CI: the ephemeral%no-protectionkey signs every artifact (.ascproduced) andsonaBundleassembles the bundle into local staging with no upload. TheRELEASE/RELEASE_RETRY/SNAPSHOTpaths can only be exercised by their real triggers.Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com