Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -18,16 +19,12 @@
* records which classes and methods each test covers, along with git metadata
* (commitId, baseBranch, timestamp) for change detection.</p>
*
* <p>Supports three output formats:</p>
* <ul>
* <li>Plain JSON (default) -- human-readable, with pretty printing</li>
* <li>Indexed JSON ({@code --indexed}) -- deduplicated class/method strings with
* integer references, typically 10-15x smaller</li>
* <li>Gzip ({@code --gzip}) -- additional compression, combinable with indexed format</li>
* </ul>
* <p>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.</p>
*
* @see CoverageMapEngine
* @see com.sap.oss.smarttestpicker.mapper.IndexedCoverageMap
* @see CoverageMapResolver
*/
@Command(
name = "generate-map",
Expand Down Expand Up @@ -61,6 +58,10 @@ public class GenerateMapCommand implements Callable<Integer>
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()
{
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -19,6 +20,10 @@
/**
* CLI subcommand for querying a coverage map interactively.
*
* <p>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}).</p>
*
* <p>Provides multiple query modes for debugging and exploring test coverage data:</p>
* <ul>
* <li>{@code --test} -- show all classes and methods covered by a specific test</li>
Expand All @@ -28,10 +33,8 @@
* <li>{@code --stats} -- display aggregate statistics (totals, min/max/avg coverage)</li>
* </ul>
*
* <p>Reads all three coverage map formats transparently: plain JSON, indexed JSON,
* and gzip-compressed files.</p>
*
* @see CoverageMapReader
* @see CoverageMapResolver
*/
@Command(
name = "query",
Expand All @@ -41,10 +44,18 @@
public class QueryCommand implements Callable<Integer>
{

@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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
Loading