Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/actions/setup-java/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Set up Java workspace
description: Install a supported JDK and cache Maven dependencies for the Java workspace.

inputs:
java-version:
default: "25"
description: JDK version to use.

runs:
using: composite
steps:
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: ${{ inputs.java-version }}
cache: maven
cache-dependency-path: "java/**/pom.xml"
11 changes: 10 additions & 1 deletion .github/workflows/conformance.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Conformance

# The Rust and JavaScript workflows run only when their own files change, but
# The port workflows run only when their own files or dependencies change, but
# their fixture tests compare against values generated from River's Go code.
# This job closes that gap: when Go code, SQL queries the generator reads, or
# the generator itself changes, it regenerates the fixtures and runs only the
Expand All @@ -11,6 +11,7 @@ on:
- master
paths:
- ".github/workflows/conformance.yaml"
- "Makefile"
- "**.go"
- "**/go.mod"
- "**/go.sum"
Expand All @@ -20,6 +21,7 @@ on:
pull_request:
paths:
- ".github/workflows/conformance.yaml"
- "Makefile"
- "**.go"
- "**/go.mod"
- "**/go.sum"
Expand Down Expand Up @@ -69,9 +71,16 @@ jobs:

- uses: ./.github/actions/setup-js

- uses: ./.github/actions/setup-java
with:
java-version: "21"

# Each target generates the fixtures before running its tests.
- name: Rust fixture tests
run: make test/rust/conformance

- name: JavaScript fixture tests
run: make test/js/conformance

- name: Java fixture tests
run: make test/java/conformance
125 changes: 125 additions & 0 deletions .github/workflows/java.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
name: Java

# Filter the workflow so unrelated changes don't add skipped jobs to CI.
on:
push:
branches:
- master
paths:
- ".github/actions/setup-java/**"
- ".github/workflows/java.yaml"
- "Makefile"
- "conformance/**"
- "java/**"
- "riverdriver/riverpgxv5/migration/**"
- "riverdriver/riversqlite/migration/**"
pull_request:
paths:
- ".github/actions/setup-java/**"
- ".github/workflows/java.yaml"
- "Makefile"
- "conformance/**"
- "java/**"
- "riverdriver/riverpgxv5/migration/**"
- "riverdriver/riversqlite/migration/**"
workflow_dispatch:

concurrency:
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
group: ${{ github.workflow }}-${{ github.ref }}

permissions:
contents: read

jobs:
quality:
name: Quality and package archives
runs-on: ubuntu-latest
timeout-minutes: 15

steps:
- uses: actions/checkout@v6
with:
persist-credentials: false

- uses: ./.github/actions/setup-java

- uses: actions/setup-go@v6
with:
go-version-file: go.work

- name: Compile and check formatting
run: make lint/java

- name: Test Go maintenance tools
run: make test/java/tools

- name: Verify canonical migration mirror
run: make verify/java-migrations

- name: Check publishable archives
run: make check/java/package

java_versions:
name: Test (Java ${{ matrix.java-version }}, SQLite)
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
java-version: ["21", "25"]

steps:
- uses: actions/checkout@v6
with:
persist-credentials: false

- uses: ./.github/actions/setup-java
with:
java-version: ${{ matrix.java-version }}

- uses: actions/setup-go@v6
with:
go-version-file: go.work

- name: Unit, SQLite, and executable CLI tests
run: make test/java/sqlite

postgres:
name: Test (PostgreSQL ${{ matrix.postgres-version }})
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
postgres-version: [14, 15, 16, 17, 18]
env:
RIVER_TEST_DATABASE_URL: postgres://postgres:postgres@127.0.0.1:5432/river_test?sslmode=disable

services:
postgres:
image: postgres:${{ matrix.postgres-version }}
env:
POSTGRES_DB: river_test
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd "pg_isready -U postgres -d river_test"
--health-interval 2s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432

steps:
- uses: actions/checkout@v6
with:
persist-credentials: false

- uses: ./.github/actions/setup-java

- uses: actions/setup-go@v6
with:
go-version-file: go.work

- name: PostgreSQL client, worker, and migration tests
run: make test/java/postgres
62 changes: 61 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
.DEFAULT_GOAL := help

SQLC ?= sqlc
MVN ?= mvn

.PHONY: check/modzip
check/modzip: ## Check that no Go module zip includes fixtures, testdata, or the Rust or JS ports
check/modzip: ## Check that no Go module zip includes fixtures, testdata, or another language's port
go run ./conformance/cmd/checkmodzip ./go.work

.PHONY: db/reset
Expand All @@ -24,6 +25,7 @@ db/reset/test: ## Drop, create, and migrate test databases
.PHONY: generate
generate: ## Generate generated artifacts
generate: generate/fixtures
generate: generate/java-migrations
generate: generate/js-migrations
generate: generate/migrations
generate: generate/rust-migrations
Expand All @@ -35,6 +37,10 @@ generate: generate/sqlc
generate/fixtures: ## Generate cross-language conformance fixtures from River's Go implementation
go run ./conformance/cmd/generatefixtures

.PHONY: generate/java-migrations
generate/java-migrations: ## Sync database migrations to Java
go run ./java/bin/sync-migrations/main.go

.PHONY: generate/js-migrations
generate/js-migrations: ## Sync database migrations to JavaScript
pnpm -C js run generate:migrations
Expand Down Expand Up @@ -97,6 +103,12 @@ define lint-target
endef
$(foreach mod,$(submodules),$(eval $(call lint-target,$(mod))))

# Java's module boundary excludes it from Go package discovery. Pass the tool
# files explicitly so they use this workspace's Go version and test dependencies.
lint::
golangci-lint run --fix ./java/bin/check-packages/*.go
golangci-lint run --fix ./java/bin/sync-migrations/*.go

# Rust targets are separate from `lint` and `test` so Go-only contributors and
# the Go CI jobs do not need a Rust toolchain; the Rust workflow runs them.
.PHONY: lint/rust
Expand All @@ -107,6 +119,15 @@ lint/rust: ## Run Rust formatting and clippy checks, including single-backend bu
cd rust && cargo clippy -p riverqueue -p riverqueue-migrate -p riverqueue-cli -p riverqueue-test --no-default-features --features sqlite --all-targets --locked -- -D warnings
cd rust && $(RUST_POSTGRES_TESTS_ENV) cargo clippy -p riverqueue -p riverqueue-migrate --all-targets --all-features --locked -- -D warnings

# Java targets stay separate so Go-only contributors do not need a JDK or Maven.
.PHONY: build/java
build/java: ## Build the Java library, CLI, and development adapter (JDK 21+)
$(MVN) --batch-mode --no-transfer-progress -f java/pom.xml package -DskipTests

.PHONY: lint/java
lint/java: ## Compile Java and check formatting
$(MVN) --batch-mode --no-transfer-progress -f java/pom.xml verify -DskipTests

# JavaScript targets, like the Rust ones, are separate from `lint` and `test`
# and need Node.js 26 and pnpm; they delegate to the workspace's own scripts.
# Run `pnpm -C js install` first.
Expand All @@ -124,6 +145,7 @@ lint/js: build/js

.PHONY: test
test:: ## Run tests (TEST_DATABASE=all, postgres, or sqlite)
test:: test/java/tools
define test-target
test:: ; cd $1 && go test ./... -timeout 2m $(if $(filter %/riverdriver/riverdrivertest,$1),$(driver_test_flags))
endef
Expand All @@ -144,6 +166,34 @@ RUST_POSTGRES_TESTS_ENV = RUSTFLAGS="$$RUSTFLAGS --cfg river_postgres_tests" \
RUSTDOCFLAGS="$$RUSTDOCFLAGS --cfg river_postgres_tests" \
CARGO_TARGET_DIR="$${CARGO_TARGET_DIR:-$(CURDIR)/rust/target}/postgres-tests"

.PHONY: test/java
test/java: ## Run Java tests, executable CLI tests, and formatting checks
test/java: generate/fixtures verify/java-migrations
test/java: test/java/tools
$(MVN) --batch-mode --no-transfer-progress -f java/pom.xml verify

# Pure fixture comparisons need neither PostgreSQL nor the legacy adapter.
.PHONY: test/java/conformance
test/java/conformance: ## Run Java tests that check Go-generated conformance fixtures
test/java/conformance: generate/fixtures
$(MVN) --batch-mode --no-transfer-progress -f java/pom.xml -pl river test -Dgroups=conformance

.PHONY: test/java/postgres
test/java/postgres: ## Run Java tests with PostgreSQL client and worker coverage (requires RIVER_TEST_DATABASE_URL)
test/java/postgres: generate/fixtures verify/java-migrations
@test -n "$$RIVER_TEST_DATABASE_URL" || { echo "RIVER_TEST_DATABASE_URL is required" >&2; exit 1; }
$(MVN) --batch-mode --no-transfer-progress -f java/pom.xml verify -Driver.test.database=postgres

.PHONY: test/java/sqlite
test/java/sqlite: ## Run Java unit, SQLite, and executable CLI tests without PostgreSQL
test/java/sqlite: generate/fixtures verify/java-migrations
$(MVN) --batch-mode --no-transfer-progress -f java/pom.xml verify -Driver.test.database=sqlite -DexcludedGroups=postgres

.PHONY: test/java/tools
test/java/tools: ## Test Java's Go maintenance tools
go test ./java/bin/check-packages/*.go
go test ./java/bin/sync-migrations/*.go

# PostgreSQL integration tests need RIVER_RUST_DATABASE_URL. Without it
# test/rust still runs unit, doc, and SQLite integration tests, and fails in CI
# so a missing URL cannot turn the PostgreSQL suite into a silent pass.
Expand Down Expand Up @@ -218,6 +268,11 @@ doc/rust: ## Build Rust API documentation, compiled examples, and doctests for e
doc/rust/docsrs: ## Build Rust API documentation as docs.rs does (nightly toolchain, `--cfg docsrs`)
cd rust && RUSTDOCFLAGS="--cfg docsrs -D warnings" CARGO_TARGET_DIR="$${CARGO_TARGET_DIR:-target}/docsrs" cargo +nightly doc -p riverqueue -p riverqueue-migrate -p riverqueue-test --all-features --no-deps --locked

.PHONY: check/java/package
check/java/package: ## Build and verify publishable Maven archives without publishing
check/java/package: build/java
go run ./java/bin/check-packages/main.go

.PHONY: check/js/dependencies
check/js/dependencies: ## Audit JavaScript advisories and production dependency licenses
pnpm -C js audit
Expand Down Expand Up @@ -304,11 +359,16 @@ update-mod-version: ## Update River packages in all submodules to $VERSION

.PHONY: verify
verify: ## Verify generated artifacts
verify: verify/java-migrations
verify: verify/js-migrations
verify: verify/migrations
verify: verify/rust-migrations
verify: verify/sqlc

.PHONY: verify/java-migrations
verify/java-migrations: ## Verify Java migrations match the canonical migrations
go run ./java/bin/sync-migrations/main.go -check

.PHONY: verify/js-migrations
verify/js-migrations: ## Verify JavaScript migrations match the canonical migrations
pnpm -C js run verify:migrations
Expand Down
4 changes: 2 additions & 2 deletions conformance/cmd/checkmodzip/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ const conformanceModulePath = "github.com/riverqueue/river/conformance"

// disallowedPathPattern matches paths, relative to a module's root, that must
// never be published: fixture and testdata directories, JSON files, and the
// conformance, JavaScript, and Rust trees.
var disallowedPathPattern = regexp.MustCompile(`(^|/)(fixtures?|testdata)/|\.json$|^(conformance|js|rust)/`)
// conformance, Java, JavaScript, and Rust trees.
var disallowedPathPattern = regexp.MustCompile(`(^|/)(fixtures?|testdata)/|\.json$|^(conformance|java|js|rust)/`)

func main() {
if len(os.Args) != 2 {
Expand Down
5 changes: 5 additions & 0 deletions java/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
target/
.idea/
*.iml
.conformance/
__pycache__/
Loading
Loading