Skip to content

[Java] Cease using maven-release-plugin due to its opinionated mutations of git history #2579

Description

@edburns

High level rationale

Java’s Maven release is the only SDK publication process that treats releasing as a source-control mutation: it uses privileged automation to push multiple versioning commits and a tag directly to main before publication completes. Steve Sanderson questioned why the workflow must push directly to main instead of producing a PR, while Stephen Toub similarly objected to the direct push and asked whether it should be submitted as a PR. Their objections center on the branch-protection bypass, inconsistency with the other SDKs, and resulting failure and rollback complexity, favoring a PR-based or otherwise independently retryable CI publication flow.

Context

Job-to-be-done

Make the Java release pipeline a read-only consumer of the commit being released, consistent with the other language publishers. A Java release must derive its version from the shared release workflow, build and publish from an immutable source commit, and complete without committing to or otherwise modifying main.

The implementation must:

  • Replace the use of maven-release-plugin and release:prepare with CI-friendly Maven versioning, using the version supplied by the release workflow only within the build workspace. No release or next-development version change may be committed to the repository.
  • Update .github/workflows/java-publish-maven.yml so it checks out an explicitly resolved source SHA rather than creating a release commit and using a pre-publication java/vX.Y.Z tag as its source.
  • Remove the documentation commit, the release-version commit, the next-SNAPSHOT commit, and every direct push to main from .github/workflows/java-publish-maven.yml. Documentation version updates must be made through the normal reviewed-PR process rather than as a side effect of publishing.
  • Remove the JAVA_RELEASE_TOKEN preflight check, privileged checkout, contents: write requirement, and repository-ruleset bypass dependency. Maven Central and GPG credentials may remain because they authorize package publication rather than repository mutation.
  • Remove the guarded rollback-release job and the commit/tag identity outputs that exist solely to undo partial release:prepare mutations. A failed publication must leave both main and repository tags unchanged.
  • Preserve the existing cross-platform classifier builds, but ensure every classifier and the primary Java SDK artifact is built from the same immutable source SHA and receives the version calculated by .github/workflows/publish.yml.
  • Update .github/workflows/publish.yml so publish-java follows the same contract as the other publishers: consume the shared version, build from the triggering SHA, publish the resulting artifacts, and report success without changing source-controlled files.
  • Create the common vX.Y.Z GitHub release only after package publication succeeds. If a Java-specific java/vX.Y.Z traceability tag remains necessary, create it after successful publication, point it at the original release SHA, and manage it alongside the existing Go and Rust language tags in the github-release job rather than inside the Maven publication workflow.
  • Retain an independently dispatchable Java publication path so a failed Maven Central deployment can be retried for the same version and source SHA without rerunning or altering the releases for other languages.
  • Update .github/workflows/java-publish-snapshot.yml and the Java POM hierarchy as required by the new CI-friendly version mechanism, while preserving the snapshot workflow’s existing read-only relationship with the repository.

The work is complete when a successful or failed Java release creates no commits on main, requires no branch-protection bypass or elevated repository token, and publishes Maven artifacts whose version and source commit match the other SDK artifacts in the same release.

Internal User Story

dd-3061183-cease-maven-release-plugin

Activity

  1. edburns commented on Sep 9, 2026

    @edburns
    CollaboratorAuthor

    At today's SDK triage, @roji stated it is unlikely that the "incorporate SDK into copilot-agent-runtime" merge will happen this week. Therefore, the deadline for this work is no earlier than 2026-09-18.

  2. roji commented on Sep 9, 2026

    @roji
    Collaborator

    Therefore, the deadline for this work is no earlier than 2026-09-18.

    That would be my assumption, but let me chat with Dev and see how the team design meeting goes tomorrow before we commit on a date. Either way, I'd treat this as the most urgent Java-side issue at the moment.

  3. SandraAhlgrimm commented on Sep 10, 2026

    @SandraAhlgrimm
    Contributor

    Proposed plan: replace maven-release-plugin with Maven CI-Friendly Versions

    Goal

    Make the Java release pipeline a read-only consumer of the commit being released, consistent with the other SDKs. A Java release (success or failure) must create no commits on main, require no elevated repository token or ruleset bypass, and publish artifacts whose version + source SHA match the other SDK artifacts in the same release.

    Current state (the problem)

    .github/workflows/java-publish-maven.yml is the only publisher that mutates git history:

    • prepare-release commits a docs version bump and pushes to main, then runs mvn release:prepare, which commits the release version + the next -SNAPSHOT and pushes both plus a java/vX.Y.Z tag to main.
    • This uses JAVA_RELEASE_TOKEN (push perms, contents: write, repository-ruleset bypass).
    • A rollback-release job force-reverts those commits/tag on failure.

    Versions are hardcoded (1.0.14-SNAPSHOT) in java/pom.xml, java/sdk/pom.xml, java/copilot-native/pom.xml. flatten-maven-plugin (ossrh mode) is already configured — the prerequisite for CI-friendly versions is in place. Other SDKs (rust/python/dotnet) consume the shared computed version and set it in-workspace only, committing nothing.

    Design

    Adopt the officially-documented ${revision} + flatten-maven-plugin pattern — the standard modern replacement for maven-release-plugin that stops mutating git history. Release version is injected at build time with -Drevision=<version>; the committed default stays -SNAPSHOT for local/snapshot builds.

    Work items

    1. POMs -> ${revision} (java/pom.xml, java/sdk/pom.xml, java/copilot-native/pom.xml)

    • Add <revision>1.0.14-SNAPSHOT</revision> in the parent POM.
    • Replace the three hardcoded <version> / parent-<version> values with ${revision}. ${project.version} cross-references (sdk -> copilot-native runtime) stay valid; flatten resolves them at publish.
    • Remove maven-release-plugin from pluginManagement.

    2. Rewrite java-publish-maven.yml

    • Delete the preflight, prepare-release, and rollback-release jobs.
    • Add a resolve-source job (mirroring java-publish-snapshot.yml) that pins the triggering SHA; add a sourceSha input.
    • Every classifier build job + deploy-maven checks out that SHA with persist-credentials: false and builds mvn deploy -Prelease -Drevision=<releaseVersion> — one immutable SHA, one version, all classifiers.
    • Drop the JAVA_RELEASE_TOKEN secret and change contents: write -> contents: read. Keep Maven Central + GPG secrets (they authorize package publication, not repo mutation). Remove the java/vX.Y.Z-tag dependency for classifier checkouts.
    • Documentation version bump leaves this workflow. scripts/update-documentation-versions.sh stays and runs through a normal reviewed PR instead of as a publish side effect.

    3. publish.yml

    • publish-java: contents: read; pass sourceSha: ${{ github.sha }} + releaseVersion: ${{ needs.version.outputs.version }}; keep consuming mavenPublished.
    • github-release (already gated on publish success): after publication, create the java/vX.Y.Z traceability tag pointing at github.sha, alongside the existing Go/Rust tag steps. The common vX.Y.Z release is already created only post-publish — unchanged.
    • Keep workflow_dispatch on the maven workflow so a failed Maven Central deploy is independently retryable for the same version + SHA without rerunning other languages.

    4. java-publish-snapshot.yml

    • Already read-only. With ${revision} defaulting to 1.0.14-SNAPSHOT, snapshot deploy is functionally unchanged; verify mvn deploy resolves ${revision}.

    5. Site deploy

    • deploy-site keyed off the version/SHA (the tag is now created by github-release); sequence it after the tag exists or pass the version directly.

    6. Contributor mental-model note (java/README.md)
    CI-friendly versions are a genuine workflow-habit change for Java devs used to maven-release-plugin: the committed <revision> stays a fixed -SNAPSHOT and the real release version is computed externally (by get-version.js, like the other SDKs). Document that the POM intentionally does not track the next release version, releases inject it via -Drevision=, and there is no release:prepare ceremony (tagging happens in publish.yml after publication).

    7. Verification

    • Local mvn install must still resolve ${revision} for downstream consumers (flatten produces resolved installed POMs) — verify a consumer resolves com.github:copilot-sdk-java with no unresolved ${revision}.
    • mvn -Prelease deploy -Drevision=X.Y.Z -DskipTests (against a local/staging repo where possible) produces artifacts + flattened POMs carrying the literal X.Y.Z, no ${revision} leakage, parent stripped, correct classifier attachments.

    Definition of done

    • A successful or failed Java release creates no commits on main.
    • No branch-protection bypass or elevated repository token is required.
    • Published artifacts carry the shared computed version and are built from the triggering SHA, matching the other SDK artifacts in the same release.
    • java/README.md documents the new versioning model.
  4. added a commit that references this issue on Sep 14, 2026
    223d7eb
  5. added a commit that references this issue on Sep 15, 2026
    22e8607
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions