ikxeno opened a new pull request, #13276:
URL: https://github.com/apache/maven/pull/13276
Two commits, reviewable apart:
1. `buildRaw` on `ModelBuilder.ModelBuilderSession`, with its own tests.
2. The `mvnval` tool, which uses it.
```
$ mvnval pom.xml
pom.xml:
ERROR 'dependencies.dependency.(groupId:artifactId:type:classifier)' must
be unique:
junit:junit:jar -> version 4.13.2 vs 4.12 @ line 12, column 5
```
Takes any number of POMs, defaults to `./pom.xml`, writes text or `--format
json`.
Exit 0 when nothing was reported, 1 when anything was rejected, 2 on bad
usage,
3 when only warnings were. Reachable as `mvnval` and as `mvn --val`.
I ran it over 2064 real POMs while writing this: 406 in this repo, 1638 IT
resources, and 20 published ones from Central. It found ten duplicate
dependency
declarations in `io.netty:netty-all:4.1.115.Final` (lines 848, 1062 and 1111
all
declare `netty-transport-native-epoll:linux-x86_64`), and it named the
deliberately
broken fixtures under `src/test/resources-project-builder` for what they are.
## Why not `mvn -f pom.xml validate`
Because that needs a project you can build. It resolves the parent, so it
wants
the network and a populated local repository, and it stops at the first
thing it
cannot resolve. `mvnval` reads files and nothing else. That makes it usable
on a
POM whose parent is not published yet, and in a pre-commit hook or a CI gate
with
no repository at all.
## Why a new API method
`buildRawModel(request)` already exists, and it is not enough: it returns the
`Model` and drops the problem collector, so the warnings never reach the
caller.
`build()` keeps the problems but throws as soon as validation reports an
error, so
a POM with one error and four warnings tells you about the error only. This
tool
needs the model read and the problems kept.
`default`, not abstract, so anything implementing `ModelBuilderSession`
against
4.0.0 still compiles. There is one implementor in tree and no japicmp gate on
`maven-api-core`, so this is about third parties, not about the build.
## What the tool cannot see
Validation stops at the raw model, so the reachable checks are a subset. A
dependency whose version comes from the parent's `dependencyManagement` is
only
caught in `validateEffectiveModel`. That is what a verdict depending on the
files
alone costs. `--help` says so, so nobody has to find out the hard way.
## Decisions worth arguing about
**The reactor is mapped before the POM is read.** A 4.1.0 subproject may
leave out
its parent version, and it is taken from the parent's file model. Without
the walk
a perfectly valid subproject fails with `'parent.version' is missing`.
**A reactor module that fails to load is logged, not reported.**
`loadFilePom`
reports that failure against the caller's result, so before this change
`mvnval a/pom.xml` said `a/pom.xml` was broken when the culprit was
`b/pom.xml`,
and the `source` field named `a/pom.xml` too. The flag is scoped to
`buildRaw`.
`build()` is untouched and still fails on a broken module, because a build
that
silently skipped one would be worse.
**Warnings exit 3, not 2.** The CLI returns 2 for a tool that failed in a
way it
does not handle, which is the same 2 the siblings use for `BAD_OPERATION`. A
gate
has to be able to tell "this POM has warnings" from "mvnval broke", so
warnings
got a code the framework does not produce.
**One problem reported twice is collapsed in the tool.** The parent version
check
sits in both `validateFileModel` and `validateRawModel`, so the model
builder hands
the same finding over twice. I collapsed it in `Report` rather than touching
the
validator, since changing that changes `mvn`.
**A fresh `ModelBuilderSession` per POM.** Sharing one across files would
share
`dag` and `mappedSources`, and two roots holding the same groupId:artifactId
then
trip `No unique Source for ...`. Slower, but it cannot report on the wrong
file.
**JSON assembled by hand.** No JSON library is on the CLI classpath and I
would
rather not put one there for one output format. Non-ASCII is escaped as
`\uXXXX`
because the writer's charset is the console's, which on Windows is routinely
not
UTF-8, and a path can carry an unpaired surrogate that no charset encodes.
**A standalone `Session`, built in `createSession()`.** `LookupInvoker` only
ever
builds a `ProtoSession`, and `ModelBuilderRequest` needs a full `Session`.
`mvnup`
has the same problem and solves it in `MvnupSessionHolder`. A bare session is
enough here because nothing is resolved and no transport is configured.
**Not an `mvnsh` built-in yet.** The registry builds its completer from
`lookupMap(Goal.class)` and `mvnval` has no goals, so wiring it up means
changing
`BuiltinShellCommandRegistryFactory`, not this tool. Happy to do it in a
follow-up
if you would rather it landed together.
**`THREAT_MODEL.md` gets a row.** It reads operator POMs and emits their
content
into a machine-readable document. It resolves no parent, opens no connection
and
writes nothing back, and the row says exactly that.
## Checked
`mvn verify` on `maven-api-cli`, `maven-api-core`, `maven-impl` and
`maven-cli`,
plus the first commit alone in a separate worktree. Checkstyle clean,
javadoc clean
under doclint. `MavenITgh10442MvnvalValidatePomTest` passes, 3 tests.
Distribution
built and the tool exercised from the unpacked zip, including paths with
spaces and
with Cyrillic, which round-trip through the JSON escaping unchanged.
Two ITs fail on my machine for reasons this branch does not touch, and I
have not
checked them against `master`:
`MavenITmng4428FollowHttpRedirectTest.testitHttpsToHttps`,
which is HTTPS transport, and
`MavenITmng7045DropUselessAndOutdatedCdiApiTest`, where
Groovy 4.0.28 dies with "BUG! exception in phase 'semantic analysis'" on JDK
25 after
the model has already built.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]