diff --git a/smart-test-picker-cli/src/main/java/com/sap/oss/smarttestpicker/cli/GenerateMapCommand.java b/smart-test-picker-cli/src/main/java/com/sap/oss/smarttestpicker/cli/GenerateMapCommand.java index 269c64c..6d7725f 100644 --- a/smart-test-picker-cli/src/main/java/com/sap/oss/smarttestpicker/cli/GenerateMapCommand.java +++ b/smart-test-picker-cli/src/main/java/com/sap/oss/smarttestpicker/cli/GenerateMapCommand.java @@ -7,6 +7,7 @@ import java.util.concurrent.Callable; import com.sap.oss.smarttestpicker.engine.CoverageMapEngine; +import com.sap.oss.smarttestpicker.store.CoverageMapResolver; import picocli.CommandLine.Command; import picocli.CommandLine.Option; @@ -18,16 +19,12 @@ * records which classes and methods each test covers, along with git metadata * (commitId, baseBranch, timestamp) for change detection.

* - *

Supports three output formats:

- * + *

When {@code --cache} is specified, the generated map is also written to the + * local cache at {@code ~/.gradle/smart-test-picker/PROJECT_NAME/local-coverage-map.json} + * so that {@code select-tests} and {@code query} can resolve it automatically.

* * @see CoverageMapEngine - * @see com.sap.oss.smarttestpicker.mapper.IndexedCoverageMap + * @see CoverageMapResolver */ @Command( name = "generate-map", @@ -61,6 +58,10 @@ public class GenerateMapCommand implements Callable description = "Compress output with gzip") private boolean gzip; + @Option(names = "--cache", + description = "Also write to local cache (~/.gradle/smart-test-picker/PROJECT_NAME/local-coverage-map.json)") + private boolean cache; + @Override public Integer call() { @@ -82,10 +83,20 @@ public Integer call() logger.info("Base branch: {}", baseBranch); logger.info("Indexed: {}", indexed); logger.info("Gzip: {}", gzip); + logger.info("Cache: {}", cache); try { new CoverageMapEngine().generate(xmlDir, output, baseBranch, projectDir, logger, indexed, gzip); + + if (cache) + { + CoverageMapResolver resolver = new CoverageMapResolver(projectDir, logger); + File cacheFile = resolver.getLocalMapPath(); + new CoverageMapEngine().generate(xmlDir, cacheFile, baseBranch, projectDir, logger, indexed, gzip); + logger.info("[SmartTestPicker] Cached local map: {}", cacheFile.getAbsolutePath()); + } + return 0; } catch (IOException e) diff --git a/smart-test-picker-cli/src/main/java/com/sap/oss/smarttestpicker/cli/QueryCommand.java b/smart-test-picker-cli/src/main/java/com/sap/oss/smarttestpicker/cli/QueryCommand.java index 30ea5aa..377c8d2 100644 --- a/smart-test-picker-cli/src/main/java/com/sap/oss/smarttestpicker/cli/QueryCommand.java +++ b/smart-test-picker-cli/src/main/java/com/sap/oss/smarttestpicker/cli/QueryCommand.java @@ -11,6 +11,7 @@ import com.sap.oss.smarttestpicker.mapper.CoverageMap; import com.sap.oss.smarttestpicker.mapper.CoverageMapReader; +import com.sap.oss.smarttestpicker.store.CoverageMapResolver; import picocli.CommandLine.ArgGroup; import picocli.CommandLine.Command; import picocli.CommandLine.Option; @@ -19,6 +20,10 @@ /** * CLI subcommand for querying a coverage map interactively. * + *

The coverage map can be provided explicitly via {@code --map}, or resolved + * automatically from the local cache using the {@code --prefer-map} mode + * (same behavior as {@code select-tests}).

+ * *

Provides multiple query modes for debugging and exploring test coverage data:

* * - *

Reads all three coverage map formats transparently: plain JSON, indexed JSON, - * and gzip-compressed files.

- * * @see CoverageMapReader + * @see CoverageMapResolver */ @Command( name = "query", @@ -41,10 +44,18 @@ public class QueryCommand implements Callable { - @Option(names = "--map", required = true, - description = "Coverage map JSON file") + @Option(names = "--map", + description = "Coverage map JSON file. If not provided, resolves from local cache.") private File mapFile; + @Option(names = "--prefer-map", defaultValue = "nearest", + description = "Map selection mode when using cache: nearest, remote, local (default: nearest)") + private String preferMap; + + @Option(names = "--project-dir", + description = "Project root directory (default: current dir)") + private File projectDir; + @ArgGroup(exclusive = true, multiplicity = "1") private QueryMode queryMode; @@ -74,7 +85,27 @@ static class QueryMode @Override public Integer call() { - if (!mapFile.exists()) + if (projectDir == null) + { + projectDir = new File(System.getProperty("user.dir")); + } + + ConsoleLogger logger = new ConsoleLogger(); + + // Resolve map: explicit --map takes precedence over cache + if (mapFile == null) + { + CoverageMapResolver.PreferMode mode = parsePreferMode(preferMap); + CoverageMapResolver resolver = new CoverageMapResolver(projectDir, logger); + mapFile = resolver.resolve(mode); + + if (mapFile == null) + { + System.err.println("No coverage map available. Use --map or run 'pull-map' first."); + return 1; + } + } + else if (!mapFile.exists()) { System.err.println("Error: coverage map not found: " + mapFile); return 1; @@ -120,6 +151,20 @@ else if (queryMode.method != null) } } + private CoverageMapResolver.PreferMode parsePreferMode(String value) + { + switch (value.toLowerCase()) + { + case "remote": + return CoverageMapResolver.PreferMode.REMOTE; + case "local": + return CoverageMapResolver.PreferMode.LOCAL; + case "nearest": + default: + return CoverageMapResolver.PreferMode.NEAREST; + } + } + private int showStats(CoverageMap map) { int totalTests = map.getTestMappings().size();