chore: migrate CI to unified publish.yml with Sonatype Central Portal#120
Conversation
- 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
|
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: |
| <distributionManagement> | ||
| <snapshotRepository> | ||
| <id>central</id> | ||
| <url>https://central.sonatype.com/repository/maven-snapshots/</url> |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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/ |
There was a problem hiding this comment.
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]There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
| - uses: actions/checkout@v6 | ||
| - uses: actions/setup-java@v5 | ||
| with: { java-version: '8', distribution: zulu } | ||
| - uses: github/codeql-action/init@v3 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Summary of Issues FoundMust Fix Before Merge:
Should Address: Setup Requirements (for repo admins):
|
- 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
| 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 |
There was a problem hiding this comment.
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*"
| 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 }} | ||
|
|
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
| -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 }} | ||
|
|
There was a problem hiding this comment.
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
fiThere was a problem hiding this comment.
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
| <distributionManagement> | ||
| <snapshotRepository> | ||
| <id>central</id> | ||
| <url>https://central.sonatype.com/repository/maven-snapshots/</url> | ||
| </snapshotRepository> | ||
| </distributionManagement> |
There was a problem hiding this comment.
✅ 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.
|
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. |
Summary
release.yaml→publish.ymland update triggers/jobsreleaseevent trigger withtags: ['v*']push triggerpublish-snapshot(new): deploys to Sonatype Central Portal snapshot repo on every push tomainor manual dispatch; usesdeploy:deploy-filewith the pre-built JARs from thepackagejob; usesenvironment: maven-centralpublish-release(renamed frompublish): switchesserver-idossrh→central, fixes GPG secret name (GPG_SIGNING_KEY→GPG_PRIVATE_KEY), usesCENTRAL_USERNAME/CENTRAL_TOKENcodeql.yml: GitHub Advanced Security scanning on PRs, pushes tomain, and weekly schedulepost-publishjob: Maven dependency graph submissionpom.xml: adddistributionManagementsnapshotRepositorypointing to Central PortalPrerequisites (must be done in GitHub UI before workflows run)
maven-centralmainas an allowed branch sopublish-snapshotpasses the environment gate automatically on main pushesmaven-centralenvironment:CENTRAL_USERNAME,CENTRAL_TOKEN,GPG_PRIVATE_KEY,GPG_PASSPHRASETest plan
main→ package (all platform cross-compiles) + publish-snapshot + post-publishv*tag → package + publish-release (pauses at environment approval) + post-publishmainand weekly on schedulehttps://claude.ai/code/session_01TPLSUAgEHPFGSoDesiPZ5N
Generated by Claude Code