WsLintMojo.java
package network.ike.plugin.ws;
import network.ike.plugin.ws.preflight.Preflight;
import network.ike.plugin.ws.preflight.PreflightCondition;
import network.ike.plugin.ws.preflight.PreflightContext;
import network.ike.plugin.ws.preflight.PreflightResult;
import network.ike.plugin.support.GoalReportBuilder;
import network.ike.workspace.WorkspaceGraph;
import org.apache.maven.api.plugin.MojoException;
import org.apache.maven.api.plugin.annotations.Mojo;
import java.io.File;
import java.util.Arrays;
import java.util.List;
/**
* Surface workspace-hygiene preflight conditions as a standalone gate
* (ike-issues#217).
*
* <p>Runs every {@link PreflightCondition} entry in <em>report-only</em>
* mode against the current workspace and emits a markdown summary.
* Always exits 0 — the goal is to make hygiene problems visible
* (typo'd {@code .mvn/jvm.config} comments, uncommitted state, leaking
* SNAPSHOT properties) before they propagate to git or Syncthing,
* not to gate the build itself. Mutating goals already require their
* relevant subset of conditions; this goal is the standalone reporting
* surface.
*
* <p>Usage:
*
* <pre>{@code
* mvn ws:lint # run every preflight check, warn on failures
* }</pre>
*
* <p>{@code ws:commit} also invokes the {@code JVM_CONFIG_NO_HASH_COMMENTS}
* subset by default so the typo'd-comment failure mode (which crashes
* the JVM before any Maven plugin can run) is caught at the transport
* boundary.
*/
@Mojo(name = "lint", projectRequired = false, aggregator = true)
public class WsLintMojo extends AbstractWorkspaceMojo {
/** Creates this goal instance. */
public WsLintMojo() {}
@Override
protected WorkspaceReportSpec runGoal() throws MojoException {
WorkspaceGraph graph = loadGraph();
File root = workspaceRoot();
List<String> sorted = graph.topologicalSort();
getLog().info("");
getLog().info(header("Lint"));
getLog().info("══════════════════════════════════════════════════════════════");
getLog().info("");
List<PreflightCondition> all = Arrays.asList(PreflightCondition.values());
PreflightResult result = Preflight.of(all,
PreflightContext.of(root, graph, sorted));
// warnIfFailed prints failure remediation to the log; it never
// throws. Pass LINT so the diagnostic context names this goal.
result.warnIfFailed(getLog(), WsGoal.LINT);
GoalReportBuilder report = new GoalReportBuilder();
report.paragraph("**Conditions checked:** " + all.size());
if (result.passed()) {
report.paragraph("All preflight conditions passed. ✓");
getLog().info(" All preflight conditions passed ✓");
} else {
report.paragraph(result.failures().size()
+ " preflight condition(s) reported issues:");
for (PreflightResult.Failure f : result.failures()) {
report.bullet("**" + f.condition().name() + "** — "
+ f.condition().description());
}
report.paragraph("_See goal log for remediation details._");
}
getLog().info("");
return new WorkspaceReportSpec(WsGoal.LINT, report.build());
}
}