diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0e3cd61..0f11bd5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,9 +37,9 @@ jobs: java-version: | 17 21 - cache: 'gradle' - - uses: gradle/actions/wrapper-validation@v3 + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 - name: Cache SonarQube packages uses: actions/cache@v4 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index f92cf94..fa4dd1a 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -30,9 +30,9 @@ jobs: with: distribution: 'temurin' java-version: 17 - cache: 'gradle' - - uses: gradle/actions/wrapper-validation@v3 + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 - name: Initialize CodeQL uses: github/codeql-action/init@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index aff7e65..79ea2cc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -35,7 +35,9 @@ jobs: with: distribution: "temurin" java-version: 17 - cache: "gradle" + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 - name: Build run: ./gradlew build --warning-mode all diff --git a/.vscode/settings.json b/.vscode/settings.json index e411722..73fd29d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { "editor.formatOnSave": true, - "editor.formatOnSaveMode": "modifications", + "editor.formatOnSaveMode": "file", "editor.codeActionsOnSave": { "source.organizeImports": "explicit", "source.generate.finalModifiers": "explicit", diff --git a/CHANGELOG.md b/CHANGELOG.md index 50a67d2..ed3bca8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [3.0.1] - 2024-09-07 + +- [PR #48](https://github.com/itsallcode/openfasttrace-gradle/pull/48) + - Fixed option `filteredArtifactTypes` + - Upgrade dependencies + ## [3.0.0] - 2024-06-16 - [Issue #26](https://github.com/itsallcode/openfasttrace-gradle/issues/26) - Added option `failBuild` that lets the build fail when it finds defects - - **Breaking Change:** `failBuild` is set to `true` by default. To keep the previous behaviour use `failBuild = false` in your build. + - **Breaking Change:** `failBuild` is set to `true` by default. To keep the previous behavior use `failBuild = false` in your build. ## [2.0.0] - 2024-06-13 diff --git a/README.md b/README.md index 9d6cb2b..27009bf 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,9 @@ Gradle plugin for the requirement tracing suite [OpenFastTrace](https://github.c 1. Preconditions: Java 17 and Gradle 8.6 1. Add plugin [`org.itsallcode.openfasttrace`](https://plugins.gradle.org/plugin/org.itsallcode.openfasttrace) to your project: - ```gradle + ```groovy plugins { - id "org.itsallcode.openfasttrace" version "3.0.0" + id "org.itsallcode.openfasttrace" version "3.0.1" } ``` @@ -34,7 +34,7 @@ Gradle plugin for the requirement tracing suite [OpenFastTrace](https://github.c ### General Configuration -```gradle +```groovy requirementTracing { failBuild = true inputDirectories = files('custom-dir') @@ -42,6 +42,7 @@ requirementTracing { reportFormat = 'plain' reportVerbosity = 'failure_details' detailsSectionDisplay = 'collapse' + filteredArtifactTypes = ["req", "dsn"] } ``` @@ -64,12 +65,13 @@ You can configure the following properties: * `detailsSectionDisplay`: Initial display status of the details section in the HTML report * `collapse` - hide details (default) * `expand` - show details +* `filteredArtifactTypes`: Use only the listed artifact types during tracing ### Configuring the Short Tag Importer The short tag importer allows omitting artifact type and the covered artifact type. Optionally you can add a prefix to the item name, e.g. a common module name. -```gradle +```groovy requirementTracing { tags { tag { @@ -110,7 +112,7 @@ Example: The Software Architecture Design project `swad` contains overall requir If you want to publish requirements to a Maven repository you can use the following configuration in your `build.gradle`: -```gradle +```groovy plugins { id 'org.itsallcode.openfasttrace' id 'maven-publish' @@ -140,7 +142,7 @@ See [publish-config](https://github.com/itsallcode/openfasttrace-gradle/tree/mai You can import requirements from another project using the `importedRequirements` configuration. The requirements must be published to a repository as a zip file and can be referenced using the usual gradle dependency syntax: -```gradle +```groovy repositories { maven { url "http://repo.example.com/maven2" diff --git a/build.gradle b/build.gradle index e0b1d35..bd1a741 100644 --- a/build.gradle +++ b/build.gradle @@ -2,11 +2,11 @@ plugins { id 'java-gradle-plugin' id 'jacoco' id 'signing' - id 'com.gradle.plugin-publish' version '1.2.1' - id 'org.sonarqube' version '5.0.0.4638' + id 'com.gradle.plugin-publish' version '1.2.2' + id 'org.sonarqube' version '5.1.0.4882' id 'pl.droidsonroids.jacoco.testkit' version '1.0.12' id 'com.github.ben-manes.versions' version '0.51.0' - id 'org.sonatype.gradle.plugins.scan' version '2.8.2' + id 'org.sonatype.gradle.plugins.scan' version '2.8.3' } repositories { @@ -15,13 +15,13 @@ repositories { apply from: 'gradle/workAroundJacocoGradleTestKitIssueOnWindows.gradle' -version = '3.0.0' +version = '3.0.1' group = 'org.itsallcode' ext { gradlePluginId = 'org.itsallcode.openfasttrace' - oftVersion = '4.0.0' - junitVersion = '5.10.2' + oftVersion = '4.1.0' + junitVersion = '5.11.0' if (project.hasProperty('oftSourceDir')) { oftSourceDir = file(project.oftSourceDir) useOftSources = oftSourceDir.exists() @@ -60,13 +60,12 @@ dependencies { } def getJavaVersion = { - return project.hasProperty('javaVersion') ? project.getProperty('javaVersion') : 17 + return project.hasProperty('javaVersion') ? project.getProperty('javaVersion') : 17 } java { toolchain { - def javaVersion = getJavaVersion() - languageVersion = JavaLanguageVersion.of(javaVersion) + languageVersion = JavaLanguageVersion.of(getJavaVersion()) } modularity.inferModulePath = false } @@ -126,7 +125,7 @@ testing { useJUnitJupiter(junitVersion) dependencies { implementation "org.junit.jupiter:junit-jupiter-params:$junitVersion" - implementation "org.hamcrest:hamcrest-core:2.2" + implementation "org.hamcrest:hamcrest-core:3.0" implementation "com.jparams:to-string-verifier:1.4.8" } } diff --git a/example-projects/custom-config/build.gradle b/example-projects/custom-config/build.gradle index 9109998..9c30279 100644 --- a/example-projects/custom-config/build.gradle +++ b/example-projects/custom-config/build.gradle @@ -3,10 +3,13 @@ plugins { id 'org.itsallcode.openfasttrace' } +def artifactTypes = findProperty('filteredArtifactTypes') +artifactTypes = artifactTypes ? artifactTypes.split(',').toList() : null requirementTracing { failBuild = findProperty('failBuild') == 'true' inputDirectories = files('custom-dir') reportFile = file('build/custom-report.txt') reportFormat = 'plain' reportVerbosity = 'ALL' + filteredArtifactTypes = artifactTypes } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e644113..a4b76b9 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a441313..9355b41 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index b740cf1..f5feea6 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 7101f8e..9b42019 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## diff --git a/src/main/java/org/itsallcode/openfasttrace/gradle/config/TracingConfig.java b/src/main/java/org/itsallcode/openfasttrace/gradle/config/TracingConfig.java index 6948940..035f030 100644 --- a/src/main/java/org/itsallcode/openfasttrace/gradle/config/TracingConfig.java +++ b/src/main/java/org/itsallcode/openfasttrace/gradle/config/TracingConfig.java @@ -6,8 +6,7 @@ import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.RegularFileProperty; import org.gradle.api.plugins.ExtensionAware; -import org.gradle.api.provider.ListProperty; -import org.gradle.api.provider.Property; +import org.gradle.api.provider.*; import org.itsallcode.openfasttrace.api.DetailsSectionDisplay; import org.itsallcode.openfasttrace.api.report.ReportVerbosity; @@ -21,8 +20,8 @@ public class TracingConfig private final ConfigurableFileCollection inputDirectories; private final RegularFileProperty reportFile; private final ListProperty importedRequirements; - private final ListProperty filteredTags; - private final ListProperty filteredArtifactTypes; + private final SetProperty filteredTags; + private final SetProperty filteredArtifactTypes; private final Property filterAcceptsItemsWithoutTag; private final Property detailsSectionDisplay; private final Property failBuild; @@ -36,8 +35,8 @@ public TracingConfig(final Project project) this.reportFormat = project.getObjects().property(String.class); this.reportFormat.set(DEFAULT_REPORT_FORMAT); this.importedRequirements = project.getObjects().listProperty(Object.class); - this.filteredTags = project.getObjects().listProperty(String.class); - this.filteredArtifactTypes = project.getObjects().listProperty(String.class); + this.filteredTags = project.getObjects().setProperty(String.class); + this.filteredArtifactTypes = project.getObjects().setProperty(String.class); this.filterAcceptsItemsWithoutTag = project.getObjects().property(Boolean.class); this.filterAcceptsItemsWithoutTag.set(true); this.detailsSectionDisplay = project.getObjects().property(DetailsSectionDisplay.class); @@ -71,12 +70,12 @@ public ListProperty getImportedRequirements() return importedRequirements; } - public ListProperty getFilteredTags() + public SetProperty getFilteredTags() { return filteredTags; } - public ListProperty getFilteredArtifactTypes() + public SetProperty getFilteredArtifactTypes() { return filteredArtifactTypes; } @@ -161,6 +160,7 @@ public String toString() { return "TracingConfig [reportVerbosity=" + reportVerbosity + ", inputDirectories=" + inputDirectories + ", reportFile=" + reportFile + ", pathConfig=" - + getTagPathConfig() + ", failBuild=" + failBuild + "]"; + + getTagPathConfig() + ", failBuild=" + failBuild + ", filteredArtifactTypes=" + + filteredArtifactTypes + "]"; } } diff --git a/src/main/java/org/itsallcode/openfasttrace/gradle/task/TraceTask.java b/src/main/java/org/itsallcode/openfasttrace/gradle/task/TraceTask.java index 3da8a33..a1af6fd 100644 --- a/src/main/java/org/itsallcode/openfasttrace/gradle/task/TraceTask.java +++ b/src/main/java/org/itsallcode/openfasttrace/gradle/task/TraceTask.java @@ -1,5 +1,6 @@ package org.itsallcode.openfasttrace.gradle.task; +import static java.util.Collections.emptySet; import static java.util.stream.Collectors.toList; import java.io.File; @@ -70,6 +71,7 @@ public SetProperty getImportedRequirements() } @Input + @Optional public SetProperty getFilteredArtifactTypes() { return filteredArtifactTypes; @@ -119,15 +121,26 @@ public void trace() getLogger().info("Tracing result: {} total items, {} defects. Writing report to {}", trace.count(), trace.countDefects(), reportPath); oft.reportToPath(trace, reportPath, getReportSettings()); - if (trace.countDefects() > 0 && shouldFailBuild()) + if (trace.countDefects() > 0) { - throw new IllegalStateException("Requirement tracing found " + trace.countDefects() - + " defects. See report at " + reportPath + " for details."); + final String message = "Requirement tracing found " + trace.countDefects() + + " defects. See report at " + reportPath + " for details."; + if (shouldFailBuild()) + { + throw new IllegalStateException(message); + } + getLogger().warn(message); + } + else + { + getLogger().info("Requirement tracing completed successfully."); } } private ReportSettings getReportSettings() { + getLogger().info("Report settings: verbosity={}, format={}, detailsSectionDisplay={}", + reportVerbosity.get(), reportFormat.get(), detailsSectionDisplay.get()); return ReportSettings.builder() // .verbosity(reportVerbosity.get()) // .outputFormat(reportFormat.get()) // @@ -147,13 +160,14 @@ private ImportSettings getImportSettings() private FilterSettings getFilterSettings() { - getLogger().info("Filter: artifactTypes={}, tags={}, acceptItemsWithoutTag={}", - filteredArtifactTypes.get(), filteredTags.get(), - filterAcceptsItemsWithoutTag.get()); - return FilterSettings.builder() // - .artifactTypes(filteredArtifactTypes.get()) // + final FilterSettings settings = FilterSettings.builder() // + .artifactTypes(filteredArtifactTypes.getOrElse(emptySet())) // .tags(filteredTags.get()) // .withoutTags(filterAcceptsItemsWithoutTag.get()).build(); + getLogger().info("Filter settings: artifactTypes={}, tags={}, acceptItemsWithoutTag={}", + settings.getArtifactTypes(), settings.getTags(), + settings.isArtifactTypeCriteriaSet()); + return settings; } private List getAllImportFiles() diff --git a/src/test/java/org/itsallcode/openfasttrace/gradle/GradleTestConfig.java b/src/test/java/org/itsallcode/openfasttrace/gradle/GradleTestConfig.java index b4a055d..62386c0 100644 --- a/src/test/java/org/itsallcode/openfasttrace/gradle/GradleTestConfig.java +++ b/src/test/java/org/itsallcode/openfasttrace/gradle/GradleTestConfig.java @@ -6,7 +6,7 @@ public enum GradleTestConfig /** * We support the latest Gradle version and the previous two. */ - EIGHT_SIX("8.6"), EIGHT_SEVEN("8.7"), EIGHT_EIGHT("8.8"); + EIGHT_EIGHT("8.8"), EIGHT_NINE("8.9"), EIGHT_TEN("8.10"); public final String gradleVersion; diff --git a/src/test/java/org/itsallcode/openfasttrace/gradle/OpenFastTracePluginTest.java b/src/test/java/org/itsallcode/openfasttrace/gradle/OpenFastTracePluginTest.java index 4d19550..b562a30 100644 --- a/src/test/java/org/itsallcode/openfasttrace/gradle/OpenFastTracePluginTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/gradle/OpenFastTracePluginTest.java @@ -64,44 +64,44 @@ void testCollectExampleProjectWithCustomConfig(final GradleTestConfig config) th assertFileContent(PROJECT_CUSTOM_CONFIG_DIR.resolve("build/reports/requirements.xml"), "\n" + // "", // - """ - - - exampleB\ - """, """ - - approved - 0 - """, // - - """ - 1 - - - dsn:exampleB - 1 - - - """, // - - """ - - - exampleB - Tracing Example - approved - 1 - """, // - - """ - 2 - Example requirement - - utest - impl - - - """, // + """ + + + exampleB\ + """, """ + + approved + 0 + """, // + + """ + 1 + + + dsn:exampleB + 1 + + + """, // + + """ + + + exampleB + Tracing Example + approved + 1 + """, // + + """ + 2 + Example requirement + + utest + impl + + + """, // " \n" + // ""); @@ -167,6 +167,15 @@ void testTraceExampleProjectWithCustomConfigFailBuild(final GradleTestConfig con "not ok - 2 total, 1 defect"); } + @ParameterizedTest(name = "filteredArtifactTypes {0}") + @EnumSource + void filteredArtifactTypes(final GradleTestConfig config) throws IOException + { + final BuildResult buildResult = runBuild(config, PROJECT_CUSTOM_CONFIG_DIR, "clean", + "traceRequirements", "-PfailBuild=true", "-PfilteredArtifactTypes=dsn"); + assertEquals(TaskOutcome.SUCCESS, buildResult.task(":traceRequirements").getOutcome()); + } + @ParameterizedTest(name = "testTraceExampleProjectWithCustomConfigFailBuild {0}") @EnumSource void testTraceExampleProjectWithCustomConfigFailBuildErrorMessage(final GradleTestConfig config) @@ -231,27 +240,26 @@ void testPublishToMavenRepo(final GradleTestConfig config) throws IOException assertThat(entryContent, containsString("\n" + // "\n")); assertThat(entryContent, containsString(""" - - - exampleB - Tracing Example - approved - 1\ - """)); + + + exampleB + Tracing Example + approved + 1\ + """)); assertThat(entryContent, containsString(""" - 2 - Example requirement - - utest - impl - - - """)); + 2 + Example requirement + + utest + impl + + + """)); } } - private static String readEntry(final ZipFile zip, final String entryName) - throws IOException + private static String readEntry(final ZipFile zip, final String entryName) throws IOException { final ZipArchiveEntry reqirementsEntry = zip.getEntry(entryName); try (BufferedReader reader = new BufferedReader(