ASSERT-KTH / ASSERT-KTH/depclean
Migrate Maven Central publishing from OSSRH (sunset) to the Central Publisher Portal, with token-based secrets and a maintainer-only release workflow
- Dominant language
- Java
- Stars
- 363
- Forks
- 37
- Avg merge
- 5h 3m
- Merged PRs (30d)
- 57
Description
## Problem
Our release pipeline still publishes to Maven Central through the legacy OSSRH Nexus instance (`oss.sonatype.org`), which Sonatype sunset in mid-2025. As configured today, a release triggered via [`.github/workflows/deploy.yml`](.github/workflows/deploy.yml) will fail because:
- `pom.xml` still declares `distributionManagement` pointing at `https://oss.sonatype.org/service/local/staging/deploy/maven2/` (and the snapshot equivalent), and uses the `org.sonatype.plugins:nexus-staging-maven-plugin` with `nexusUrl` set to `https://oss.sonatype.org/`.
- `deploy.yml` configures Maven server auth via `actions/setup-java` with `server-username: MAVEN_USERNAME` / `server-password: MAVEN_PASSWORD`, backed by the `NEXUS_USERNAME` / `NEXUS_PASSWORD` repository secrets — i.e. classic Sonatype account username + password.
Sonatype's replacement, the [Central Publisher Portal](https://central.sonatype.com), no longer accepts account username/password for publishing. It authenticates with a **user token** (a generated token *username* + token *password* pair, distinct from your account login) and expects artifacts to be pushed through the new Publisher API rather than the old Nexus staging repository API.
## Goal
Migrate our publishing setup so that releases go through the new Central Publisher Portal, using token-based credentials stored as GitHub Actions secrets, triggered only by maintainers.
## Proposed changes
- [x] **Generate a Central Publisher Portal user token** for the project's Sonatype account (Account → Generate User Token at central.sonatype.com), and store it as new repository secrets (e.g. `CENTRAL_TOKEN_USERNAME` / `CENTRAL_TOKEN_PASSWORD`), replacing `NEXUS_USERNAME` / `NEXUS_PASSWORD`.
- [x] **Update `pom.xml`**:
- Replace `org.sonatype.plugins:nexus-staging-maven-plugin` with `org.sonatype.central:central-publishing-maven-plugin`, which is Sonatype's officially supported plugin for the Central Publisher Portal.
- Update/remove the `distributionManagement` block as required by the new plugin (it publishes via the Publisher API rather than a classic `deploy` to a Nexus URL).
- Keep the existing GPG signing step (`maven-gpg-plugin`) — Central still requires signed artifacts.
- [x] **Update `.github/workflows/deploy.yml`**:
- Swap the `server-username`/`server-password` wiring and env vars over to the new token secrets.
- Verify the release step (`clean deploy -P deploy`) still works with the new plugin, or adjust the goal/phase it binds to if `central-publishing-maven-plugin` expects a different invocation (e.g. `deploy` still, but potentially with auto-publish configuration for whether releases should be published immediately or held for manual verification).
- [ ] **Restrict manual triggering to maintainers only**. `workflow_dispatch` currently allows any user with write access to trigger a release. Consider one of:
- A GitHub Environment (e.g. `release`) with required reviewers limited to maintainers, referenced from the `release` job.
- An explicit `github.actor` allow-list check as a guard step at the start of the job.
- [ ] **Evaluate [JReleaser](https://jreleaser.org/)** as a potential replacement/simplification of parts of `deploy.yml`:
- It has built-in support for publishing to Maven Central via the Central Portal (token auth included).
- It can generate changelog/release notes automatically, potentially replacing or complementing the current `softprops/action-gh-release` step.
- If adopted, this would let us drop the separate GPG/staging plugin wiring in favor of JReleaser's unified config.
- [x] Update `CONTRIBUTING.md`/docs describing the release process, if they reference the old OSSRH credentials or steps.
- [x] Do a dry-run release (e.g. to a test/staging coordinate or with `-DdryRun`/deployment left unpublished) to confirm the new pipeline works end-to-end before cutting a real release.
## References
- [`pom.xml`](pom.xml) — `distributionManagement`, `nexus-staging-maven-plugin`, `deploy` profile (~lines 328-402)
- [`.github/workflows/deploy.yml`](.github/workflows/deploy.yml) — release workflow using `NEXUS_USERNAME`/`NEXUS_PASSWORD`
- https://central.sonatype.org/publish/publish-portal-maven/ — official guide for publishing via the Central Portal with the new Maven plugin
- https://jreleaser.org/guide/latest/examples/maven/maven-central.html — JReleaser's Maven Central publishing support
Contributor guide
Assessment
This issue has not been assessed yet.