CI :: Build failure : NPE in maven-artifact-plugin:compare with `-pl` builds
envgap__apache__incubator-kie-6876
01 / FAILURE SIGNATURE
As reported upstream
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-artifact-plugin:3.5.1:compare (compare)
Not a benchmark task.
- In a clean container the reported failure did not reproduce, or the known fix did not make the project run.
02 / ENVIRONMENT RECIPE
- Base commit
61c0e37b966bb34e50ca12deee906d45b789d9bb- Manifest
pom.xml- Reproduce
Awaiting issue-specific recipe- Run under trace
Awaiting a meaningful runtime command
03 / ORIGINAL ISSUE TEXT
apache/incubator-kie #6876 · read the original issue
# NPE in maven-artifact-plugin:compare with `-pl` builds
## Symptom
CI build fails with:
```
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-artifact-plugin:3.5.1:compare (compare)
on project kie-parent: Execution compare of goal
org.apache.maven.plugins:maven-artifact-plugin:3.5.1:compare failed:
Cannot invoke "org.apache.maven.project.MavenProject.getBuild()" because "root" is null
```
Reproducible with 3.5.2. **Fixed in 3.6.1** (see Solution below).
https://issues.apache.org/jira/browse/MARTIFACT-79
## Root Cause
The CI workflow (`.github/workflows/ci.yaml`, line 195) runs:
```bash
mvn ... -Dfull -Dreproducible -pl "$pl" install
```
where `$pl` is the list of affected modules (e.g. `kie-parent,kie-api,...`). The root pom (`drools-parent`) is **not** included in `$pl`.
The `-Dreproducible` property activates the `reproducible-build` profile (root `pom.xml`, line 275), which binds `maven-artifact-plugin:compare` to the `install` phase.
In a multi-module reactor, the `compare` goal aggregates results. For the **last** module in the reactor, `CompareMojo.execute()` calls:
```java
checkAgainstReference(artifacts, session.getProjects().size() == 1);
```
Since there are multiple modules, `mono = false`, which leads to:
```java
// CompareMojo.java line 126 (3.5.2)
MavenProject root = mono ? project : getExecutionRoot();
File referenceDir = new File(root.getBuild().getDirectory(), "reference"); // NPE here
```
`getExecutionRoot()` iterates over `session.getProjects()` looking for a project where `isExecutionRoot() == true`. With `-pl`, the root pom (`drools-parent`) is excluded from the reactor, so no project has `isExecutionRoot() == true`, and the method returns `null`.
In 3.6.x the code changed to `session.getTopLevelProject()`, which returns the first project in the reactor (e.g. `kie-parent`) rather than null when the root pom is excluded via `-pl`. This resolves the NPE.
### Code path (3.5.x — broken)
```
AbstractBuildinfoMojo.execute()
→ mono = session.getProjects().size() == 1 // false (multiple -pl modules)
→ last module: calls checkAgainstReference(artifacts, false)
→ CompareMojo.checkAgainstReference()
→ root = getExecutionRoot() // returns null
→ root.getBuild() // NPE
```
```java
// AbstractBuildinfoMojo.java line 342
protected MavenProject getExecutionRoot() {
for (MavenProject p : session.getProjects()) {
if (p.isExecutionRoot()) {
return p;
}
}
return null; // ← no guard against null
}
```
## Version comparison
| Version | Root resolution method | NPE with `-pl`? |
|---------|--------------------------------|-----------------|
| 3.5.1 | `getExecutionRoot()` | Yes |
| 3.5.2 | `getExecutionRoot()` | Yes (confirmed) |
| 3.6.1 | `session.getTopLevelProject()` | **No** (confirmed) |
In 3.5.x, `getExecutionRoot()` returns `null` when the root pom is not in the reactor.
In 3.6.x, `session.getTopLevelProject()` returns the first project in the reactor, avoiding the NPE.
## Affected CI step
```yaml
# .github/workflows/ci.yaml line 189-195
- name: "PR CHECK :: BUILD :: Changed and affected modules"
if: github.event_name == 'pull_request'
shell: bash
run: |
pl=$(paste -sd, "$MAVEN_PL_AFFECTED_FILE")
[ -z "$pl" ] && echo "No affected modules. Skipping." && exit 0
mvn --batch-mode --no-transfer-progress -fae -Dsurefire.redirectTestOutputToFile=true -Dfull -Dreproducible -pl "$pl" install
```
Note: the full CI build on `push` (line 200) runs **without** `-pl` and works correctly:
```yaml
- name: "CI :: BUILD :: Full"
if: github.event_name == 'push'
run: mvn ... -Dfull -Dreproducible install
```
## Solution
Upgrade `maven-artifact-plugin` to **3.6.1**. No CI workflow changes needed.
In root `pom.xml`:
```xml
<version.maven.artifact.plugin>3.6.1</version.maven.artifact.plugin>
```
### Additional required change
Version 3.6.1's `check-buildplan` goal has an updated plugin database that correctly detects `maven-remote-resources-plugin:3.2.0` as non-reproducible (inherited from the Apache parent POM). Upgrade it to 3.3.0:
```xml
<version.maven-remote-resources-plugin>3.3.0</version.maven-remote-resources-plugin>
```
Without this, the build fails with:
```
[ERROR] plugin with non-reproducible output: org.apache.maven.plugins:maven-remote-resources-plugin:3.2.0, require minimum 3.3.0
```
### Alternative: Add the root pom to `-pl`
If upgrading the plugin is not feasible, adding `.` (the root pom) to `-pl` in the CI workflow also fixes the NPE with 3.5.x:
```bash
mvn ... -Dfull -Dreproducible -pl ".,$pl" install
```
This ensures `drools-parent` is in the reactor so `getExecutionRoot()` finds it. The root pom is `pom`-packaging only, so build overhead is negligible.
### Confirmed
`mvn -Dreproducible -pl kie-parent,kie-api install` succeeds with 3.6.1 **without** adding `.` to `-pl`:
```
[INFO] [Reproducible Builds] rebuild comparison result: 6 files match
[INFO] BUILD SUCCESS
```
04 / LABELS
Labels from the report text only; not yet run
No supported category has been assigned.
Label rules and the text that matched
[]