Skip to content

javachanges Output Contracts

1. Overview

This page explains which javachanges outputs are safe for automation, which ones are only intended for human review, and what the current output shape looks like.

Use it when you are:

  • writing CI scripts around javachanges
  • deciding whether to parse terminal output or read generated files
  • trying to understand which fields are intended to stay stable

2. Stability map

OutputIntended consumerStability guidance
manifest-field stdoutscripts and CIpreferred machine-readable interface
.changesets/release-plan.jsoncompatibility scripts and CImachine-readable when generated plan files are enabled
.changesets/release-plan.mdcompatibility pull request and merge request bodieshuman-readable, structure may evolve
.changesets/release-plan-backup.jsonlocal recovery before committing plan --apply truemachine-readable recovery snapshot, local workflow artifact
add --format json stdoutscripts and CImachine-readable changeset creation contract
version --format json stdoutscripts and CImachine-readable version/build metadata contract
release tag helpers --format json stdoutscripts and CImachine-readable release tag parsing contract
modules --format json stdoutscripts and CImachine-readable build/module discovery contract
status stdoutlocal operators and reviewershuman-oriented, do not parse rigidly
status --format json stdoutscripts and CImachine-readable release-plan status contract
next --format json stdoutscripts and CImachine-readable next-step recommendation contract
plan --format json stdoutscripts and CImachine-readable plan preview/apply contract
validate --format json stdoutscripts and CImachine-readable local release-readiness contract
render-vars stdoutlocal operatorshuman-oriented by default
render-vars --format json stdoutscripts and CImachine-readable JSON contract
doctor-local stdoutlocal operatorshuman-oriented by default
doctor-local --format json stdoutscripts and CImachine-readable JSON contract
doctor-platform stdoutlocal operatorshuman-oriented by default
doctor-platform --format json stdoutscripts and CImachine-readable JSON contract
sync-vars dry-run stdoutlocal operatorspreview text only, not a stable API
audit-vars stdoutlocal operatorshuman-oriented by default
audit-vars --format json stdoutscripts and CImachine-readable JSON contract
preflight --format json stdoutscripts and CImachine-readable publish-preflight contract
publish --format json stdoutscripts and CImachine-readable publish contract
gradle-publish --format json stdoutscripts and CImachine-readable Gradle publish contract
github-release-plan --format json stdoutscripts and CImachine-readable GitHub release-plan contract
github-tag-from-plan --format json stdoutscripts and CImachine-readable GitHub tag contract
github-release-from-plan --format json stdoutscripts and CImachine-readable GitHub Release contract
gitlab-release-plan --format json stdoutscripts and CImachine-readable GitLab release-plan contract
gitlab-tag-from-plan --format json stdoutscripts and CImachine-readable GitLab tag contract
gitlab-release --format json stdoutscripts and CImachine-readable GitLab Release contract

Practical rule:

  • if automation needs one value, prefer manifest-field
  • if automation needs fresh release metadata in CI, prefer --fresh true
  • if automation needs the compatibility manifest, read .changesets/release-plan.json
  • do not build CI logic around terminal headings, spacing, or localized labels

3. add --format json output

Use JSON output when a script needs to create a changeset and then read the created file path without parsing human text.

Command:

bash
mvn -q -DskipTests compile exec:java -Dexec.args="add --directory /path/to/repo --summary 'add release notes command' --release minor --no-interactive true --format json"

Current shape:

json
{
  "ok": true,
  "command": "add",
  "repository": "/path/to/repo",
  "createdChangeset": ".changesets/20260418-add-release-notes-command.md",
  "releaseLevel": "minor",
  "affectedPackages": ["core"],
  "summary": "add release notes command",
  "nextCommands": [
    "javachanges status --directory /path/to/repo",
    "javachanges next --directory /path/to/repo"
  ]
}

For CI, combine --format json with --no-interactive true so missing input is returned as a JSON error instead of waiting for stdin.

4. version --format json output

Use JSON output when automation needs the current revision together with the build model that produced it.

Command:

bash
mvn -q -DskipTests compile exec:java -Dexec.args="version --directory /path/to/repo --format json"

Current shape:

json
{
  "ok": true,
  "command": "version",
  "repository": "/path/to/repo",
  "buildTool": "maven",
  "versionFile": "pom.xml",
  "currentRevision": "0.1.0-SNAPSHOT",
  "releaseVersion": "0.1.0",
  "snapshot": true
}

The plain version command still prints only the raw current revision.

5. Release tag helper JSON output

Use JSON output when automation needs both the release version and release module from a tag.

Command:

bash
mvn -q -DskipTests compile exec:java -Dexec.args="release-version-from-tag --tag core/v1.2.3 --format json"

Current shape:

json
{
  "ok": true,
  "command": "release-version-from-tag",
  "tag": "core/v1.2.3",
  "releaseVersion": "1.2.3",
  "releaseModule": "core"
}

release-module-from-tag --format json returns the same fields with "command": "release-module-from-tag". For whole-repo tags like v1.2.3, releaseModule is null.

6. modules --format json output

Use JSON output when automation needs the exact detected module names before creating a changeset.

Command:

bash
mvn -q -DskipTests compile exec:java -Dexec.args="modules --directory /path/to/repo --format json"

Current shape:

json
{
  "ok": true,
  "command": "modules",
  "repository": "/path/to/repo",
  "buildTool": "maven",
  "versionFile": "pom.xml",
  "currentRevision": "0.1.0-SNAPSHOT",
  "modules": ["core", "api"],
  "nextCommands": [
    "javachanges add --directory /path/to/repo --modules core --summary \"describe the change\" --release patch",
    "javachanges add --directory /path/to/repo --modules all --summary \"describe the change\" --release patch"
  ]
}

For single-module repositories, nextCommands contains only the module-specific add command.

7. status output

status prints a human-readable release summary.

Current command:

bash
mvn -q -DskipTests compile exec:java -Dexec.args="status --directory /path/to/repo"

Current layout:

text
Repository: /path/to/repo
Current revision: 0.1.0-SNAPSHOT
Latest whole-repo tag: none
Pending changesets: 1
Release plan:
- Release type: minor
- Affected packages: core, api
- Release version: v0.2.0
- Next snapshot: 0.2.0-SNAPSHOT

Changesets:
- 20260418-add-release-notes.md [minor] (packages: core, api) Add release notes generation workflow.

Next steps:
  javachanges plan --directory /path/to/repo --apply true
  javachanges next --directory /path/to/repo

Important behavior:

  • if there are no pending changesets, the command prints Release plan: none
  • the human output ends with copyable next-step commands
  • the command currently prints English headings
  • visible change type text is omitted when the internal type is other

Automation guidance:

  • do not parse the bullet text or spacing
  • if you need releaseVersion or releaseLevel, read the manifest instead

8. manifest-field output

manifest-field is the narrowest machine-readable interface.

Command:

bash
mvn -q -DskipTests compile exec:java -Dexec.args="manifest-field --directory /path/to/repo --field releaseVersion --fresh true"

Current behavior:

  • reads .changesets/release-plan.json, or derives from current repository state with --fresh true
  • prints the requested field value
  • is intended for CI steps such as PR titles, tag names, or publish job metadata

Common fields:

FieldMeaning
releaseVersionRelease version without the leading v
nextSnapshotVersionNext snapshot version written back into pom.xml or gradle.properties
releaseLevelAggregated release level

9. .changesets/release-plan.json

This is the primary machine-readable release manifest.

Current shape:

json
{
  "releaseVersion": "0.2.0",
  "nextSnapshotVersion": "0.2.0-SNAPSHOT",
  "releaseLevel": "minor",
  "tagStrategy": "whole-repo",
  "tags": ["v0.2.0"],
  "releaseTargets": [
    {
      "module": null,
      "tag": "v0.2.0"
    }
  ],
  "generatedAt": "2026-04-19T13:29:58.202943+08:00",
  "changesets": [
    {
      "file": "20260418-add-release-notes.md",
      "release": "minor",
      "type": "other",
      "summary": "Add release notes generation workflow.",
      "modules": ["core", "api"]
    }
  ]
}

Field contract:

FieldMeaning
releaseVersionfinal release version without the v prefix
nextSnapshotVersionnext root snapshot version after plan application
releaseLevelaggregated release level across all included changesets
tagStrategyconfigured tag strategy, currently whole-repo or per-module
tags[]planned release tags
releaseTargets[].modulemodule associated with a planned tag, or null for whole-repo releases
releaseTargets[].tagplanned tag for this release target
generatedAtmanifest generation timestamp
changesets[].fileoriginal changeset filename
changesets[].releaserelease bump for that changeset
changesets[].typelegacy compatibility field, often other
changesets[].summarysummary derived from the changeset body or legacy metadata
changesets[].modulesaffected Maven artifactIds or Gradle project names

Important caveats:

  • the field is still called modules in JSON for compatibility, even though user-facing docs prefer packages
  • type is not the release bump; release is the meaningful release signal

10. .changesets/release-plan.md

This file is designed for human review and PR or MR descriptions.

Current structure:

md
## Release Plan 🚀

> Generated from `.changesets/*.md`. Review the plan, then merge when the release looks right.

| Field | Value |
| --- | --- |
| 🚦 Release type | `minor` |
| 📦 Affected packages | `core, api` |
| 🏷️ Release version | `v0.2.0` |
| 🔖 Tag strategy | `whole-repo` |
| 🧾 Planned tags | `v0.2.0` |
| 🔁 Next snapshot | `0.2.0-SNAPSHOT` |

## Included Changesets 📝

### ✨ Minor Changes

- **Add release notes generation workflow.**
  - 🚦 Release: `minor`
  - 📦 Packages: `core, api`

## What happens next ✅

- Merging this PR triggers the automatic tag push.
- Existing release workflows reuse the generated release metadata.

Guidance:

  • safe for PR bodies
  • not a stable machine interface
  • headings and sentence wording may evolve

11. render-vars output

render-vars shows which values will be treated as variables or secrets for GitHub or GitLab.

Current command:

bash
mvn -q -DskipTests compile exec:java -Dexec.args="render-vars --env-file env/release.env.local --platform github"

Current GitHub layout:

text
使用 env 文件: env/release.env.local
敏感值默认已打码。传入 --show-secrets true 可显示原值。

== GitHub Actions Variables ==
MAVEN_RELEASE_REPOSITORY_URL             https://repo.example.com/maven-releases/
MAVEN_SNAPSHOT_REPOSITORY_URL            https://repo.example.com/maven-snapshots/
MAVEN_RELEASE_REPOSITORY_ID              maven-releases
MAVEN_SNAPSHOT_REPOSITORY_ID             maven-snapshots

== GitHub Actions Secrets ==
MAVEN_REPOSITORY_USERNAME                PLACEHOLDER
MAVEN_REPOSITORY_PASSWORD                PLACEHOLDER
MAVEN_RELEASE_REPOSITORY_USERNAME        MISSING

Current GitLab layout:

text
使用 env 文件: env/release.env.local
敏感值默认已打码。传入 --show-secrets true 可显示原值。

== GitLab CI/CD Variables ==
GITLAB_RELEASE_TOKEN                     OPTIONAL (fallback: CI_JOB_TOKEN)
MAVEN_RELEASE_REPOSITORY_URL             https://repo.example.com/maven-releases/
MAVEN_REPOSITORY_USERNAME                PL****ER

Value states currently used:

StateMeaning
raw valuereal configured value
MISSINGkey is absent
PLACEHOLDERkey still uses replace-me style placeholder data
masked value like ab****yzsecret is present but hidden

Automation guidance:

  • treat this as an operator preview only
  • use the env file itself as the source of truth, not the rendered table text

JSON mode:

bash
mvn -q -DskipTests compile exec:java -Dexec.args="render-vars --env-file env/release.env.local --platform github --format json"

Current JSON shape:

json
{
  "ok": true,
  "command": "render-vars",
  "envFile": "env/release.env.local",
  "platform": "github",
  "showSecrets": false,
  "sections": [
    {
      "title": "GitHub Actions Variables",
      "entries": [
        {
          "label": "MAVEN_RELEASE_REPOSITORY_URL",
          "value": "https://repo.example.com/maven-releases/"
        }
      ]
    }
  ]
}

Contract notes:

  • stdout contains only the JSON object
  • exit code 0 means the command succeeded
  • sections[].entries[].label is the field name and value is the rendered value or status word

12. doctor-local output

doctor-local validates local runtime prerequisites, env completeness, CLI auth, and optional repository identifiers.

Current command:

bash
mvn -q -DskipTests compile exec:java -Dexec.args="doctor-local --env-file env/release.env.local"

Current section layout:

text
== 本机运行时 ==
java -version                            OK
./mvnw                                   MISSING
mvn                                      OK
Maven command                           mvn (system)
mvn -q -version                         OK

== 本地 env 文件 ==
env/release.env.local                    OK
MAVEN_REPOSITORY_USERNAME                PLACEHOLDER

== 平台 CLI ==
gh                                       OK
gh auth status                           FAILED
glab                                     MISSING

== 仓库标识 ==
GITHUB_REPO                              NOT_SET
GITLAB_REPO                              NOT_SET

Current status words:

StatusMeaning
OKthe check passed
MISSINGthe required tool, file, or value does not exist
FAILEDthe command exists but the validation failed
SKIPPEDa dependent check was skipped
PLACEHOLDERthe value still uses placeholder data
OPTIONALthe key is absent but optional
NOT_SETan optional repo identifier flag was not provided
INVALIDa provided repository identifier is malformed

Important current behavior:

  • the implementation prefers ./mvnw when it exists
  • if the wrapper is absent, it falls back to a system-installed mvn
  • failure ends with a human-readable checklist and a thrown error

JSON mode:

bash
mvn -q -DskipTests compile exec:java -Dexec.args="doctor-local --env-file env/release.env.local --format json"

Current JSON behavior:

  • stdout contains only one JSON object
  • exit code 0 means all local checks passed
  • non-zero exit code means at least one required check failed
  • the payload includes sections, and may include suggestions plus final error

13. doctor-platform and audit-vars

doctor-platform validates local env values and authenticated platform access before sync or audit work.

Current section layout:

text
使用 env 文件: env/release.env.local

== 本地 env 检查 ==
MAVEN_RELEASE_REPOSITORY_URL             OK
MAVEN_REPOSITORY_USERNAME                PLACEHOLDER

== GitHub CLI 检查 ==
gh                                       OK
gh auth status                           FAILED

audit-vars compares local values with remote platform state.

Current audit result words:

StatusMeaning
MATCHremote value matches local value
PRESENTremote secret exists
REMOTE_ONLYremote value exists but local input is absent or placeholder
SKIPPEDnothing meaningful to compare
MISSING_REMOTElocal real value exists but remote value is missing
MISMATCHlocal and remote values differ

doctor-platform --format json behaves similarly to doctor-local --format json:

  • stdout contains only one JSON object
  • exit code 0 means the env and selected platform checks passed
  • non-zero exit code means auth, repo identifiers, or required env values failed validation
  • the payload includes platform, sections, and optional final error

audit-vars --format json now provides a machine-readable contract as well:

  • stdout contains only one JSON object
  • exit code 0 means all audited remote values matched the expected local state
  • non-zero exit code means at least one audited item ended in MISSING_REMOTE or MISMATCH, or a platform precondition failed
  • the payload includes platform, sections, and optional final error

GitLab-specific additions:

  • doctor-platform --platform gitlab --format json now includes protected-variable and protected-branch sections
  • if protected variables exist but the configured snapshotBranch is not protected, the command fails explicitly instead of silently passing

14. Publish And GitLab Release JSON

preflight, publish, gitlab-release-plan, gitlab-tag-from-plan, and gitlab-release now expose a shared machine-readable top-level contract.

Current common fields:

FieldMeaning
okwhether the command succeeded
commandcommand name
actionaction taken or planned
skippedwhether the command intentionally skipped work
reasonhuman-readable reason for skip, dry-run, or success summary
releaseVersionresolved release version without extra parsing
effectiveVersionactual version passed into the publish flow, including snapshot mode decisions
releaseModuleresolved module or null for whole-repo work
tagrelease tag when relevant
tagStrategyresolved tag strategy when relevant
tagsresolved release tag list when relevant
releaseNotesFilegenerated or consumed notes file path when relevant
projectIdGitLab project id when relevant
snapshotVersionModesnapshot version mode when the command is operating on a snapshot
snapshotBuildStampAppliedwhether javachanges applied a stamped snapshot build suffix

Example:

json
{
  "ok": true,
  "command": "gitlab-release",
  "action": "create-release",
  "skipped": false,
  "reason": "Created GitLab Release.",
  "releaseVersion": "1.2.3",
  "effectiveVersion": "1.2.3",
  "releaseModule": "core",
  "tag": "core/v1.2.3",
  "tagStrategy": null,
  "tags": null,
  "releaseNotesFile": "/path/to/repo/target/release-notes.md",
  "projectId": "12345",
  "execute": true,
  "dryRun": false,
  "snapshotVersionMode": null,
  "snapshotBuildStampApplied": false
}

Snapshot-specific example:

json
{
  "ok": true,
  "command": "preflight",
  "action": "publish-snapshot",
  "skipped": false,
  "reason": "Preflight checks passed.",
  "releaseVersion": "1.2.3-SNAPSHOT",
  "effectiveVersion": "1.2.3-SNAPSHOT",
  "releaseModule": null,
  "tag": null,
  "releaseNotesFile": null,
  "projectId": null,
  "execute": false,
  "dryRun": true,
  "snapshotVersionMode": "plain",
  "snapshotBuildStampApplied": false
}

15. Automation recommendations

For CI and scripting:

  1. use platform release-plan commands with --write-plan-files false for normal CI release branches
  2. read releaseVersion with manifest-field --fresh true; use the compatibility manifest only when you intentionally generated one
  3. if scripts need structured diagnostics, use render-vars --format json, doctor-local --format json, doctor-platform --format json, or audit-vars --format json
  4. use diagnostic JSON only for environment validation flows

Avoid:

  • parsing aligned column spacing
  • parsing localized headings like == 本地 env 检查 ==
  • depending on the exact prose of failure summaries
NeedDocument
Full command listCLI Reference
Generated manifest fieldsRelease Plan Manifest
Practical command sequencesCommand Cookbook
Failure diagnosisTroubleshooting Guide

Released under the Apache-2.0 License.