Skip to content

ci: stage to Central portal + manual release, not irreversible auto-release (#14)#24

Merged
mibrahimdev merged 1 commit into
mainfrom
ci/14-stage-manual-release
Jun 14, 2026
Merged

ci: stage to Central portal + manual release, not irreversible auto-release (#14)#24
mibrahimdev merged 1 commit into
mainfrom
ci/14-stage-manual-release

Conversation

@mibrahimdev

Copy link
Copy Markdown
Owner

Closes #14.

What & why

The publish workflow ran publishAndReleaseToMavenCentral, which on every v*
tag uploads and auto-releases both :sharingan and :sharingan-noop to
Maven Central in one irreversible shot. Central releases can never be
unpublished
— a bad coordinate, a broken/unsigned POM, or only one of the two
modules uploaded would be a forever-public mistake.

This PR switches the flow to stage + manual release (the maintainer's
decision on #14): a tag now stages a deployment to the Central Portal and
stops; a human verifies it and clicks Publish in the portal.

After this commit, a release tag stages to the Central portal and waits for a human to release — no more irreversible auto-release.

Before / after Gradle task

Gradle task Behaviour
Before publishAndReleaseToMavenCentral uploads and auto-releases to Central, end to end
After publishToMavenCentral uploads to a new Central Portal deployment and stops; human clicks Publish

Task semantics confirmed against the vanniktech 0.36.0 plugin docs (Central
Portal page): publishToMavenCentral stages and stops; publishAndReleaseToMavenCentral
auto-releases. The Gradle config (mavenPublishing { publishToMavenCentral() },
no automaticRelease) already matches the stage-only task.

Acceptance criteria (issue #14)

  • Decision recorded — staging + manual release chosen over auto-release-with-a-verify-gate, because Central releases are irreversible. Recorded in docs/adr/0001-stage-then-manual-release.md, in this PR body, and as an inline comment in publish.yml.
  • CI workflow updatedpublish.yml runs publishToMavenCentral (stage-only) instead of publishAndReleaseToMavenCentral.
  • Dry-run / staged publish exercised — cannot run here (needs Central + signing secrets and a real tag, which only exist in CI). Dry-run instructions for the maintainer below. Not fakeable locally.
  • Release process documenteddocs/RELEASING.md (linked from README).

Workflow diff summary

.github/workflows/publish.yml (only this workflow touched — left other workflow files alone):

  • Publish step now runs ./gradlew publishToMavenCentral (stage-only) instead of publishAndReleaseToMavenCentral.
  • Removed the auto gh release create step — it would announce a GitHub "release" while the artifact is still only staged on the portal. The maintainer cuts the GitHub Release after clicking Publish (documented in RELEASING.md). permissions dropped from contents: write to contents: read accordingly.
  • Added a workflow_dispatch trigger (tag push trigger kept) so the maintainer can dry-run the staged flow without cutting a tag. The version-tag assertion now has if: github.event_name == 'push' so it's skipped on dispatch runs (which have no tag).
  • Added a header comment + a Staged - next steps summary step recording the decision and pointing at docs/RELEASING.md.

YAML validated with yaml.safe_load (parses clean); triggers resolve to push + workflow_dispatch; the single gradle run line is ./gradlew publishToMavenCentral.

Dry-run instructions for the maintainer

You can't release-by-accident here — the task is stage-only — so a real
dry-run is safe:

  1. Manual dispatch (no tag needed): GitHub → ActionsPublish to Maven CentralRun workflow on this branch (or main after merge). A workflow_dispatch run skips the version-tag assert and stages the current catalog version.
  2. Or a throwaway tag: push e.g. v0.0.1-rc1 only if you also set the catalog sharingan version to match (the assert enforces tag == catalog version). The dispatch route avoids this.
  3. Confirm it reaches the portal without releasing: when the job finishes, open https://central.sonatype.com/publishing/deployments. You should see a new deployment, VALIDATED, NOT released, with both io.github.mibrahimdev:sharingan and io.github.mibrahimdev:sharingan-noop. The workflow makes no Publish/Release API call — verify nothing landed on central.sonatype.com/artifact/....
  4. Clean up: click Drop on the staged deployment to discard it. Nothing reaches Central.

Once you're happy with the real release, follow docs/RELEASING.md: verify the staged deployment → click Publish → cut the GitHub Release.

🤖 Generated with Claude Code

After this commit, a release tag stages to the Central portal and waits for
a human to release -- no more irreversible auto-release.

The publish workflow ran `publishAndReleaseToMavenCentral`, which uploads AND
auto-releases both :sharingan and :sharingan-noop to Maven Central in one
irreversible shot on every v* tag (Central releases can never be unpublished).
It now runs `publishToMavenCentral`, which uploads to a new Central Portal
deployment and STOPS; a maintainer verifies the staged artifact and clicks
Publish in the portal.

- publish.yml: swap the Gradle task to the stage-only `publishToMavenCentral`,
  drop the auto GitHub Release step (it would announce a release while the
  artifact is still only staged -- the maintainer cuts it after the portal
  Publish), and add a `workflow_dispatch` trigger so the staged flow can be
  dry-run without cutting a tag (tag trigger kept; version-tag assert skipped
  on dispatch since it has no tag). Inline comment records the decision.
- docs/RELEASING.md: new two-step maintainer guide -- push tag, verify the
  staged deployment in the Central Portal (coordinates io.github.mibrahimdev,
  both :sharingan and :sharingan-noop present, VALIDATED, POM + .asc signatures
  complete), click Publish, then cut the GitHub Release. Includes the dry-run
  via workflow_dispatch.
- docs/adr/0001-stage-then-manual-release.md: ADR recording the deliberate
  choice of staging + manual release over auto-release-with-a-CI-gate, because
  Central releases are irreversible.
- README: link maintainers to docs/RELEASING.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mibrahimdev mibrahimdev merged commit 2668c4d into main Jun 14, 2026
1 check passed
@mibrahimdev mibrahimdev deleted the ci/14-stage-manual-release branch June 14, 2026 12:23
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.

De-risk Maven Central publish: stop irreversible auto-release on tag (HITL)

1 participant