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]

Reply via email to