Release to Maven Central #24
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
| name: Release to Maven Central | |
| on: | |
| workflow_dispatch: | |
| release: | |
| types: [published] | |
| permissions: | |
| contents: read | |
| jobs: | |
| publish: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Java | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: '11' | |
| cache: maven | |
| # 可选:快速检查必需的 Secrets 是否存在(避免空跑) | |
| - name: Check required secrets | |
| run: | | |
| [ -z "${{ secrets.GPG_PRIVATE_KEY }}" ] && echo "GPG_PRIVATE_KEY is EMPTY" && exit 1 || echo "GPG_PRIVATE_KEY is SET" | |
| [ -z "${{ secrets.CENTRAL_USERNAME }}" ] && echo "CENTRAL_USERNAME is EMPTY" && exit 1 || echo "CENTRAL_USERNAME is SET" | |
| [ -z "${{ secrets.CENTRAL_TOKEN }}" ] && echo "CENTRAL_TOKEN is EMPTY" && exit 1 || echo "CENTRAL_TOKEN is SET" | |
| [ -z "${{ secrets.GPG_PASSPHRASE }}" ] && echo "GPG_PASSPHRASE is EMPTY (OK if your key has no passphrase)" || echo "GPG_PASSPHRASE is SET" | |
| # 仅在 CI 导入私钥(你已把 private.asc 转成单行 base64 存在 GPG_PRIVATE_KEY) | |
| - name: Import GPG private key (base64) | |
| env: | |
| GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} | |
| run: | | |
| set -e | |
| mkdir -p ~/.gnupg | |
| chmod 700 ~/.gnupg | |
| printf "pinentry-mode loopback\n" >> ~/.gnupg/gpg.conf | |
| printf "allow-loopback-pinentry\n" >> ~/.gnupg/gpg-agent.conf | |
| gpgconf --kill gpg-agent || true | |
| echo "$GPG_PRIVATE_KEY" > "$RUNNER_TEMP/priv.b64" | |
| base64 -d "$RUNNER_TEMP/priv.b64" > "$RUNNER_TEMP/private.asc" | |
| gpg --batch --import "$RUNNER_TEMP/private.asc" | |
| echo "== Secret keys in keyring ==" | |
| gpg --batch --list-secret-keys --keyid-format LONG || true | |
| # 仅在 CI 生成 settings.xml(开发者本地无需配置) | |
| - name: Create temporary Maven settings.xml (CI-only) | |
| env: | |
| CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }} | |
| CENTRAL_TOKEN: ${{ secrets.CENTRAL_TOKEN }} | |
| run: | | |
| mkdir -p ~/.m2 | |
| { | |
| printf '<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">\n' | |
| printf ' <servers>\n' | |
| printf ' <server>\n' | |
| printf ' <id>ossrh</id>\n' | |
| printf ' <username>${env.CENTRAL_USERNAME}</username>\n' | |
| printf ' <password>${env.CENTRAL_TOKEN}</password>\n' | |
| printf ' </server>\n' | |
| printf ' </servers>\n' | |
| printf '</settings>\n' | |
| } > ~/.m2/settings.xml | |
| - name: Probe Central auth with username guess | |
| env: | |
| U1: welsir # 如果你在 Profile 里找到了 Username,就改成那个 | |
| TOK: ${{ secrets.CENTRAL_TOKEN }} # Publishing/Deployment Token 的明文 | |
| run: | | |
| set -e | |
| url=https://s01.oss.sonatype.org/service/local/staging/profiles | |
| code=$(curl -s -o /dev/null -w "%{http_code}" -u "$U1:$TOK" "$url") | |
| echo "probe($U1) => HTTP $code" | |
| - name: Diagnose Maven settings | |
| run: | | |
| echo "Show ~/.m2/settings.xml:" | |
| sed -n '1,200p' ~/.m2/settings.xml || true | |
| echo "Effective server IDs found in settings.xml:" | |
| awk -F'[<>]' '/<id>/{print "id=" $3}' ~/.m2/settings.xml || true | |
| # 合并:检查 Secrets 长度 + 用最小项目做一次 auth 调试(-X) | |
| - name: Check CENTRAL secrets length (no leak) and auth debug deploy | |
| env: | |
| CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }} | |
| CENTRAL_TOKEN: ${{ secrets.CENTRAL_TOKEN }} | |
| run: | | |
| set -e | |
| # 1) 检查 Secrets 长度(不泄露明文) | |
| USER_LEN=$(printf "%s" "$CENTRAL_USERNAME" | wc -c | tr -d ' ') | |
| TOKEN_LEN=$(printf "%s" "$CENTRAL_TOKEN" | wc -c | tr -d ' ') | |
| echo "USER_LEN=$USER_LEN" | |
| echo "TOKEN_LEN=$TOKEN_LEN" | |
| if [ "$USER_LEN" -eq 0 ] || [ "$TOKEN_LEN" -eq 0 ]; then | |
| echo "ERROR: CENTRAL_USERNAME or CENTRAL_TOKEN is empty. Fix Secrets before continuing." | |
| exit 1 | |
| fi | |
| # 2) 用一个最小项目做一次 auth 检查(不影响你的主项目配置) | |
| mkdir -p /tmp/miniproj && cd /tmp/miniproj | |
| cat > pom.xml <<'XML' | |
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
| <modelVersion>4.0.0</modelVersion> | |
| <groupId>io.github.timemachinelab</groupId> | |
| <artifactId>auth-check</artifactId> | |
| <version>0.0.1</version> | |
| <distributionManagement> | |
| <repository> | |
| <id>ossrh</id> | |
| <url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url> | |
| </repository> | |
| <snapshotRepository> | |
| <id>ossrh</id> | |
| <url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url> | |
| </snapshotRepository> | |
| </distributionManagement> | |
| </project> | |
| XML | |
| # 3) 显式指定 settings,并开启 -X 抓取认证细节 | |
| # 用 || true 避免 401 时整个 Job 直接失败,中断后续日志收集。 | |
| mvn -X -B -U -s ~/.m2/settings.xml -DskipTests=true deploy || true | |
| # 确认版本不是 SNAPSHOT(发布前置检查) | |
| - name: Ensure release version (non-SNAPSHOT) | |
| run: | | |
| VERSION=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:3.5.0:exec) | |
| echo "Project version: $VERSION" | |
| if echo "$VERSION" | grep -qi SNAPSHOT; then | |
| echo "ERROR: version is SNAPSHOT. Please set a release version." | |
| exit 1 | |
| fi | |
| # 先 verify,便于排错;显式指定 KEY_ID(替换为你的 KEY_ID) | |
| - name: Verify with signing (detailed logs) | |
| env: | |
| GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} | |
| run: | | |
| set -e | |
| KEY_ID="6BFD927CC2352BD5" # TODO: 替换为你的长 KEYID | |
| echo "Using KEY_ID=$KEY_ID" | |
| mvn -e -X -s ~/.m2/settings.xml -Dgpg.passphrase="$GPG_PASSPHRASE" -Dgpg.keyname="$KEY_ID" -DskipTests=true clean verify | |
| # 签名并发布到 OSSRH(Maven Central) | |
| - name: Build, sign and deploy | |
| env: | |
| GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} | |
| run: | | |
| set -e | |
| KEY_ID="6BFD927CC2352BD5" # TODO: 同上 | |
| mvn -B -U -s ~/.m2/settings.xml -Dgpg.passphrase="$GPG_PASSPHRASE" -Dgpg.keyname="$KEY_ID" clean deploy |