Skip to content

Thin main jar + manual Maven Central publish workflow#27

Merged
jochen-testingbot merged 3 commits into
masterfrom
thin-jar
Jul 15, 2026
Merged

Thin main jar + manual Maven Central publish workflow#27
jochen-testingbot merged 3 commits into
masterfrom
thin-jar

Conversation

@jochen-testingbot

@jochen-testingbot jochen-testingbot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Problem

maven-shade-plugin was configured to replace the main build artifact with the shaded uber jar, so the published com.testingbot:TestingBotTunnel Maven artifact was a fat jar bundling Jetty (~1000 classes), Apache HTTP, commons-cli, Jackson, logback, etc.

Maven consumers (notably the Jenkins TestingBot plugin) then received those bundled classes on a flat classpath, where they shadow the consumer's own copies. Concretely this:

  • breaks the Jenkins plugin's test harness (bundled Jetty 11 clashes with the harness' Jetty 12 — Request is a class vs an interface), blocking all JenkinsRule/JCasC tests, and
  • shadows the consumer's commons-cli (the plugin's modern DefaultParser/Option.builder threw NoSuchFieldError at runtime).

You can't exclude classes bundled inside a jar, so consumers had no way to fix this.

Change

Attach the shaded uber jar under a shaded classifier instead of replacing the main artifact:

  • Maven Central now gets a thin main jar (~451 KB, project classes only) whose POM declares the real dependencies, so consumers resolve Jetty/HTTP/commons-cli/etc. transitively at the correct versions and can manage/exclude them normally.
  • Docker, the CLI release asset, and the package-time smoke test use the runnable -shaded jar, so nothing changes for CLI users.
  • The GitHub release keeps the familiar runnable TestingBotTunnel-<version>.jar download name (the release workflow renames the shaded jar).

No dependency versions changed; this is purely how the artifact is packaged/published.

Verification

Local mvn -DskipTests package (JDK 11):

  • TestingBotTunnel-4.8.jar0 bundled Jetty classes, 451 KB (thin).
  • TestingBotTunnel-4.8-shaded.jar — 7.3 MB, runnable: java -jar target/TestingBotTunnel-4.8-shaded.jar --versionVersion: testingbot-tunnel.jar 4.8.

The existing release workflow (tag → mvn clean deploy via the Central Portal plugin) publishes the thin main jar + sources + javadoc + the shaded classifier, all GPG-signed.


Also: manual "Publish to Maven Central" workflow

Adds .github/workflows/maven-publish.yml (workflow_dispatch) that deploys the current POM version to Central on demand — deploy only, no GitHub release or Docker. This is how to get 4.8 onto Maven Central (it's already released on GitHub/Docker but never published to Central), without re-tagging.

⚠️ Maven Central versions are immutable — only run this from a branch that builds the thin jar (i.e. this branch, or master after merge), so 4.8 is published thin and stays thin.

Summary by CodeRabbit

  • New Features
    • Added a manually triggered workflow for publishing artifacts to Maven Central.
  • Improvements
    • Release packages now include the runnable shaded JAR with a consistent filename.
    • Docker builds now use the complete shaded application package.
    • Post-build verification runs against the runnable shaded artifact.
  • Bug Fixes
    • Corrected release uploads to use the intended executable JAR instead of the thin package.

maven-shade-plugin replaced the main artifact with the uber jar, so the published
com.testingbot:TestingBotTunnel Maven artifact bundled Jetty, Apache HTTP, commons-cli, etc.
Consumers (e.g. the Jenkins TestingBot plugin) then got those bundled classes shadowing their own
copies on a flat classpath, breaking modern APIs and the test harness.

Attach the shaded uber jar under the 'shaded' classifier instead of replacing the main artifact:
- Maven Central gets a thin main jar whose POM declares the real dependencies (transitive, correctly versioned).
- Docker, the CLI release asset, and the package-time smoke test use the runnable '-shaded' jar.
- The GitHub release asset keeps the familiar runnable TestingBotTunnel-<version>.jar name.

Verified locally: main jar has 0 bundled Jetty classes (451 KB); shaded jar runs 'java -jar ... --version'.
Lets us publish the current POM version to Central on demand (e.g. 4.8, already released on
GitHub/Docker) without re-tagging or re-running the GitHub release + Docker jobs. Deploy-only,
mirrors release.yml's Central/GPG setup. Run it from a branch that produces the thin jar.
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 63d2b412-5d45-4341-8bc0-b828e5e5221b

📥 Commits

Reviewing files that changed from the base of the PR and between 44a9709 and 07e29ee.

📒 Files selected for processing (2)
  • .github/workflows/maven-publish.yml
  • .github/workflows/release.yml

📝 Walkthrough

Walkthrough

The build now publishes a thin main JAR alongside a shaded shaded classifier. Docker and GitHub Releases consume the shaded artifact, while a new manually triggered workflow deploys signed artifacts to Maven Central.

Changes

Maven artifact flow

Layer / File(s) Summary
Shaded artifact contract
pom.xml
The shade plugin attaches the uber JAR with the shaded classifier, and the package smoke test runs that artifact.
Runtime and release artifact selection
Dockerfile, .github/workflows/release.yml
Docker packaging and GitHub Releases select the shaded JAR while retaining their existing output names.
Manual Maven Central publication
.github/workflows/maven-publish.yml
A manually triggered JDK 11 workflow deploys to Maven Central with Maven caching, credentials, and GPG signing configuration.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Maven
  participant Docker
  participant GitHubReleases
  participant MavenCentral

  Maven->>Maven: Attach shaded JAR and run smoke test
  Maven->>Docker: Provide shaded JAR
  Docker->>Docker: Rename artifact to testingbot-tunnel.jar
  Maven->>GitHubReleases: Copy shaded JAR to release-assets
  GitHubReleases->>GitHubReleases: Upload release asset
  Maven->>MavenCentral: Deploy signed artifacts
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the two main changes: publishing a thin main jar and adding a manual Maven Central publish workflow.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@jochen-testingbot jochen-testingbot changed the title Publish a thin main jar (attach uber jar as 'shaded' classifier) Thin main jar + manual Maven Central publish workflow Jul 15, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/maven-publish.yml:
- Around line 10-15: Add workflow-level token permissions in the Maven publish
workflow by declaring contents read access alongside the top-level on
configuration. Keep the publish job behavior unchanged while ensuring the
workflow token has no write permissions.
- Around line 10-15: Add workflow-level concurrency to the Maven publish
workflow, using a stable group for all runs and configuring new manual runs to
wait for an existing publish rather than deploying concurrently. Keep the
existing publish job and workflow_dispatch trigger unchanged.
- Around line 18-22: Update the “Checkout code” and “Set up JDK 11” steps to
reference immutable, verified commit SHAs for actions/checkout and
actions/setup-java instead of the mutable `@v4` tags, while preserving their
existing action versions and configuration.
- Around line 3-11: Restrict the workflow_dispatch entry for the Maven publish
workflow to an approved protected release tag or branch, and validate that the
checked-out ref and POM version match the expected release before deployment.
Add the validation before the Maven publish step and fail the workflow on any
mismatch, while preserving the existing manual publishing behavior for valid
release refs.
- Around line 18-19: Update the actions/checkout step in the Maven publish
workflow to set persist-credentials to false, ensuring the checkout does not
retain the GitHub token in local Git configuration before mvn deploy runs.
- Around line 34-38: Remove the inline -Dgpg.passphrase argument from the Maven
deploy command. Keep GPG_PASSPHRASE in the existing env configuration so
actions/setup-java continues supplying the passphrase through the environment.

In @.github/workflows/release.yml:
- Around line 55-56: Update the “Upload JAR to GitHub Releases” workflow step to
use the current major version of softprops/action-gh-release and pin it to the
corresponding full commit SHA instead of the mutable `@v1` tag.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 25e17f30-3379-40a3-8438-398fdc53b9db

📥 Commits

Reviewing files that changed from the base of the PR and between 0a7b373 and 44a9709.

📒 Files selected for processing (4)
  • .github/workflows/maven-publish.yml
  • .github/workflows/release.yml
  • Dockerfile
  • pom.xml

Comment on lines +3 to +11
# Manually publish the current POM version to Maven Central, without creating a
# GitHub release or Docker image (use this to publish a version that was already
# tagged/released on GitHub, e.g. 4.8). Select the branch to run from in the
# "Run workflow" dropdown — it publishes whatever version the checked-out POM has.
#
# NOTE: Maven Central versions are immutable. Only run this from a branch whose
# build produces the thin main jar (i.e. after the thin-jar change is merged).
on:
workflow_dispatch:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

file=".github/workflows/maven-publish.yml"

echo "=== file outline ==="
ast-grep outline "$file" --view expanded || true

echo
echo "=== numbered file excerpt ==="
cat -n "$file"

echo
echo "=== search for workflow env/permissions/checkout/setup-java/deploy ==="
rg -n "workflow_dispatch|permissions:|environment:|actions/checkout|setup-java|mvn|deploy|gpg|MAVEN_CENTRAL|maven" "$file"

Repository: testingbot/Testingbot-Tunnel

Length of output: 2438


Gate this publish job to a protected release ref. The workflow accepts any selected branch and runs it with Maven Central and GPG secrets, so a bad or compromised ref can publish the wrong immutable version or alter the publish steps. Enforce a protected tag/branch and reject POM/version mismatches before deploy.

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 10-11: insufficient job-level concurrency limits (concurrency-limits): workflow is missing concurrency setting

(concurrency-limits)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/maven-publish.yml around lines 3 - 11, Restrict the
workflow_dispatch entry for the Maven publish workflow to an approved protected
release tag or branch, and validate that the checked-out ref and POM version
match the expected release before deployment. Add the validation before the
Maven publish step and fail the workflow on any mismatch, while preserving the
existing manual publishing behavior for valid release refs.

Source: MCP tools

Comment thread .github/workflows/maven-publish.yml
Comment thread .github/workflows/maven-publish.yml Outdated
Comment thread .github/workflows/maven-publish.yml Outdated
Comment thread .github/workflows/maven-publish.yml Outdated
Comment thread .github/workflows/release.yml Outdated
…rrency, GPG env

maven-publish.yml:
- Add contents:read permissions and a maven-central-publish concurrency group (queue, never race)
- Pin actions/checkout + actions/setup-java to commit SHAs; set persist-credentials: false
- Drop the inline -Dgpg.passphrase (passphrase already supplied via the GPG_PASSPHRASE env by setup-java)

release.yml:
- Pin softprops/action-gh-release to v3 commit SHA (was mutable @v1)

Skipped: restricting workflow_dispatch to a protected release tag + ref/version validation. The
workflow is intentionally a maintainer-only manual publish (workflow_dispatch needs repo write and
secrets) that must be runnable from master or a feature branch (e.g. to publish 4.8 thin from this
branch); tying it to a protected tag defeats that, and Central's immutability already blocks
overwriting an existing version.
@jochen-testingbot
jochen-testingbot merged commit 62d4778 into master Jul 15, 2026
7 checks passed
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.

1 participant