Skip to content

Commit 9deacba

Browse files
committed
ci: upload to the Central Portal on a tag, but never auto-publish
Maven Central is the one registry in this fleet with NO Trusted Publishing, so unlike PyPI, RubyGems and NuGet this workflow needs real stored secrets. Doppler (seatlayer-release/prd) stays the source of truth; Actions holds copies. The workflow uploads and stops. pom.xml already sets <autoPublish>false</autoPublish> and <waitUntil>validated</waitUntil>, so the deployment lands in the Portal as validated and waits for a human to press Publish. That is the last reversible moment — a deployment can be dropped, but a published version is on Central permanently and can never be replaced or deleted. Automating that click would trade the only undo we have for a few seconds. Two things that must agree or the upload fails in ways that read as something else: setup-java's server-id must match <publishingServerId> in pom.xml (both 'central', or the upload 401s), and the deploy must carry -Prelease, because signing lives in that profile and Central rejects any artifact without a detached .asc. Verified locally before landing: mvn verify is green, and help:evaluate returns exactly 0.1.0, which is the string the tag check compares against.
1 parent f85ed27 commit 9deacba

1 file changed

Lines changed: 78 additions & 0 deletions

File tree

.github/workflows/release.yml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
name: Release
2+
3+
# Uploads to Maven Central via the Central Portal.
4+
#
5+
# Unlike the other five registries in this fleet, Central has NO Trusted
6+
# Publishing — there is no OIDC path, so this is the one workflow that needs
7+
# real stored secrets. Doppler (project seatlayer-release, config prd) is the
8+
# source of truth; these are operational copies pushed into Actions secrets.
9+
#
10+
# This workflow UPLOADS BUT DOES NOT PUBLISH. pom.xml sets
11+
# <autoPublish>false</autoPublish>, so the deployment lands in the Portal as
12+
# VALIDATED and waits for a human to press Publish. That is deliberate and is
13+
# the last reversible moment: a deployment can be dropped, but a published
14+
# version is on Central permanently — it can never be replaced or deleted.
15+
#
16+
# To release: push a tag matching <version> in pom.xml, then press Publish in
17+
# the Portal once the deployment shows validated.
18+
#
19+
# git tag v0.1.0 && git push origin v0.1.0
20+
21+
on:
22+
push:
23+
tags: ["v*"]
24+
25+
permissions: {}
26+
27+
jobs:
28+
deploy:
29+
runs-on: ubuntu-latest
30+
environment:
31+
name: maven-central
32+
url: https://central.sonatype.com/publishing/deployments
33+
steps:
34+
- uses: actions/checkout@v4
35+
36+
- uses: actions/setup-java@v4
37+
with:
38+
java-version: "17"
39+
distribution: temurin
40+
cache: maven
41+
# Writes ~/.m2/settings.xml with <server><id>central</id>, matching
42+
# <publishingServerId>central</publishingServerId> in pom.xml. These
43+
# two names must agree or the upload 401s.
44+
server-id: central
45+
server-username: MAVEN_USERNAME
46+
server-password: MAVEN_PASSWORD
47+
# Imports the private key into the runner's keyring so maven-gpg-plugin
48+
# can produce the detached .asc signatures Central requires.
49+
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
50+
gpg-passphrase: MAVEN_GPG_PASSPHRASE
51+
52+
- name: Gate
53+
run: mvn -B verify
54+
55+
- name: Refuse to publish if the tag and pom version disagree
56+
run: |
57+
tag="${GITHUB_REF_NAME#v}"
58+
ver="$(mvn -B -q help:evaluate -Dexpression=project.version -DforceStdout)"
59+
if [ "$tag" != "$ver" ]; then
60+
echo "::error::tag v$tag does not match pom version $ver"
61+
exit 1
62+
fi
63+
64+
- name: Deploy to the Central Portal
65+
# -Prelease activates the signing profile. Central rejects any artifact
66+
# without a detached .asc, and an ordinary `mvn deploy` would upload
67+
# unsigned and be refused.
68+
run: mvn -B -Prelease deploy
69+
env:
70+
MAVEN_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
71+
MAVEN_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
72+
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
73+
74+
- name: Where this landed
75+
run: |
76+
echo "Uploaded and validated — NOT yet published."
77+
echo "Press Publish at https://central.sonatype.com/publishing/deployments"
78+
echo "to make io.seatlayer:seatlayer-java:${GITHUB_REF_NAME#v} permanent."

0 commit comments

Comments
 (0)