artifactTypes;
+
+ /**
+ * Determines which tags should be imported.
+ *
+ * Import only specification items that have at least one of the listed
+ * tags. If you add a single underscore {@code _}, specification items that
+ * have no tags at all are also imported.
+ *
+ * Default: Import all specification items.
+ */
+ @Parameter(property = "tags")
+ Set tags;
+
/**
* Skip running OFT.
*
@@ -114,19 +127,35 @@ public class TraceMojo extends AbstractMojo
@Parameter(defaultValue = "${project}", readonly = true)
private MavenProject project;
- @Component
- private ProjectBuilder mavenProjectBuilder;
-
@Parameter(defaultValue = "${session}", readonly = true)
private MavenSession session;
+ private final ProjectBuilder mavenProjectBuilder;
+
+ /**
+ * Create a new instance.
+ *
+ * @param mavenProjectBuilder
+ * maven project builder
+ */
+ @Inject
+ public TraceMojo(final ProjectBuilder mavenProjectBuilder)
+ {
+ this.mavenProjectBuilder = mavenProjectBuilder;
+ }
/**
- * Create a new instance
+ * Constructor used in unit tests.
+ *
+ * @param mavenProjectBuilder
+ * maven project builder
+ * @param project
+ * maven project
*/
- public TraceMojo()
+ TraceMojo(final ProjectBuilder mavenProjectBuilder, final MavenProject project)
{
- // Added default constructor to fix javadoc warning
+ this(mavenProjectBuilder);
+ this.project = project;
}
@Override
@@ -216,7 +245,7 @@ private static void createDir(final Path path)
}
}
- private ImportSettings createImportSettings()
+ ImportSettings createImportSettings()
{
final List sourcePaths = getSourcePaths();
logSourcePaths(sourcePaths);
@@ -228,14 +257,38 @@ private ImportSettings createImportSettings()
getLog().info("Tracing doc directory " + docPath.get());
settings.addInputs(docPath.get());
}
- if (artifactTypes != null)
+ final FilterSettings filterSettings = FilterSettings.builder()
+ .artifactTypes(getFilteredArtifactTypes())
+ .tags(getFilteredTags())
+ .withoutTags(isFilterWithoutTags())
+ .build();
+ settings.filter(filterSettings);
+ return settings.build();
+ }
+
+ private Set getFilteredArtifactTypes()
+ {
+ return artifactTypes == null ? emptySet() : artifactTypes;
+ }
+
+ private Set getFilteredTags()
+ {
+ if (tags == null)
{
- FilterSettings filterSettings = FilterSettings.builder()
- .artifactTypes(artifactTypes)
- .build();
- settings.filter(filterSettings);
+ return emptySet();
}
- return settings.build();
+ final Set copy = new HashSet<>(tags);
+ copy.remove(WILDCARD_TAG);
+ return copy;
+ }
+
+ private boolean isFilterWithoutTags()
+ {
+ if (tags == null || tags.isEmpty())
+ {
+ return true;
+ }
+ return tags.contains(WILDCARD_TAG);
}
private void logSourcePaths(final List sourcePaths)
@@ -245,7 +298,7 @@ private void logSourcePaths(final List sourcePaths)
return;
}
final Path baseDir = project.getBasedir().toPath();
- final List relativePaths = sourcePaths.stream().map(baseDir::relativize).collect(toList());
+ final List relativePaths = sourcePaths.stream().map(baseDir::relativize).toList();
getLog().info(
"Tracing " + sourcePaths.size() + " sub-directories of base dir " + baseDir + ": "
+ relativePaths);
@@ -284,15 +337,15 @@ private List getSourcePathOfProject(final MavenProject mavenProject)
final List compileSourceRoots = mavenProject.getCompileSourceRoots();
final List testCompileSourceRoots = mavenProject.getTestCompileSourceRoots();
final List resourceDirs = mavenProject.getResources().stream().map(Resource::getDirectory)
- .collect(toList());
+ .toList();
final List testResourceDirs = mavenProject.getTestResources().stream().map(Resource::getDirectory)
- .collect(toList());
+ .toList();
final Stream sourcePaths = Stream
.of(compileSourceRoots, resourceDirs, testCompileSourceRoots, testResourceDirs)
.flatMap(List::stream)
.map(Path::of)
.filter(Files::exists);
- return Stream.concat(sourcePathsOfSubModules, sourcePaths).collect(toList());
+ return Stream.concat(sourcePathsOfSubModules, sourcePaths).toList();
}
private Optional getProjectSubPath(final String dir)
diff --git a/src/test/java/org/itsallcode/openfasttrace/maven/TraceMojoVerifierTest.java b/src/test/java/org/itsallcode/openfasttrace/maven/TraceMojoIT.java
similarity index 83%
rename from src/test/java/org/itsallcode/openfasttrace/maven/TraceMojoVerifierTest.java
rename to src/test/java/org/itsallcode/openfasttrace/maven/TraceMojoIT.java
index b76f574..5d7719a 100644
--- a/src/test/java/org/itsallcode/openfasttrace/maven/TraceMojoVerifierTest.java
+++ b/src/test/java/org/itsallcode/openfasttrace/maven/TraceMojoIT.java
@@ -16,12 +16,14 @@
import org.apache.maven.it.Verifier;
import org.hamcrest.MatcherAssert;
import org.junit.jupiter.api.*;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
import com.exasol.mavenpluginintegrationtesting.MavenIntegrationTestEnvironment;
-class TraceMojoVerifierTest
+class TraceMojoIT
{
- private static final Logger LOG = Logger.getLogger(TraceMojoVerifierTest.class.getName());
+ private static final Logger LOG = Logger.getLogger(TraceMojoIT.class.getName());
private static final Path BASE_TEST_DIR = Paths.get("src/test/resources").toAbsolutePath();
private static final String CURRENT_PLUGIN_VERSION = getCurrentProjectVersion();
private static final String OFT_GOAL = "org.itsallcode:openfasttrace-maven-plugin:" + CURRENT_PLUGIN_VERSION
@@ -37,12 +39,14 @@ class TraceMojoVerifierTest
private static final Path EMPTY_PROJECT = BASE_TEST_DIR.resolve("empty-project");
private static final Path SIMPLE_PROJECT = BASE_TEST_DIR.resolve("simple-project");
private static final Path PROJECT_WITH_PLUGINS = BASE_TEST_DIR.resolve("project-with-plugins");
+ private static final Path PROJECT_WITH_TAGS = BASE_TEST_DIR.resolve("project-with-tags");
private static final Path TRACING_DEFECTS = BASE_TEST_DIR.resolve("project-with-tracing-defects");
private static final Path TRACING_DEFECTS_FAIL_BUILD = BASE_TEST_DIR
.resolve("project-with-tracing-defects-fail-build");
private static final Path HTML_REPORT_PROJECT = BASE_TEST_DIR
.resolve("html-report");
- public static final Path PARTIAL_ARTIFACT_COVERAGE_PROJECT = BASE_TEST_DIR.resolve("project-with-partial-artifact-coverage");
+ public static final Path PARTIAL_ARTIFACT_COVERAGE_PROJECT = BASE_TEST_DIR
+ .resolve("project-with-partial-artifact-coverage");
private static MavenIntegrationTestEnvironment mvnITEnv;
@BeforeAll
@@ -65,8 +69,8 @@ void testTracingWithMultipleLanguages() throws Exception
verifier.setCliOptions(List.of("-pl ."));
verifier.executeGoals(List.of("generate-sources", "generate-test-sources", OFT_GOAL));
verifier.verifyErrorFreeLog();
- assertThat(fileContent(PROJECT_WITH_MULTIPLE_LANGUAGES.resolve("target/tracing-report.txt"))
- , equalTo("ok - 8 total\n"));
+ assertThat(fileContent(PROJECT_WITH_MULTIPLE_LANGUAGES.resolve("target/tracing-report.txt")),
+ equalTo("ok - 8 total\n"));
}
@Test
@@ -173,7 +177,7 @@ void testTracingFindsDefectsFailBuild()
() -> runTracingMojo(TRACING_DEFECTS_FAIL_BUILD));
assertAll(() -> assertThat(exception.getMessage(), containsString("Tracing found 1 defects out of 2 items")),
() -> assertThat(fileContent(TRACING_DEFECTS_FAIL_BUILD.resolve("target/tracing-report.txt")),
- containsString("not ok - 2 total, 1 defect")));
+ containsString("not ok - 2 total, 1 defect")));
}
@Test
@@ -183,7 +187,7 @@ void testHtmlReport() throws Exception
final String content = fileContent(HTML_REPORT_PROJECT.resolve("target/tracing-report.html"));
assertAll(() -> assertThat(content, containsString("✓ 3 total")),
- () ->assertThat(content, containsString("")));
+ () -> assertThat(content, containsString("")));
}
@Test
@@ -209,6 +213,35 @@ void testTracingSelectedArtifactTypes() throws Exception
equalTo("ok - 2 total\n"));
}
+ @ParameterizedTest(name = "wanted tags {0} finds {1} items")
+ @CsvSource(delimiter = ';', nullValues = "NULL", value =
+ { "NULL; 3", "tagA; 1", "tagB; 1", "tagA,tagB; 2", "tagA,tagB,_; 3", "tagC; 0", "_,tagA; 2",
+ // This should find 1 item but finds 3 due to a bug in OFT:
+ // https://github.com/itsallcode/openfasttrace/issues/432
+ "_; 3" })
+ void testTracingSelectedTags(final String tags, final int expectedItemCount) throws Exception
+ {
+ final Verifier verifier = mvnITEnv.getVerifier(PROJECT_WITH_TAGS);
+ verifier.addCliOption("-DfailBuild=false");
+ if (tags != null)
+ {
+ verifier.addCliOption("-Dtags=" + tags);
+ }
+ verifier.executeGoal(OFT_GOAL);
+ verifier.verifyErrorFreeLog();
+ final String expectedResult;
+ if (expectedItemCount > 0)
+ {
+ expectedResult = "not ok - %1$d total, %1$d defect".formatted(expectedItemCount);
+ }
+ else
+ {
+ expectedResult = "ok - 0 total";
+ }
+ assertThat(fileContent(PROJECT_WITH_TAGS.resolve("target/tracing-report.txt")),
+ containsString(expectedResult));
+ }
+
private static void runTracingMojo(final Path projectDir) throws Exception
{
final Verifier verifier = mvnITEnv.getVerifier(projectDir);
diff --git a/src/test/java/org/itsallcode/openfasttrace/maven/TraceMojoTest.java b/src/test/java/org/itsallcode/openfasttrace/maven/TraceMojoTest.java
new file mode 100644
index 0000000..8e006ce
--- /dev/null
+++ b/src/test/java/org/itsallcode/openfasttrace/maven/TraceMojoTest.java
@@ -0,0 +1,161 @@
+package org.itsallcode.openfasttrace.maven;
+
+import static java.util.Collections.emptySet;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.maven.model.Resource;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectBuilder;
+import org.itsallcode.matcher.auto.AutoMatcher;
+import org.itsallcode.openfasttrace.api.FilterSettings;
+import org.itsallcode.openfasttrace.api.importer.ImportSettings;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.io.TempDir;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+class TraceMojoTest
+{
+ @Mock
+ ProjectBuilder mavenProjectBuilderMock;
+ @Mock
+ MavenProject projectMock;
+ @TempDir
+ Path baseDir;
+
+ TraceMojo testee;
+
+ @BeforeEach
+ void setup()
+ {
+ this.testee = createMojo();
+ }
+
+ TraceMojo createMojo()
+ {
+ when(projectMock.getBasedir()).thenReturn(baseDir.toFile());
+ return new TraceMojo(mavenProjectBuilderMock, projectMock);
+ }
+
+ @Test
+ void createDefaultImportSettings()
+ {
+ testee.artifactTypes = null;
+ assertThat(testee.createImportSettings(), AutoMatcher.equalTo(ImportSettings.builder().build()));
+ }
+
+ @Test
+ void createImportSettingsAddsSourceRootPaths() throws IOException
+ {
+ final Path compileSrcPath = baseDir.resolve("src");
+ final Path testCompileSrcPath = baseDir.resolve("test");
+ Files.createDirectories(compileSrcPath);
+ Files.createDirectories(testCompileSrcPath);
+ when(projectMock.getCompileSourceRoots()).thenReturn(List.of(compileSrcPath.toString()));
+ when(projectMock.getTestCompileSourceRoots()).thenReturn(List.of(testCompileSrcPath.toString()));
+
+ assertImportSettings(ImportSettings.builder().addInputs(compileSrcPath, testCompileSrcPath));
+ }
+
+ @Test
+ void createImportSettingsAddsResourcesDir() throws IOException
+ {
+ final Path resourcesPath = baseDir.resolve("res");
+ Files.createDirectories(resourcesPath);
+ when(projectMock.getResources()).thenReturn(List.of(resource(resourcesPath)));
+
+ assertImportSettings(ImportSettings.builder().addInputs(resourcesPath));
+ }
+
+ private static Resource resource(final Path directory)
+ {
+ final Resource resource = new Resource();
+ resource.setDirectory(directory.toString());
+ return resource;
+ }
+
+ @Test
+ void createImportSettingsAddsDocPath() throws IOException
+ {
+ final Path docDir = baseDir.resolve("doc");
+ Files.createDirectories(docDir);
+
+ assertImportSettings(ImportSettings.builder().addInputs(docDir));
+ }
+
+ @Test
+ void createImportSettingsWithNullArtifactTypes()
+ {
+ testee.artifactTypes = null;
+ assertFilterSettings(FilterSettings.builder());
+ }
+
+ @Test
+ void createImportSettingsWithEmptyArtifactTypes()
+ {
+ testee.artifactTypes = emptySet();
+ assertFilterSettings(FilterSettings.builder());
+ }
+
+ @Test
+ void createImportSettingsWithArtifactTypes()
+ {
+ testee.artifactTypes = Set.of("feat", "req");
+ assertFilterSettings(FilterSettings.builder().artifactTypes(Set.of("feat", "req")));
+ }
+
+ @Test
+ void createImportSettingsWithNullTags()
+ {
+ testee.tags = null;
+ assertFilterSettings(FilterSettings.builder());
+ }
+
+ @Test
+ void createImportSettingsWithEmptyTags()
+ {
+ testee.tags = emptySet();
+ assertFilterSettings(FilterSettings.builder());
+ }
+
+ @Test
+ void createImportSettingsWithTags()
+ {
+ testee.tags = Set.of("tag1", "tag2");
+ assertFilterSettings(FilterSettings.builder().tags(Set.of("tag1", "tag2")).withoutTags(false));
+ }
+
+ @Test
+ void createImportSettingsWithWildcardTag()
+ {
+ testee.tags = Set.of("_", "tag1", "tag2");
+ assertFilterSettings(FilterSettings.builder().tags(Set.of("tag1", "tag2")).withoutTags(true));
+ }
+
+ @Test
+ void createImportSettingsWithOnlyWildcardTag()
+ {
+ testee.tags = Set.of("_");
+ assertFilterSettings(FilterSettings.builder().tags(emptySet()).withoutTags(true));
+ }
+
+ private void assertImportSettings(final ImportSettings.Builder importSettingsBuilder)
+ {
+ assertThat(testee.createImportSettings(), AutoMatcher.equalTo(importSettingsBuilder.build()));
+ }
+
+ private void assertFilterSettings(final FilterSettings.Builder filterSettingsBuilder)
+ {
+ assertImportSettings(ImportSettings.builder().filter(filterSettingsBuilder.build()));
+ }
+}
diff --git a/src/test/resources/project-with-tags/doc/spec.md b/src/test/resources/project-with-tags/doc/spec.md
new file mode 100644
index 0000000..25433a6
--- /dev/null
+++ b/src/test/resources/project-with-tags/doc/spec.md
@@ -0,0 +1,13 @@
+# Without Tag
+`dsn~without-tag~1`
+Needs: impl
+
+# With Tag A
+`dsn~with-tag-a~1`
+Tags: tagA
+Needs: impl
+
+# With Tag B
+`dsn~with-tag-b~1`
+Tags: tagB
+Needs: impl
diff --git a/src/test/resources/project-with-tags/pom.xml b/src/test/resources/project-with-tags/pom.xml
new file mode 100644
index 0000000..70e1448
--- /dev/null
+++ b/src/test/resources/project-with-tags/pom.xml
@@ -0,0 +1,36 @@
+
+
+ 4.0.0
+
+ org.itsallcode
+ openfasttrace-maven-plugin-test
+ 0.0.0
+ jar
+
+
+ 17
+ 17
+ UTF-8
+
+
+
+
+
+ org.itsallcode
+ openfasttrace-maven-plugin
+
+
+ trace-requirements
+
+ trace
+
+
+
+
+ plain
+
+
+
+
+