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
6 changes: 6 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@
"java.sources.organizeImports.staticStarThreshold": 3,
"java.configuration.updateBuildConfiguration": "automatic",
"java.compile.nullAnalysis.mode": "automatic",
"java.test.config": {
"vmArgs": [
"--add-opens",
"java.base/java.lang=ALL-UNNAMED"
]
},
"sonarlint.connectedMode.project": {
"connectionId": "itsallcode",
"projectKey": "org.itsallcode:openfasttrace-gradle"
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#81](https://github.com/itsallcode/openfasttrace-gradle/issues/81):
- Ensure compatibility with Gradle configuration cache
- Mark plugin as compatible with configuration cache
- [PR #85](https://github.com/itsallcode/openfasttrace-gradle/pull/85):
- Allow configuring color schema
- Configuration values for details section display and report verbosity are now case insensitive
- Improve error messages for invalid enum values

## [3.2.0] - 2026-08-18

Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,12 @@ You can configure the following properties:
* `failures` - list of defect specification items
* `failure_summaries` - list of summaries for defect specification items
* `failure_details` - summaries and details for defect specification items (default)
* `direct_failure_details` - details of non-transitive unclean items (added in OFT 4.6.0)
* `all` - summaries and details for all specification items
* `reportColorScheme`: Color scheme of plain text report
* `black_and_white` - Black and white (default)
* `monochrome` - Monochrome (e.g for printers)
* `color` - Color
* `detailsSectionDisplay`: Initial display status of the details section in the HTML report
* `collapse` - hide details (default)
* `expand` - show details
Expand Down
4 changes: 3 additions & 1 deletion example-projects/custom-config/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ requirementTracing {
inputDirectories = files('custom-dir')
reportFile = file('build/custom-report.txt')
reportFormat = 'plain'
reportVerbosity = 'ALL'
reportVerbosity = 'all'
reportColorScheme = findProperty('reportColorScheme')
detailsSectionDisplay = 'collapse'
filteredArtifactTypes = artifactTypes
filterWantedStatuses = wantedStatuses
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ private static void configureTask(final Project rootProject,
.get()));
}
task.getReportVerbosity().set(config.getReportVerbosity());
task.getReportColorScheme().set(config.getReportColorScheme());
task.getReportFormat().set(config.getReportFormat());
task.getImportedRequirements()
.from(getImportedRequirements(rootProject, rootProject.getAllprojects()));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package org.itsallcode.openfasttrace.gradle.config;

import java.util.List;
import java.util.Set;
import static java.util.stream.Collectors.joining;

import java.util.*;
import java.util.stream.Collectors;

import org.gradle.api.Project;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.plugins.ExtensionAware;
import org.gradle.api.provider.*;
import org.itsallcode.openfasttrace.api.ColorScheme;
import org.itsallcode.openfasttrace.api.DetailsSectionDisplay;
import org.itsallcode.openfasttrace.api.report.ReportVerbosity;

Expand All @@ -18,6 +21,7 @@ public class TracingConfig
private static final String DEFAULT_REPORT_FORMAT = "plain";

private final Property<ReportVerbosity> reportVerbosity;
private final Property<ColorScheme> reportColorScheme;
private final Property<String> reportFormat;
private final ConfigurableFileCollection inputDirectories;
private final RegularFileProperty reportFile;
Expand All @@ -41,6 +45,7 @@ public TracingConfig(final Project project)
this.reportFile = project.getObjects().fileProperty();
this.reportVerbosity = project.getObjects().property(ReportVerbosity.class);
this.reportVerbosity.set(DEFAULT_REPORT_VERBOSITY);
this.reportColorScheme = project.getObjects().property(ColorScheme.class);
this.reportFormat = project.getObjects().property(String.class);
this.reportFormat.set(DEFAULT_REPORT_FORMAT);
this.importedRequirements = project.getObjects().listProperty(Object.class);
Expand All @@ -65,6 +70,16 @@ public Property<ReportVerbosity> getReportVerbosity()
return reportVerbosity;
}

/**
* Returns the report color scheme.
*
* @return the color scheme
*/
public Property<ColorScheme> getReportColorScheme()
{
return reportColorScheme;
}

/**
* Returns the report format property.
*
Expand Down Expand Up @@ -163,7 +178,28 @@ public SetProperty<String> getFilterWantedStatuses()
*/
public void setReportVerbosity(final String reportVerbosity)
{
setReportVerbosity(ReportVerbosity.valueOf(reportVerbosity));
this.setReportVerbosity(convertVerbosity(reportVerbosity));
}

private static ReportVerbosity convertVerbosity(final String reportVerbosity)
{
if (reportVerbosity == null)
{
return null;
}
try
{
return ReportVerbosity.valueOf(reportVerbosity.toUpperCase(Locale.ROOT));
}
catch (final IllegalArgumentException e)
{
final String validVerbosities = Arrays.stream(ReportVerbosity.values()).map(ReportVerbosity::name)
.collect(joining(", "));
throw new IllegalArgumentException(
"Invalid verbosity '" + reportVerbosity + "'. Valid verbosities are: "
+ validVerbosities,
e);
}
}

/**
Expand All @@ -177,6 +213,49 @@ public void setReportVerbosity(final ReportVerbosity reportVerbosity)
this.reportVerbosity.set(reportVerbosity);
}

/**
* Sets the report color scheme.
*
* @param reportColorScheme
* color scheme to use
*/
public void setReportColorScheme(final String reportColorScheme)
{
this.setReportColorScheme(convertColorScheme(reportColorScheme));
}

private static ColorScheme convertColorScheme(final String reportColorScheme)
{
if (reportColorScheme == null)
{
return null;
}
try
{
return ColorScheme.valueOf(reportColorScheme.toUpperCase(Locale.ROOT));
}
catch (final IllegalArgumentException e)
{
final String validColorSchemes = Arrays.stream(ColorScheme.values()).map(ColorScheme::name)
.collect(joining(", "));
throw new IllegalArgumentException(
"Invalid color scheme '" + reportColorScheme + "'. Valid color schemes are: "
+ validColorSchemes,
e);
}
}

/**
* Sets the report color scheme.
*
* @param reportColorScheme
* color scheme to use
*/
public void setReportColorScheme(final ColorScheme reportColorScheme)
{
this.reportColorScheme.set(reportColorScheme);
}

/**
* Sets the report format.
*
Expand Down Expand Up @@ -254,6 +333,17 @@ public void setFilterAcceptsItemsWithoutTag(final boolean filterAcceptsItemsWith
this.filterAcceptsItemsWithoutTag.set(filterAcceptsItemsWithoutTag);
}

/**
* Sets the report details section display setting by name.
*
* @param detailsSectionDisplay
* display setting name
*/
public void setDetailsSectionDisplay(final DetailsSectionDisplay detailsSectionDisplay)
{
this.detailsSectionDisplay.set(detailsSectionDisplay);
}

/**
* Sets the report details section display setting by name.
*
Expand All @@ -262,7 +352,28 @@ public void setFilterAcceptsItemsWithoutTag(final boolean filterAcceptsItemsWith
*/
public void setDetailsSectionDisplay(final String detailsSectionDisplay)
{
this.detailsSectionDisplay.set(DetailsSectionDisplay.valueOf(detailsSectionDisplay));
this.setDetailsSectionDisplay(convertDetailsSelectionDisplay(detailsSectionDisplay));
}

private static DetailsSectionDisplay convertDetailsSelectionDisplay(final String detailsSectionDisplay)
{
if (detailsSectionDisplay == null)
{
return null;
}
try
{
return DetailsSectionDisplay.valueOf(detailsSectionDisplay.toUpperCase(Locale.ROOT));
}
catch (final IllegalArgumentException e)
{
final String validValues = Arrays.stream(DetailsSectionDisplay.values()).map(Enum::name)
.collect(Collectors.joining(", "));
throw new IllegalArgumentException(
"Invalid details section display '" + detailsSectionDisplay + "'. Valid values are: "
+ validValues,
e);
}
}

/**
Expand Down Expand Up @@ -310,8 +421,8 @@ public void setFailBuild(final boolean failBuild)
@Override
public String toString()
{
return "TracingConfig [reportVerbosity=" + reportVerbosity + ", inputDirectories="
+ inputDirectories + ", reportFile=" + reportFile + ", pathConfig="
return "TracingConfig [reportVerbosity=" + reportVerbosity + ", reportColorScheme=" + reportColorScheme
+ ", inputDirectories=" + inputDirectories + ", reportFile=" + reportFile + ", pathConfig="
+ getTagPathConfig() + ", failBuild=" + failBuild + ", filteredArtifactTypes="
+ filteredArtifactTypes + ", filterWantedStatuses=" + filterWantedStatuses + "]";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.gradle.api.provider.SetProperty;
import org.gradle.api.tasks.*;
import org.itsallcode.openfasttrace.api.*;
import org.itsallcode.openfasttrace.api.ReportSettings.Builder;
import org.itsallcode.openfasttrace.api.core.*;
import org.itsallcode.openfasttrace.api.importer.ImportSettings;
import org.itsallcode.openfasttrace.api.report.ReportVerbosity;
Expand All @@ -25,10 +26,14 @@
@CacheableTask
public class TraceTask extends DefaultTask
{
private static final ColorScheme DEFAULT_COLOR_SCHEME = ColorScheme.BLACK_AND_WHITE;

private final RegularFileProperty requirementsFile = getProject().getObjects().fileProperty();
private final RegularFileProperty outputFile = getProject().getObjects().fileProperty();
private final Property<ReportVerbosity> reportVerbosity = getProject().getObjects()
.property(ReportVerbosity.class);
private final Property<ColorScheme> reportColorScheme = getProject().getObjects()
.property(ColorScheme.class);
private final Property<String> reportFormat = getProject().getObjects().property(String.class);
private final Property<DetailsSectionDisplay> detailsSectionDisplay = getProject().getObjects()
.property(DetailsSectionDisplay.class);
Expand Down Expand Up @@ -83,6 +88,18 @@ public Property<ReportVerbosity> getReportVerbosity()
return reportVerbosity;
}

/**
* Get the report color scheme property.
*
* @return the color scheme property
*/
@Input
@Optional
public Property<ColorScheme> getReportColorScheme()
{
return reportColorScheme;
}

/**
* Returns the report format property.
*
Expand Down Expand Up @@ -213,22 +230,23 @@ public void trace()

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()) //
.showOrigin(true) //
.newline(Newline.UNIX) //
.detailsSectionDisplay(detailsSectionDisplay.get()) //
.build();
getLogger().info("Report settings: verbosity={}, format={}, detailsSectionDisplay={}, colorScheme={}",
reportVerbosity.get(), reportFormat.get(), detailsSectionDisplay.get(), reportColorScheme.getOrNull());
final Builder builder = ReportSettings.builder()
.verbosity(reportVerbosity.get())
.outputFormat(reportFormat.get())
.showOrigin(true)
.newline(Newline.UNIX)
.detailsSectionDisplay(detailsSectionDisplay.get())
.colorScheme(reportColorScheme.getOrElse(DEFAULT_COLOR_SCHEME));
return builder.build();
}

private ImportSettings getImportSettings()
{
return ImportSettings.builder() //
.addInputs(getAllImportFiles()) //
.filter(getFilterSettings()) //
return ImportSettings.builder()
.addInputs(getAllImportFiles())
.filter(getFilterSettings())
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,21 @@ void filteredWantedStatusesInvalidStatus()
"Invalid status 'invalid'. Valid statuses are: APPROVED, PROPOSED, DRAFT, REJECTED"));
}

@Test
void reportColorSchemeColor()
{
fixture(PROJECT_CUSTOM_CONFIG_DIR)
.withoutBuildCache()
.withArgs("clean", "traceRequirements", "-PreportColorScheme=color")
.withReportFile(Path.of("build/custom-report.txt"))
.run()
.assertTraceOutcomeSuccess()
.assertOutput(containsString(
"Report settings: verbosity=ALL, format=plain, detailsSectionDisplay=COLLAPSE, colorScheme=COLOR"))
.assertReportFileLines(
"\u001B[91mnot ok\u001B[0m - 2 total, 1 direct, 0 transitive defects");
}

@Test
void testTraceExampleProjectWithCustomConfigFailBuildErrorMessage()
{
Expand Down
Loading
Loading