Repository navigation
Conversation
|
One format worth considering for the machine-readable console mode: logfmt. It sits nicely between plain text (human-readable) and JSON lines (fully structured): parseable by Loki, Vector, Grafana out of the box, but still legible with a plain The interesting property: with Could be offered as a |
7eaa538 to
869e497
Compare
gnodet-bot
left a comment
There was a problem hiding this comment.
Console modes review — overall this is solid. Three specific issues worth addressing before merge.
This review was generated by an AI agent, Hermès on behalf of @gnodet.
11205e6 to
92a187f
Compare
7b65dd4 to
14521d5
Compare
gnodet-bot
left a comment
There was a problem hiding this comment.
Console modes + build report review — the three findings from the previous review (PR #12697 / old SHA 7b65dd40) are all addressed in this resubmission. One new concurrency issue found, and one pre-existing concern persists.
Addressed from prior review:
- ✅
MachineExecutionEventLoggermojo key now includesgroupId— module collision in multi-module builds fixed - ✅
BUILD FAILUREheader correctly atlogger.error()inlogResult() - ✅
currentVisitedProjectCountis nowAtomicIntegerinMachineExecutionEventLogger
This review was generated by an AI agent, Hermès on behalf of @gnodet.
gnodet-bot
left a comment
There was a problem hiding this comment.
Console modes re-review (SHA 67d50688) — all four findings from the prior review are addressed. One nit remains unresolved.
Addressed from prior review:
- ✅
RichBuildEventListener.completedProjectsrace — fixed:volatile int→final AtomicIntegerwith.incrementAndGet()/.get()throughout - ✅ Per-module FAILURE lines in
ExecutionEventLoggerlogged at wrong level — fixed:if (buildSummary instanceof BuildFailure) logger.error(...)branch added - ✅
PlainExecutionEventLoggerBUILD FAILURE logged at INFO — fixed:session.getResult().hasExceptions()check added, tests updated - ✅
PlainExecutionEventLogger.volatile int currentVisitedProjectCount— fixed:volatiledropped (lock provides the memory ordering) - ✅ Unknown
--console=value silent fallthrough — fixed: warning now logged viacontext.logger.warn()
One missed fix:
This review was generated by an AI agent, Hermès on behalf of @gnodet.
67d5068 to
3487903
Compare
gnodet-bot
left a comment
There was a problem hiding this comment.
Re-review after 3487903335 ("fix review: RichBuildEventListener race, logger.error on failures, unknown --console warn, drop volatile")
All four findings from the previous CHANGES_REQUESTED reviews are addressed:
| Finding | Status |
|---|---|
completedProjects++ race in RichBuildEventListener |
✅ Fixed — volatile int → AtomicInteger, incrementAndGet() used throughout |
Per-module FAILURE lines logged at INFO in ExecutionEventLogger.logReactorSummary |
✅ Fixed — BuildFailure instanceof check now routes to logger.error() |
BUILD FAILURE logged at INFO in PlainExecutionEventLogger.logResult |
✅ Fixed — session.getResult().hasExceptions() check now routes to logger.error() |
Silent fallthrough for unknown --console= values in MavenInvoker.determineConsoleMode |
✅ Fixed — unknown values now emit a warn(); "auto" falls through silently as before |
Misleading volatile on currentVisitedProjectCount in PlainExecutionEventLogger |
✅ Fixed — volatile dropped |
One nit from the prior inline comment (already posted on this SHA) remains open:
RichExecutionEventLogger.java:85 — private volatile int currentVisitedProjectCount still has the misleading volatile modifier. The field is only ever mutated inside synchronized (this) blocks, and the lock already provides the required happens-before. The volatile is redundant and signals incorrect intent to future readers — same fix as applied to PlainExecutionEventLogger.
This review was generated by an AI agent, Hermès on behalf of @gnodet.
gnodet-bot
left a comment
There was a problem hiding this comment.
Console modes re-review (SHA a39b4c2e) — the remaining nit from the previous review is addressed.
Addressed:
- ✅
volatileremoved fromcurrentVisitedProjectCountinRichExecutionEventLogger— correct. The field is only written insidesynchronized (this)(line 258:number = ++currentVisitedProjectCount) and assigned single-threadedly at session start (line 147). The JMM happens-before guarantee from the monitor makesvolatileredundant and misleading (it implied an unsynchronized read path that does not exist).
All prior findings from all previous reviews are addressed. The PR is ready.
This review was generated by an AI agent, Hermès on behalf of @gnodet.
a39b4c2 to
0855915
Compare
gnodet-bot
left a comment
There was a problem hiding this comment.
Console modes re-review (SHA 08559154) — re-reviewing the delta since the prior APPROVE (a39b4c2e).
Delta since last review:
- ✅ Trailing newline added to 7 files (
MachineBuildEventListener.java,LayeredOptions.java,LookupInvoker.java, 4 test files) — trivial formatting fix, no logic change. - ✅
WorkspaceParentProjectBuilderTest.java(new, 141 lines) — solid test for workspace parent basedir handling. Correctly overridesgetWorkspaceReader()(the hook exists on master since #13212). Two scenarios well-covered: parent from project-local repository gets no basedir, parent that is a session project keeps its basedir. Test structure is clean —@TempDir, proper POM helpers, correct use ofassertNull/assertEquals. No issues. - ✅
domtripVersion1.6.0 → 1.7.0,jlineVersion4.4.3 → 4.4.5 — both are minor bug-fix releases with no breaking API changes. JLine 4.4.5 includes fixes for FFM SIGQUIT handler, ColorPalette OSC 4 fallback, ReDoS-vulnerable regex, and paginated layout defects. domtrip 1.7.0 is from the maveniverse project (same maintainer). Both bumps are safe. - ✅
.worktrees/**added to RAT exclusion — correct, avoids false license-header hits on git worktree admin files.
All prior findings from the review chain remain addressed. APPROVED.
This review was generated by an AI agent, Hermès on behalf of @gnodet.
gnodet-bot
left a comment
There was a problem hiding this comment.
Console modes re-review (SHA f6bb3306) — single commit since the prior APPROVE (08559154).
Delta: Restores getWorkspaceReader() hook in AbstractCoreMavenComponentTestCase.
- ✅
getWorkspaceReader()returnsnullby default —DefaultSessionBuilder.setWorkspaceReader(null)is a plain field assignment, no NPE risk. - ✅
SessionBuilder.setWorkspaceReader(WorkspaceReader)exists in resolver 2.0.23 — the call site is valid. - ✅
WorkspaceParentProjectBuilderTest.getWorkspaceReader()override (already in-tree) is now wired intoinitRepoSession(), which is the whole point of this commit. - ✅ Javadoc on the new method is correct and sufficient.
Clean fix. APPROVE.
This review was generated by an AI agent, Hermès on behalf of @gnodet.
gnodet-bot
left a comment
There was a problem hiding this comment.
Console modes re-review (SHA 48f67cdb) — single commit since the prior APPROVE (f6bb3306).
Delta: Restores isProjectPom() helper and its use in resolveProjectSource() in DefaultProjectBuilder.
- ✅
isProjectPom(Path pomFile)— logic is correct.pomFile == nullguard handlesArtifact.getPath()returningnullbefore resolution.projects == nullguard matches the existing pattern at line 371 (defensive for UT environments).filter(Objects::nonNull)is appropriate even though the list is@Nonnull. The use ofnormalize()is more correct than the existing line 371 equivalent. - ✅
localProject = isWorkspaceRepo && isProjectPom(pomArtifact.getPath())— restores the original invariant: only POMs belonging to actual session projects get a basedir. FixesWorkspaceParentProjectBuilderTest.parentFromProjectLocalRepositoryHasNoBasedir. - ✅ No new behavior introduced — pure restoration of code accidentally dropped in the squash commit.
Clean fix, no issues.
This review was generated by an AI agent, Hermès on behalf of @gnodet.
gnodet-bot
left a comment
There was a problem hiding this comment.
Console modes re-review (SHA 905812cd) — single commit since the prior APPROVE (48f67cdb).
Delta: Isolates ITs from the CI environment so CI → plain auto-detection does not suppress output that ITs rely on.
- ✅
AbstractMavenIntegrationTestCase.newVerifier()—removeCIEnvironmentVariables()called in the base method. Verified against all six CI detectors:GenericCIDetector(CI="false"),GithubCIDetector(GITHUB_ACTIONS=""),TravisCIDetector(TRAVIS=""),CircleCIDetector(CIRCLECI=""),JenkinsCIDetector(WORKSPACE=""),TeamcityCIDetector(TEAMCITY_VERSION="") — every detector is correctly neutralized. - ✅
MavenITmng8655SettingsParserTest.coreRealmParserReadsBootstrapSettings()— adds--console=verboseto theForkedMavenExecutorcall (which bypassesnewVerifier()and thus the base-class fix). Correct:verbosemode usesExecutionEventLoggerwhich emits theBuilding bootstrap-settings 0.1line the assertion checks. - ✅ Existing CI-aware ITs: tests that called
removeCIEnvironmentVariables()individually (mng4829, mng6240, mng4461) are now redundant but harmless. No regression.
All prior findings remain resolved. Clean delta.
This review was generated by an AI agent, Hermès on behalf of @gnodet.
905812c to
512629a
Compare
gnodet-bot
left a comment
There was a problem hiding this comment.
Console modes re-review (SHA 512629a5) — re-reviewing the delta since the prior APPROVE (905812cd).
Context: The branch was force-pushed. The new HEAD collapses several prior commits into a different squash. Comparing the PR diff vs master (the only merge-relevant delta), the sole net-new code change is the JUL-level clamping in LookupInvoker.
Items that appeared to regress vs 905812cd but are not merge regressions:
jlineVersion4.4.5 → 4.4.3,domtripVersion1.7.0 → 1.6.0,.worktrees/**RAT exclude absent — these were squashed out of the PR branch, but all three are already on master via independent commits (ebb415b5,77944f80,18806b1a45). They will survive the merge.WorkspaceParentProjectBuilderTestnot in PR branch — was added+deleted within the feature branch squash. master has it independently viac3b52889c3. Merge will keep master's version.
New JUL-level clamping in LookupInvoker (configureLogging + activateLogging):
configureLogging (quiet mode): MavenJulHandler.install() sets Level.ALL internally, then setLevel(Level.SEVERE) immediately overrides it. These two calls are synchronous in a single thread — zero event-processing window between them. Level.SEVERE blocks JUL events before they reach publish(), preventing the SLF4J-bootstrap reentrancy flood that Level.ALL would cause while SLF4J is still pre-activated. Correct.
activateLogging: post-activate() JUL root level is set to mirror the SLF4J effective level (quiet→SEVERE, verbose→ALL, default→INFO). The isInstalled() guard prevents double-install. The three-way mapping is correct.
The fix correctly closes the race window described in the comment: between configureLogging and activateLogging, createTerminal() runs and JLine emits JUL events. In quiet mode those events were leaking before this change. Setting Level.SEVERE at source (JUL root) before createTerminal() is the right fix — the isLevelEnabled() check in MavenJulHandler.publish() would not suffice because newly created SLF4J loggers briefly see the default INFO level during the reentrancy window.
IT coverage via MavenITmng4387QuietLoggingTest (on master, already exercises quiet-mode output expectations). The change is narrowly scoped and well-explained. APPROVE.
This review was generated by an AI agent, Hermès on behalf of @gnodet.
gnodet-bot
left a comment
There was a problem hiding this comment.
Console modes re-review (SHA 2c47687a) — re-reviewing the new commit since the prior APPROVE (512629a5).
One nit: the comment block is now stale after the cwd change.
This review was generated by an AI agent, Hermès on behalf of @gnodet.
| return executorTool.localRepository(executorRequest() | ||
| .cwd(tempBasedir) | ||
| ExecutorRequest.Builder builder = executorRequest() | ||
| .cwd(basedir) |
There was a problem hiding this comment.
🔶 Nit — stale comment: the comment at lines 447-448 now contradicts the code:
"but we should not use basedir, as it may contain extensions.xml or a project, that Maven will eagerly load"
But the code below now calls .cwd(basedir). If the intent changed (e.g. because the settings.xml path must be resolved relative to basedir, and the new code mitigates the extension-loading risk differently), the comment should be updated to explain the new rationale. If basedir is still problematic here, this change should be reconsidered.
…enhancements Introduce the logging foundation for the console-modes feature chain: - LogEvent / LogLevel API types in org.apache.maven.api.build.report - MavenJulHandler: a JUL handler that routes java.util.logging events through SLF4J/Maven's logging pipeline, replacing SLF4JBridgeHandler - Structured log event capture in DefaultLogEvent for per-mojo log recording - Export build.report package from maven-api module - Add 'requires java.logging' to maven-logging module Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add BuildReport, ModuleReport, MojoReport, FailureReport, BuildStatus API types (maven-api-core) - Add BuildEnvironment API type and Session.buildEnvironment() accessor - Implement BuildReportCollector in maven-core: captures per-mojo log output, timing, failures - Implement BuildReportJsonWriter: writes structured JSON report to file at build end - Integrate into MavenInvoker and DefaultMavenExecutionRequest - Extend MavenSimpleLogger and MavenJulHandler with LogSink support for log capture - Add SessionStub.buildEnvironment() stub for maven-testing - Add BuildReportCollectorTest, BuildReportJsonWriterTest, BuildReportIntegrationTest - Handle MojoSkipped events in BuildReportCollector - Fix ConcurrentModificationException in buildReport() log buffer iteration
Add --console CLI flag with four output modes: - plain: compact one-line-per-module output, ideal for CI (auto-selected in CI environments) - rich: JLine status bar with live reactor progress (auto-selected on interactive TTYs) - verbose: full mojo-level output, current Maven 4.0 default behavior - machine: JSON lines – one typed JSON object per lifecycle event, designed for piping to external tools Auto-detection (--console=auto, the default): CI → plain, interactive TTY → rich, otherwise → verbose. New event loggers: PlainExecutionEventLogger, RichBuildEventListener, RichExecutionEventLogger, MachineBuildEventListener, MachineExecutionEventLogger. ITs pass --console=verbose to isolate from CI auto-detection without switching the executor from embedded to forked mode. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2c47687 to
33557d1
Compare
gnodet-bot
left a comment
There was a problem hiding this comment.
Three findings in the new API files and test infrastructure.
This review was generated by an AI agent, Hermès on behalf of @gnodet.
| * | ||
| * @return the resume-from selector, or {@code null} if not specified | ||
| */ | ||
| String resumeFrom(); |
There was a problem hiding this comment.
@Nullable annotation on resumeFrom()
The Javadoc says "or null if not specified", but the method has no @Nullable annotation. Every other nullable-returning method in the Maven API carries this annotation to make the null contract explicit for callers and static analysis tools. The file imports @Nonnull but not @Nullable.
| String resumeFrom(); | |
| @Nullable | |
| String resumeFrom(); |
And add the import alongside @Nonnull:
import org.apache.maven.api.annotations.Nullable;
| return executorTool.localRepository(executorRequest() | ||
| .cwd(tempBasedir) | ||
| ExecutorRequest.Builder builder = executorRequest() | ||
| .cwd(basedir) |
There was a problem hiding this comment.
The comment at lines 447–448 says:
// but we should not use basedir, as it may contain extensions.xml or a project, that Maven will eagerly
But this PR changes .cwd(tempBasedir) to .cwd(basedir) on the very next line. Either the comment is stale and should be removed/updated, or the .cwd(basedir) change reintroduces the problem the comment was guarding against. Please clarify the intent and update the comment accordingly.
| List<String> goals(); | ||
|
|
||
| /** | ||
| * The GAV of the top-level project ({@code groupId:artifactId:version}). | ||
| * | ||
| * @return the project identifier, never {@code null} | ||
| */ | ||
| @Nonnull | ||
| String project(); | ||
|
|
||
| /** | ||
| * Whether this was a multi-module (reactor) build. | ||
| * | ||
| * @return {@code true} for multi-module builds | ||
| */ | ||
| boolean multiModule(); | ||
|
|
||
| /** | ||
| * The degree of concurrency ({@code -T} flag), or 1 for sequential builds. | ||
| * | ||
| * @return the thread count | ||
| */ | ||
| int threads(); |
There was a problem hiding this comment.
💡 goals() and threads() overlap with environment().goals() and environment().threads()
BuildReport already exposes environment() which returns a BuildEnvironment — and BuildEnvironment has both goals() and threads(). Surfacing them again directly on BuildReport creates two sources of truth for the same data. If they are convenience aliases (delegates to environment()), the Javadoc should say so explicitly. If they can diverge from the environment values, that distinction also needs to be documented.
Summary
Part 3 of the logging feature chain. Depends on #12695 (build report).
Adds the
--consoleCLI flag with four output modes:plain— compact one-line-per-module output, ideal for CI (auto-selected in CI environments)rich— JLine status bar with live reactor progress (auto-selected on interactive TTYs)verbose— full mojo-level output, current Maven 4.0 default behaviormachine— JSON lines: one typed JSON object per lifecycle event, designed for piping to external toolsAuto-detection (
--console=auto, the default): CI → plain, interactive TTY → rich, otherwise → verbose.Files changed (17 files)
Options.java(+console())PlainExecutionEventLogger,RichBuildEventListener,RichExecutionEventLogger,MachineBuildEventListener,MachineExecutionEventLoggerCommonsCliOptions,LayeredOptions,LookupInvoker(preliminary interactive detection),MavenInvoker(console mode switch + transfer listener)ExecutionEventLogger(version info on failure, linear reactor summary)PR chain
mvnlogviewerTest plan
mvn verify -pl api/maven-api-cli,impl/maven-cli -am— all tests pass