Skip to content

ci(release): publish the Java client to Maven Central from the core v* tag - #738

Merged
HuiJun merged 7 commits into
developfrom
feature/release-java-client-on-core-tag
Sep 30, 2026
Merged

HuiJun merged 7 commits into
developfrom
feature/release-java-client-on-core-tag

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Targets develop. It was stacked on #735, which has merged, and #739 (Rust) is stacked on this PR.

What and why

The Java client is now published the way the Python and Node clients are: from the core v* tag, in the core release workflow, at the core's version. Before this, the Java client had a release Maven profile but nothing in CI published it, and the docs planned a separate opensysml-java-v* tag that was never used.

Version lock

  • client/java/pom.xml is set to 0.9.0, the version _version.py declares on develop (no -SNAPSHOT). Both modules' <parent><version> match it, and so do the two in-repo consumers that build the client from the checkout: editors/cameo/pom.xml (opensysml.client.version) and the opensysml-client dependency in editors/syson/backend/pom.xml. The editors' own project versions are unchanged. The release branch bumps all of these alongside _version.py; the release checklist in releasing.md now says so.
  • check_version.py --java reads the pom's own <version> and checks it against _version.py (same SemVer→PEP 440 translation as --node, so 0.9.0-rc1 ↔ 0.9.0rc1). When a tag is given, the tag must spell the pom version exactly. -SNAPSHOT is rejected. The Node and Java checks share one helper, _client_version, and all Node messages are unchanged. --node and --java are mutually exclusive.
  • build-python-package calls --java next to --node, so a pom that disagrees fails the release before anything is built.
  • A pytest check that every in-repo reference to the client version (the module parents, cameo, syson) equals the parent pom's version.
  • scripts/ci-changed-areas.sh: a change to client/java/pom.xml now also runs the Python suite, where the lockstep tests live (same as client/node/package.json). The test cases were updated to match; two-clients legitimately gains python. The editor poms get the same trigger in ci(release): publish the Rust client to crates.io from the core v* tag #739.

autoPublish=true (owner decision). The central-publishing-maven-plugin profile now sets <autoPublish>true</autoPublish> and <waitUntil>published</waitUntil>. Per Sonatype's docs, waitUntil defaults to validated and published requires autoPublish. With these settings the build blocks until Central reports the deployment published, and reports any failure, so a green job means the version is on Central.

publish-maven job (java-executor). It requires Publish GitHub release and Java client tests, and sits beside publish-pypi and publish-npm, independent of both. java-test was added to the release workflow (requires: *go-suite), and Publish GitHub release now also requires it.

The credentials come from the restricted org context Maven Central (context: ["Maven Central"] on the workflow entry; context names are matched exactly). Whoever pushes the tag must be allowed to use it, as with PyPI and npm.

Everything that can fail runs before the upload:

  1. The tag must equal v<pom version> (read with mvn help:evaluate); a -SNAPSHOT version is refused.
  2. CENTRAL_TOKEN_USERNAME, CENTRAL_TOKEN_PASSWORD, GPG_PRIVATE_KEY and GPG_PASSPHRASE must all be non-empty. Only the missing variable's name is printed.
  3. Refuse a version already on Central: repo1 is checked for both opensysml-parent and opensysml-client. HTTP 200 → refuse, 404 → proceed, any other response → fail rather than guess.
  4. gpg --batch --import the ASCII-armoured key, then test-sign with the passphrase via --passphrase-fd. An expired key or a wrong passphrase fails here.
  5. ~/.m2/settings.xml gets a central server whose credentials are ${env.…} references, so the token is never written to disk.
  6. MAVEN_GPG_PASSPHRASE=… mvn -B -Prelease deploy -pl opensysml-client -am -DskipTests. Tests are skipped because java-test ran them on this revision in the same workflow (the same split as publish-pypi). -am brings the parent pom, which the client's pom names, so Central needs it too. maven-gpg-plugin 3.2.7 reads the passphrase from MAVEN_GPG_PASSPHRASE (its passphraseEnvName default since 3.2.0), and that alone works in batch mode. A comment on this step says never to run it with -X/debug output, because the settings interpolation would print the token.

Pre-releases. Central has no test registry, so a pre-release tag publishes an ordinary, permanent version, which Maven orders before the release. This is documented in releasing.md.

Docs. The releasing.md section "Releasing the Java client to Maven Central" is rewritten: the core tag, the lockstep version, the four variables in the Maven Central context, GPG key expiry and rotation, immutability, pre-releases, the job's steps in order, and what can be rerun after a partial failure. Also updated: the releasing.md intro, the release checklist, the post-release Central check, the root README, client/java/README.md, the guide, the Java API reference, the roadmap and the syson design note. One changelog fragment: changes/unreleased/java-client-maven-release.added.md.

How it was verified

  • pytest tests/test_check_version.py tests/test_version.py passes, including 9 new Java tests; the existing tests are unchanged.
  • bash scripts/ci-changed-areas-test.sh passes.
  • mvn -B -f client/java/pom.xml install -Dopensysml.requireService=true passes (297 tests, 0 failures).
  • The Java conformance run passes (292 passed, 0 failed, 10 skipped).
  • The cameo and syson builds that consume the client build successfully (-DskipTests package).
  • Signing was checked with a throwaway passphrase-protected key: the job's test-sign step succeeds with the right passphrase and fails with a wrong one. MAVEN_GPG_PASSPHRASE=… mvn -B -Prelease verify -pl opensysml-client -am -DskipTests signs 4 files, and gpg --verify reports a good signature on the client jar and on the parent pom. No deploy was run.
  • gpg is present in cimg/openjdk:17.0; the apt-get install is only a fallback.
  • circleci config validate, python3 scripts/changelog.py check, python3 scripts/check-doc-links.py (0 broken), make docs-check, gofmt -l ., go vet ./... and go test ./tests/hygiene/... all pass.

Nothing was published.

Checklist

  • make test and make lint pass locally (the affected suites above)
  • Tests added or updated for the change
  • Documentation extended where it already covers the surface (see CONTRIBUTING.md)
  • Changelog entry added as changes/unreleased/<slug>.<section>.md, not as an edit to CHANGELOG.md
  • baselines regenerated and make docs-counts run if a gate count moved (no gate count moved)
  • No internal work-item labels (waves, slices, F4, K5) in the body, docs, or changelog

Link to Devin session: https://nasa-jpl-demo.devinenterprise.com/sessions/50e350d0913749039440892f390a0f90
Open in Devin Desktop: https://nasa-jpl-demo.devinenterprise.com/desktop/session/50e350d0913749039440892f390a0f90?variant=devin
Requested by: @HuiJun

devin-ai-integration Bot and others added 4 commits September 30, 2026 02:22
…entral

The pom and its consumers follow _version.py in lockstep, checked by
check_version.py --java and a pytest gate that also runs on a
manifest-only change; the release profile publishes the validated
deployment itself and waits until it is on Central.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
publish-maven runs in the release workflow on the v* tag, beside
publish-pypi and publish-npm, signing and uploading at the core version
from the restricted maven-central context.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ording

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

Co-Authored-By: jason.han <hanhuijun@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

@devin-ai-integration
devin-ai-integration Bot marked this pull request as ready for review September 30, 2026 02:55
Co-Authored-By: jason.han <hanhuijun@gmail.com>
Base automatically changed from feature/release-node-client-on-core-tag to develop September 30, 2026 03:10

@devin-ai-integration devin-ai-integration Bot left a comment

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.

Devin Review found 2 new potential issues.

1 flag not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

emit python "$( { [[ "$service" = true ]] || matches "$python_pattern" || matches '^client/node/package\.json$'; } && echo true || echo false)"
# The client-manifest/Python version lockstep tests live in the Python suite,
# so the Node and Java manifests have to run it too.
emit python "$( { [[ "$service" = true ]] || matches "$python_pattern" || matches '^client/node/package\.json$' || matches '^client/java/pom\.xml$'; } && echo true || echo false)"

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.

🟡 Editor version drift escapes CI

When only an editor's client version changes, python remains disabled and its lockstep test never runs. An editor can then build against an older published client while the Java parent names a different version.

Learn more

The Python suite contains test_every_in_repo_reference_names_the_poms_version, which checks the two editor dependencies against the Java parent. The area filter enables that suite for changes to the Java parent, but not for changes to the editor manifests themselves. If an editor selects an existing older artifact, Maven can resolve it and the editor build can pass without detecting the mismatch.

Example: The parent declares 0.9.0, and a pull request changes only the SysON dependency to published version 0.8.0. The SysON build can use 0.8.0; the Python lockstep assertion is skipped.

Recommended fix: Enable the Python area when either editor manifest changes, and add corresponding cases to ci-changed-areas-test.sh.

Suggested change
emit python "$( { [[ "$service" = true ]] || matches "$python_pattern" || matches '^client/node/package\.json$' || matches '^client/java/pom\.xml$'; } && echo true || echo false)"
emit python "$( { [[ "$service" = true ]] || matches "$python_pattern" || matches '^client/node/package\.json$' || matches '^client/java/pom\.xml$' || matches '^editors/cameo/pom\.xml$' || matches '^editors/syson/backend/pom\.xml$'; } && echo true || echo false)"

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

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.

You're right: a change to either editor's pom alone skips the Python suite, which is where the lockstep test lives. This PR was accepted as it stands, so I'm fixing it in the stacked follow-up that publishes the Rust client, which changes this same line anyway. There, editors/cameo/pom.xml and editors/syson/backend/pom.xml will also enable the Python area, with test cases for both.

Comment thread .circleci/config.yml
Co-Authored-By: jason.han <hanhuijun@gmail.com>
@HuiJun
HuiJun merged commit 8709482 into develop Sep 30, 2026
23 checks passed
@HuiJun
HuiJun deleted the feature/release-java-client-on-core-tag branch September 30, 2026 04:36
@devin-ai-integration devin-ai-integration Bot mentioned this pull request Sep 30, 2026
3 of 6 tasks
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