Skip to content

chore: migrate CI to unified publish.yml with Sonatype Central Portal#120

Merged
bernardladenthin merged 2 commits into
mainfrom
claude/sonatype-central-portal
May 11, 2026
Merged

chore: migrate CI to unified publish.yml with Sonatype Central Portal#120
bernardladenthin merged 2 commits into
mainfrom
claude/sonatype-central-portal

Conversation

@bernardladenthin
Copy link
Copy Markdown
Owner

Summary

  • Rename release.yamlpublish.yml and update triggers/jobs
  • Replace release event trigger with tags: ['v*'] push trigger
  • publish-snapshot (new): deploys to Sonatype Central Portal snapshot repo on every push to main or manual dispatch; uses deploy:deploy-file with the pre-built JARs from the package job; uses environment: maven-central
  • publish-release (renamed from publish): switches server-id ossrh→central, fixes GPG secret name (GPG_SIGNING_KEYGPG_PRIVATE_KEY), uses CENTRAL_USERNAME/CENTRAL_TOKEN
  • Add codeql.yml: GitHub Advanced Security scanning on PRs, pushes to main, and weekly schedule
  • Add post-publish job: Maven dependency graph submission
  • pom.xml: add distributionManagement snapshotRepository pointing to Central Portal
  • All GitHub Actions on latest major versions (checkout@v6, setup-java@v5, upload-artifact@v7, download-artifact@v8, maven-dependency-submission-action@v5)

Prerequisites (must be done in GitHub UI before workflows run)

  1. Go to Settings → Environments → maven-central
  2. Under "Deployment branches and tags", add main as an allowed branch so publish-snapshot passes the environment gate automatically on main pushes
  3. Secrets required in the maven-central environment: CENTRAL_USERNAME, CENTRAL_TOKEN, GPG_PRIVATE_KEY, GPG_PASSPHRASE

Test plan

  • Push to main → package (all platform cross-compiles) + publish-snapshot + post-publish
  • Push v* tag → package + publish-release (pauses at environment approval) + post-publish
  • Feature branch push / PR → package only; publish jobs skipped
  • CodeQL runs on PRs targeting main and weekly on schedule

https://claude.ai/code/session_01TPLSUAgEHPFGSoDesiPZ5N


Generated by Claude Code

- Rename release.yaml → publish.yml and update workflow name
- Replace release event with tags: ['v*'] push trigger and main branch
- publish-snapshot: deploy to Central Portal snapshot repo on main push
  or manual dispatch (replaces GitHub Releases + GitHub Packages)
- publish-release: switch server-id ossrh→central, fix GPG secret name
  (GPG_SIGNING_KEY→GPG_PRIVATE_KEY), use CENTRAL_USERNAME/TOKEN
- Add codeql.yml for GitHub Advanced Security (weekly + PR)
- Add post-publish job for Maven dependency graph submission
- pom.xml: add distributionManagement snapshotRepository for Central Portal

https://claude.ai/code/session_01TPLSUAgEHPFGSoDesiPZ5N
@claude
Copy link
Copy Markdown

claude Bot commented May 11, 2026

Critical Issue Found: Missing in pom.xml

The PR adds but release deployments need a entry in distributionManagement. Without it, publish-release will fail.

Add this to pom.xml distributionManagement section:

<repository>
  <id>central</id>
  <url>https://central.sonatype.com/repository/releases/</url>
</repository>

Comment thread pom.xml
<distributionManagement>
<snapshotRepository>
<id>central</id>
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing <repository> section for release deployments. The publish-release job deploys non-snapshot versions (e.g., 1.0.0) and requires this entry:

<repository>
  <id>central</id>
  <url>https://central.sonatype.com/repository/releases/</url>
</repository>

Without it, mvn deploy will fail to find a target repository for release versions.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not needed. central-publishing-maven-plugin with <extensions>true</extensions> (in the release profile) replaces Maven's default deploy plugin and intercepts the deploy lifecycle for non-SNAPSHOT versions. It uploads artifacts to Central Portal directly via its own API using <publishingServerId>, independent of any distributionManagement/<repository> entry.

Adding a <repository> would only affect Maven's built-in deploy plugin, which is no longer invoked when the extension is active. The publish-release job will work correctly without it.


Generated by Claude Code

- uses: actions/download-artifact@v8
with:
name: llama-jars
path: snapshot-jars/
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The post-publish job depends on both publish-snapshot and publish-release even though they run in mutually exclusive scenarios (snapshot on main push, release on tag push).

While the condition correctly handles skipped jobs, consider adding a comment documenting why both dependencies are needed, to prevent accidental breakage if either job is renamed or removed in the future.

Suggested comment:

# Depends on both publish jobs (mutually exclusive):
# - publish-snapshot runs on main branch pushes
# - publish-release runs on tag pushes
# Only one will succeed per trigger; post-publish runs if either succeeds
needs: [package, publish-snapshot, publish-release]

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The if: condition is self-documenting: publish-snapshot.result == 'success' || publish-release.result == 'success'. Since these two jobs have mutually exclusive trigger conditions (main branch vs. v* tags), only one can ever succeed per run. Adding inline YAML comments would add noise to an already clear condition. No change needed.


Generated by Claude Code

publish:
if: ${{ github.event_name == 'release' || (github.event.inputs.release_to_maven_central == 'true' && needs.crosscompile-linux-x86_64-cuda.outputs.built == 'true') }}
publish-release:
name: Publish Release to Central
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The maven-dependency-submission-action runs after publishing and needs to access the checked-out repository. This job should inherit the environment protection from the publish jobs that precede it. Consider adding environment: maven-central here as well to enforce that the source code must come from a trusted context, or add a comment explaining why it's safe to run without environment protection.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

post-publish does not deploy any artifacts or access secrets from the maven-central environment — it only submits the dependency graph and uploads coverage reports. Requiring the maven-central environment gate on this job would block the dependency graph submission on every main-branch push until a reviewer approves, which is unnecessary overhead. The maven-central environment is intentionally scoped to the two jobs that actually publish.


Generated by Claude Code

Comment thread .github/workflows/codeql.yml Outdated
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with: { java-version: '8', distribution: zulu }
- uses: github/codeql-action/init@v3
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: CodeQL actions are pinned to v3, while other workflow actions use v5+ (checkout@v6, setup-java@v5, maven-dependency-submission-action@v5). While v3 is still maintained, consider upgrading to a newer version for consistency. Check GitHub's documentation for any breaking changes between v3 and the latest CodeQL action version.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@claude
Copy link
Copy Markdown

claude Bot commented May 11, 2026

Summary of Issues Found

Must Fix Before Merge:

  1. Add entry to pom.xml for release deployments (blocking issue)

Should Address:
2. Add documentation comment to post-publish job explaining why it depends on two mutually-exclusive jobs
3. Consider adding environment protection to post-publish job for consistency
4. Update CodeQL actions to match version consistency with other actions (v5+)

Setup Requirements (for repo admins):

  • Configure 'maven-central' environment in GitHub Settings
  • Add 'main' branch to deployment branches in environment settings
  • Create secrets: CENTRAL_USERNAME, CENTRAL_TOKEN, GPG_PRIVATE_KEY, GPG_PASSPHRASE

- github/codeql-action bumped from v3 to v4 (latest major)
- post-publish job gets permissions: contents: write (needed by
  maven-dependency-submission-action to submit the dependency graph)

https://claude.ai/code/session_01TPLSUAgEHPFGSoDesiPZ5N
Comment on lines +622 to 632
MAVEN_PASSWORD: ${{ secrets.CENTRAL_TOKEN }}

publish:
if: ${{ github.event_name == 'release' || (github.event.inputs.release_to_maven_central == 'true' && needs.crosscompile-linux-x86_64-cuda.outputs.built == 'true') }}
publish-release:
name: Publish Release to Central
if: startsWith(github.ref, 'refs/tags/v') || github.event.inputs.release_to_maven_central == 'true'
needs: [ package, crosscompile-linux-x86_64-cuda ]
runs-on: ubuntu-latest
environment: maven-central
steps:
- uses: actions/checkout@v6
- uses: actions/download-artifact@v8
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Environment protection incomplete for tags: This job runs on tag pushes (startsWith(github.ref, 'refs/tags/v')) with environment: maven-central, but the PR prerequisites only mention adding main as an allowed deployment branch.

Tag-based deployments may require additional environment configuration (e.g., adding refs matching refs/tags/v* as allowed deployment branches or configuring tag protection). Without this, tag pushes will fail with an environment protection error.

Suggest: Update the prerequisites section to include: "For tag pushes, ensure the maven-central environment also allows deployment from tags matching refs/tags/v*"

Comment on lines 595 to 623
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
environment: maven-central
steps:
- uses: actions/checkout@v6
- uses: actions/download-artifact@v8
with:
name: llama-jars
path: snapshot-jars/
- name: Publish rolling snapshot release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
run: |
gh release delete snapshot --yes --cleanup-tag || true
gh release create snapshot snapshot-jars/*.jar \
--title "Snapshot Build" \
--notes "Snapshot from ${{ github.sha }} — ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
--prerelease \
--target ${{ github.sha }}
- name: Set up Maven for GitHub Packages
uses: actions/setup-java@v5
- uses: actions/setup-java@v5
with:
distribution: 'zulu'
java-version: '8'
server-id: github
server-username: GITHUB_ACTOR
server-password: GITHUB_TOKEN
- name: Delete snapshot package from GitHub Packages
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh api --method DELETE /user/packages/maven/net.ladenthin.llama || true
- name: Publish to GitHub Packages
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
distribution: zulu
server-id: central
server-username: MAVEN_USERNAME
server-password: MAVEN_PASSWORD
- name: Deploy snapshot
run: |
VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
mvn --batch-mode deploy:deploy-file \
-Durl=https://maven.pkg.github.com/${{ github.repository }} \
-DrepositoryId=github \
-Durl=https://central.sonatype.com/repository/maven-snapshots \
-DrepositoryId=central \
-Dfile=snapshot-jars/llama-${VERSION}.jar \
-DpomFile=pom.xml \
-Dsources=snapshot-jars/llama-${VERSION}-sources.jar \
-Djavadoc=snapshot-jars/llama-${VERSION}-javadoc.jar
env:
MAVEN_USERNAME: ${{ secrets.CENTRAL_USERNAME }}
MAVEN_PASSWORD: ${{ secrets.CENTRAL_TOKEN }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Breaking change: GitHub releases discontinued for snapshots. The old workflow published snapshot builds to GitHub Releases (gh release create snapshot), but this new workflow publishes directly to Maven Central snapshots repository instead.

If external tools, CI pipelines, or documentation reference snapshot releases from GitHub, they will break. This is a significant workflow change.

Questions:

  • Is the GitHub Release asset deprecation intentional?
  • Should snapshot builds still be available from GitHub (e.g., via a separate rollover release), or is Maven Central the canonical source now?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is intentional. GitHub Releases are no longer the canonical distribution channel — Maven Central snapshots are. Consumers should pull snapshots from https://central.sonatype.com/repository/maven-snapshots/ via their build tool, not from GitHub Release assets. The GitHub Release approach was a workaround for the absence of Central Portal snapshot support; that workaround is no longer needed.


Generated by Claude Code

Comment on lines 618 to 623
-Dsources=snapshot-jars/llama-${VERSION}-sources.jar \
-Djavadoc=snapshot-jars/llama-${VERSION}-javadoc.jar
env:
MAVEN_USERNAME: ${{ secrets.CENTRAL_USERNAME }}
MAVEN_PASSWORD: ${{ secrets.CENTRAL_TOKEN }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Version mismatch risk: When a tag v1.2.3 is pushed, the workflow automatically publishes a release. However, there's no validation that the tag version matches the <version> in pom.xml.

If a developer accidentally pushes v1.2.3 while pom.xml contains 1.2.4-SNAPSHOT, a mismatched artifact will be published to Maven Central with incorrect version metadata.

Suggest: Add a validation step before publish-release that compares the tag version with pom.xml:

TAG_VERSION=$(echo "${{ github.ref }}" | sed 's|refs/tags/v||')
POM_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
if [[ "$TAG_VERSION" != "$POM_VERSION" ]]; then
  echo "Error: Tag version $TAG_VERSION does not match pom.xml version $POM_VERSION"
  exit 1
fi

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid observation, but tag-version/pom-version alignment is a release workflow practice outside the scope of this CI migration. The same gap exists in other repos (streambuffer, BitcoinAddressFinder) and is a deliberate decision to keep the workflow simple. A version validation step can be added in a follow-up if desired.


Generated by Claude Code

Comment thread pom.xml
Comment on lines +37 to +42
<distributionManagement>
<snapshotRepository>
<id>central</id>
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct: The snapshot repository URL matches the documented Sonatype Central Portal endpoint. However, ensure the <id>central</id> matches the server-id: central in the GitHub Actions workflow and the corresponding credentials are configured in ~/.m2/settings.xml or via CI environment variables.

@claude
Copy link
Copy Markdown

claude Bot commented May 11, 2026

Review Summary: This PR migrates to Sonatype Central Portal with CodeQL scanning. Key strengths: cleaner tag-based triggers, unified Maven Central, security scanning. See inline comments for three critical issues: (1) incomplete environment protection for tags, (2) snapshot releases removed from GitHub, (3) no tag-to-version validation. Please address before merge.

@bernardladenthin bernardladenthin merged commit 9b52694 into main May 11, 2026
31 of 34 checks passed
@bernardladenthin bernardladenthin deleted the claude/sonatype-central-portal branch May 11, 2026 08:18
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.

2 participants