View on GitHub

Ant Manipulator

Align Ant build versions with PME/GME

Alignment Report

Overview

ant-manipulator emits two JSON reports, each with a different job:

Report Property Default path When written
PME alignment report reportJSONOutputFile alignmentReport.json beside the build file After alignment, only if something was realigned (or reportJsonUnchanged=true). With no versioning option or versionModification=false nothing is realigned, so it is only written with reportJsonUnchanged=true
Discovery report discoveryReportJSONOutputFile discovery-report.json beside the build file Always, including when restURL is not set (discovery/report-only mode)

The PME alignment report is what PNC/Repour consume: it reuses PME’s own JSON POJOs (org.jboss.pnc.mavenmanipulator.common.json, from pom-manipulation-common-lite) so its shape is byte-for-byte compatible with PME’s and GME’s alignmentReport.json — a diff of the groupId:artifactId:version changes that were actually applied.

The discovery report is this tool’s own, richer diagnostic output: every coordinate candidate found, how they were grouped into artifacts, which versions are concrete vs. tokenised, and the result of reconciling tokens. It has no PME/GME equivalent and is independently useful even when restURL isn’t set.

PME Alignment Report

Output Path

Property Description Default
reportJSONOutputFile Path of the PME-shaped JSON report file alignmentReport.json beside the build file
reportJsonUnchanged Write the report even when no artifact was realigned false
-DreportJSONOutputFile=/tmp/alignmentReport.json

By default the report is only written when at least one artifact’s version was actually realigned (mirroring PME: there’s nothing useful to report otherwise). Set -DreportJsonUnchanged=true to force it to be written regardless.

JSON Structure

The report has two top-level keys, exactly as PME defines them:

Key Type Description
executionRoot object GAV of the artifact treated as “the” project root — see Choosing executionRoot
modules array One entry per artifact whose version was realigned

Each executionRoot / modules[].gav object is:

Field Description
groupId Maven group ID of the realigned (new) coordinate
artifactId Maven artifact ID of the realigned (new) coordinate
version The computed publish version
originalGAV The original groupId:artifactId:version before realignment

Ant Manipulator only realigns a project’s own publishing coordinates (not its consumed dependencies), so unlike PME’s ModulesItem, the properties/dependencies/managedDependencies/ plugins/profiles fields are always empty and omitted from the output.

Choosing executionRoot

Unlike a Maven reactor, an Ant project has no single canonical root GAV — one build.xml can publish many artifacts. executionRoot is chosen as whichever realigned artifact has a finding sourced directly from the root build file (the one passed to -f); if none is declared there, the first realigned artifact (by groupId:artifactId order) is used instead.

When versionModification=false nothing is realigned, so modules is empty — but executionRoot is still populated, chosen the same way from the discovered artifacts and reported at its unchanged declared version (originalGAV equals version). This lets PNC/Repour record and tag the build even when no version was modified.

Annotated example

{
  "executionRoot": {
    "groupId": "com.example",
    "artifactId": "my-lib",
    "version": "1.2.3.redhat-00001",
    "originalGAV": "com.example:my-lib:1.2.3"
  },
  "modules": [
    {
      "gav": {
        "groupId": "com.example",
        "artifactId": "my-lib",
        "version": "1.2.3.redhat-00001",
        "originalGAV": "com.example:my-lib:1.2.3"
      }
    }
  ]
}

Discovery Report

Output Path

Property Description Default
discoveryReportJSONOutputFile Path of the discovery JSON report file discovery-report.json beside the build file
-DdiscoveryReportJSONOutputFile=/tmp/my-report.json

JSON Structure

The report has four top-level keys:

Key Type Description
rootBuildFile string Absolute path of the build file passed to -f
generatedAt string ISO-8601 UTC timestamp
summary object Aggregate counts (see below)
artifacts array One entry per distinct groupId:artifactId pair
projectVersionCandidates array Coordinates whose GA could not be definitively attributed to a single artifact

summary object

Field Description
coordinateCandidates Total number of raw coordinate findings before deduplication
artifacts Number of distinct groupId:artifactId pairs
conflicts Number of GAs where two or more incompatible versions were found
projectVersionCandidates Number of version candidates that could not be grouped into a confirmed artifact
tokenisedVersions Number of distinct version tokens (${…} / @TOKEN@) seen
tokensResolved Tokens that resolved to exactly one concrete value
tokensAmbiguous Tokens that resolved to more than one concrete value
tokensUnresolved Tokens that could not be resolved to any concrete value

artifacts array entry

Each entry represents one groupId:artifactId and collects all the findings for that pair.

Field Description
groupId Maven group ID
artifactId Maven artifact ID
primaryVersion The single best version for this artifact (may be a token)
conflict true if two or more incompatible versions were found
confidence Confidence level of the best finding (HIGH, MEDIUM, LOW)
resolvedVersions Concrete version strings found directly
tokenisedVersions Version token strings found
reconciled Reconciliation results for each tokenised version (see below)
findings List of individual coordinate findings that contributed to this artifact

reconciled / reconciliation object

When a version is tokenised, the tool follows Ant’s property-substitution chains to find concrete values. The result is captured in a reconciliation object:

Field Description
token The original token string (${project.version}, @VERSION@, etc.)
resolved List of concrete values the token resolves to
unresolved List of intermediate tokens that still could not be resolved
ambiguous true if resolved contains more than one value
fullyResolved true if unresolved is empty

Annotated example

{
  "rootBuildFile": "/builds/my-project/build.xml",
  "generatedAt": "2025-03-01T10:00:00.000000000Z",
  "summary": {
    "coordinateCandidates": 3,
    "artifacts": 2,
    "conflicts": 0,
    "projectVersionCandidates": 1,
    "tokenisedVersions": 1,
    "tokensResolved": 1,
    "tokensAmbiguous": 0,
    "tokensUnresolved": 0
  },
  "artifacts": [
    {
      "groupId": "com.example",
      "artifactId": "my-lib",
      "primaryVersion": "@VERSION@",
      "conflict": false,
      "confidence": "HIGH",
      "resolvedVersions": [],
      "tokenisedVersions": ["@VERSION@"],
      "reconciled": [
        {
          "token": "@VERSION@",
          "resolved": ["1.2.3"],
          "unresolved": [],
          "ambiguous": false,
          "fullyResolved": true
        }
      ],
      "findings": [
        {
          "groupId": "com.example",
          "artifactId": "my-lib",
          "version": "@VERSION@",
          "sourceKind": "POM_TEMPLATE",
          "confidence": "HIGH",
          "sourceFile": "/builds/my-project/src/maven/my-lib.pom",
          "detail": "pom template",
          "reconciled": {
            "token": "@VERSION@",
            "resolved": ["1.2.3"],
            "unresolved": [],
            "ambiguous": false,
            "fullyResolved": true
          }
        }
      ]
    }
  ],
  "projectVersionCandidates": []
}

Programmatic Access

The PME-shaped report is produced by PmeAlignmentReport in the core module, and serialised with PME’s own JSONUtils/PME POJOs from pom-manipulation-common-lite. The discovery report is produced by AlignmentReport, also in org.jboss.pnc.antmanipulator.report, and serialised with a plain Jackson ObjectMapper. If you need to consume either report programmatically rather than parsing the JSON directly, use the respective build(...) factory method after running the pipeline stages manually.