Skip to content

[java] Publish complete GitHub release assets for the Maven proxy - #1543

Open
brandur wants to merge 4 commits into
masterfrom
brandur-java-github-releases
Open

brandur wants to merge 4 commits into
masterfrom
brandur-java-github-releases

Conversation

@brandur

@brandur brandur commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

🤖 Publish Java releases through GitHub and the public River Maven proxy. Each release contains nine canonical files: the shared parent POM plus library and CLI POMs, thin JARs, sources, and Javadoc. Sonatype/signing is optional.

Remove the CLI's shaded -all.jar. Users can install river-java with JBang or use Maven to download a portable directory of runtime JARs. Both paths retain Postgres and SQLite support; dependencies are cached separately instead of duplicated inside every release. Add main-class/version metadata to the thin CLI and test it with its runtime dependencies.

java/bin/github-release.py provides three release steps:

  • prepare builds/tests against a temporary file repository, checks archives, and stages nine artifacts with a SHA-256 manifest.
  • upload requires a clean build and matching local/remote tag, creates or resumes a draft, and verifies asset hashes. It refuses mismatches and published releases. Creation and publication use --latest=false so Java never replaces the Go Latest release.
  • verify checks every proxy artifact/checksum, resolves dependencies into a fresh Maven cache, confirms repository provenance, compiles/runs a consumer, and runs thin CLI version and SQLite migration checks.

Document executable release instructions for humans and local agents using gh auth login. Java CI exercises release tooling and artifact staging. Existing published alpha.1 assets remain unchanged. Verification waits for the proxy’s scheduled import; dev/local setup links to explicit refresh instructions.

Merge after https://github.com/riverqueue/gomodproxy-workers/pull/100 is deployed to production; installation instructions use https://riverqueue.com/maven.

Validation:

  • make check/java/github-release test/java/tools lint/java/tools: passed, including 513 Java/CLI tests, 10 Python tests, and archive checks. The nine staged artifacts total 869,774 bytes (0.83 MiB).
  • Release verification passed against a local HTTP repository with fresh Maven caches and the staged manifest; the exact Maven README workflow and JBang also ran the new thin CLI successfully.
  • JBang resolved the existing alpha.1 thin CLI through the dev proxy and ran SQLite migrations up/list/down. That older thin JAR reports development for its version; new builds carry the version metadata.
  • make test TEST_DATABASE=sqlite and make lint: passed.

@brandur
brandur requested a review from bgentry October 25, 2026 19:31

@bgentry bgentry left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 Reviewed all seven changed files and the supporting build/release configuration, with particular attention to artifact integrity, tag binding, credentials, subprocesses, and CI permissions. I did not identify a confirmed security vulnerability. Two release-workflow issues are noted inline.

Comment thread java/docs/development.md Outdated
7. Publish the verified draft. Alpha, beta, and RC versions are marked as prereleases automatically:

```sh
gh release edit "java/v$VERSION" --repo riverqueue/river --draft=false

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 [P2] Prevent stable Java releases from replacing the repository's Latest release

For a stable version such as 0.1.0, this publish command omits --latest=false. GitHub's release-update API defaults make_latest to true for newly published releases, so publishing the Java draft can replace the Go release at the repository's /releases/latest endpoint and Latest badge. The uploader only supplies --latest=false in its prerelease creation branch, which does not protect this stable publication step. Please pass --latest=false here and in the publish command printed by upload(); covering the stable path would catch this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed!

Comment thread java/bin/github_release_test.py Outdated
self.assertEqual(
create[:4], ["gh", "release", "create", "java/v" + self.version]
)
for flag in ("--draft", "--verify-tag", "--prerelease", "--latest=false"):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 [P2] Keep the prerelease fixture independent of the release version bump

The documented version-update command replaces 0.1.0-alpha.1 throughout java/, including self.version in this test module. When releasing a stable version such as 0.1.0, this test then supplies a stable manifest but still requires --prerelease and --latest=false, so the release PR fails test/java/tools. I reproduced this by applying that replacement in memory: the current ten tests pass, while the stable-version copy fails this assertion. Use a fixed synthetic prerelease fixture that the release bump will not replace (and a separate stable-version case), or explicitly exclude these release-tool fixtures from the bump.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed!

@bgentry bgentry left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 I’d like to revisit making the shaded CLI JAR a required release asset. In the existing java/v0.1.0-alpha.1 release, the ten assets total 16,907,645 bytes (16.12 MiB). The river-cli-0.1.0-alpha.1-all.jar alone is 16,036,333 bytes (15.29 MiB, 94.8%); the other nine assets combined are 871,312 bytes (0.83 MiB). For scale, the ordinary river JAR is 218,795 bytes and the thin river-cli JAR is 12,821 bytes.

I inspected the published -all.jar as a ZIP. Approximately 11.20 MiB compressed is SQLite native libraries for multiple operating systems/architectures; 2.24 MiB is Jackson; 0.98 MiB is the PostgreSQL driver; River's own classes are about 0.20 MiB. This is mostly a cross-platform dependency bundle, not 15 MiB of River source. Xerial's SQLite JDBC packaging explains why its default JAR carries native binaries for many platforms and documents its without-natives and platform-specific classifier options.

My preferred change for this PR is to publish the nine POM/thin JAR/sources/Javadoc assets as the normal Maven release, and make the -all.jar an explicit, optional standalone CLI distribution rather than an entry in the required artifact_files()/manifest/upload/verification set. If we do not ship that optional distribution by default, each release's archived and mirrored bytes fall by about 95%. This fits Maven's normal model: the main JAR and POM describe the artifact and its dependencies, while an attached shaded executable is a convenience for java -jar, not a requirement for dependency consumers (Maven Shade documentation). It also keeps our release upload, verification, storage, and mirror work proportional to the actual library artifacts. At this scale I do not expect the R2 storage bill alone to be alarming; the concern is making a large duplicate bundle mandatory on every release.

There are real tradeoffs to handle explicitly:

  • A thin CLI JAR cannot replace today's one-file java -jar instructions by itself. If that workflow is a supported product requirement, retain a separate standalone distribution or provide a dependency-resolving launcher, and update the docs and CLI smoke test accordingly. Keeping a universal standalone JAR is defensible if its convenience is worth the roughly 15 MiB per release; I would still avoid making it a prerequisite for publishing the normal Maven artifacts.
  • Removing -all.jar from the release does not make Maven CLI downloads 15 MiB smaller: the CLI POM still declares sqlite-jdbc and PostgreSQL, and Xerial's default SQLite dependency includes the native bundle. Do not simply remove SQLite or strip the shaded JAR with minimizeJar; SQLite operation and reflectively loaded JDBC/services need to keep working. If client download size becomes important, a separate follow-up could evaluate Xerial's platform-specific native classifiers or optional driver variants, with tests on the supported platforms and both databases.

Could we make the normal release complete without -all.jar and decide separately whether the one-file CLI distribution is worth publishing?

@brandur

brandur commented Oct 26, 2026

Copy link
Copy Markdown
Contributor Author

Okay, getting rid of that -all.jar is a good idea. I removed it and we went from 16.12 MiB to 0.83 MiB.

The CLI turns out to be a bit problematic, but luckily there's reasonably easy way to manage this separately with another program called JBang. Installation becomes this:

jbang app install --name river-java --java 21 \
  --java-options=--enable-native-access=ALL-UNNAMED \
  --repos https://riverqueue.com/maven \
  --main com.riverqueue.cli.MigrationCli \
  com.riverqueue:river-cli:0.1.0-alpha.1

export PATH="$HOME/.jbang/bin:$PATH"

Then use is this:

export DATABASE_URL=postgres://localhost/myapp

river-java migrate-list
river-java migrate-up --dry-run
river-java migrate-up

You can specify --name river in the install command instead to make it river migrate-list instead of river-java.

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