ReportMojo.java
package network.ike.plugin.ws;
import org.apache.maven.api.plugin.MojoException;
import org.apache.maven.api.plugin.annotations.Mojo;
import org.apache.maven.api.plugin.annotations.Parameter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Stream;
/**
* List and open the {@code ws꞉*.md} goal reports at the workspace root.
*
* <p>Each {@code ws:*} goal writes its latest output to a per-goal file
* alongside {@code workspace.yaml} and the aggregator {@code pom.xml}
* (for example {@code ws꞉overview.md}, {@code ws꞉release-draft.md}).
* This goal lists those reports newest-first and opens the workspace
* root in the default file manager so you can browse them.
*
* <p>Usage:
* <pre>
* mvn ws:report # list and open
* mvn ws:report -Dws.report.printOnly=true # list only
* </pre>
*/
@Mojo(name = "report", projectRequired = false, aggregator = true)
public class ReportMojo extends AbstractWorkspaceMojo {
/** Prefix shared by every {@code ws:*} goal report filename. */
private static final String REPORT_PREFIX = "ws\uA789";
/** Suffix shared by every {@code ws:*} goal report filename. */
private static final String REPORT_SUFFIX = ".md";
/** Creates this goal instance. */
public ReportMojo() {}
/**
* Skip opening the file manager; just print the paths.
*/
@Parameter(property = "ws.report.printOnly", defaultValue = "false")
private boolean printOnly;
@Override
protected WorkspaceReportSpec runGoal() throws MojoException {
Path root = workspaceRoot().toPath();
List<Path> reports = findReports(root);
if (reports.isEmpty()) {
getLog().info("No ws꞉*.md reports at " + root
+ ". Run a ws: goal first.");
return new WorkspaceReportSpec(WsGoal.REPORT,
"No `ws꞉*.md` goal reports at the workspace root yet.\n");
}
getLog().info("Workspace reports at " + root + ":");
StringBuilder body = new StringBuilder();
body.append(reports.size()).append(" goal report(s) at the workspace root, "
+ "newest first:\n\n");
for (Path report : reports) {
getLog().info(" " + root.relativize(report));
body.append("- `").append(root.relativize(report)).append("`\n");
}
if (!printOnly) {
boolean opened = WorkspaceReport.openInBrowser(root, getLog());
if (opened) {
getLog().info("Opened workspace root in file manager.");
} else {
getLog().info("Could not open file manager — browse directly: "
+ root);
}
}
return new WorkspaceReportSpec(WsGoal.REPORT, body.toString());
}
/**
* List {@code ws꞉*.md} files at the workspace root sorted newest-first.
*
* @param root the workspace root directory
* @return reports sorted by modification time, newest first; empty if
* the directory is missing or contains no matching files
*/
private static List<Path> findReports(Path root) {
if (!Files.isDirectory(root)) return List.of();
try (Stream<Path> entries = Files.list(root)) {
return entries
.filter(Files::isRegularFile)
.filter(ReportMojo::isReportFile)
.sorted(Comparator.comparing(ReportMojo::lastModified)
.reversed())
.toList();
} catch (IOException e) {
return List.of();
}
}
private static boolean isReportFile(Path path) {
String name = path.getFileName().toString();
return name.startsWith(REPORT_PREFIX) && name.endsWith(REPORT_SUFFIX);
}
private static FileTime lastModified(Path path) {
try {
return Files.getLastModifiedTime(path);
} catch (IOException e) {
return FileTime.fromMillis(0L);
}
}
}