![JAR search and dependency download from the Maven repository](/logo.png)
org.apache.maven.plugins.checkstyle.CheckstyleViolationCheckMojo Maven / Gradle / Ivy
Show all versions of maven-checkstyle-plugin Show documentation
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.plugins.checkstyle;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.puppycrawl.tools.checkstyle.DefaultLogger;
import com.puppycrawl.tools.checkstyle.SarifLogger;
import com.puppycrawl.tools.checkstyle.XMLLogger;
import com.puppycrawl.tools.checkstyle.api.AuditListener;
import com.puppycrawl.tools.checkstyle.api.AutomaticBean.OutputStreamOptions;
import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginManagement;
import org.apache.maven.model.Resource;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.plugins.checkstyle.exec.CheckstyleExecutor;
import org.apache.maven.plugins.checkstyle.exec.CheckstyleExecutorException;
import org.apache.maven.plugins.checkstyle.exec.CheckstyleExecutorRequest;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.configuration.PlexusConfiguration;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.PathTool;
import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.xml.pull.MXParser;
import org.codehaus.plexus.util.xml.pull.XmlPullParser;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
/**
* Performs Checkstyle analysis and outputs violations or a count of violations
* to the console, potentially failing the build.
* It can also be configured to re-use an earlier analysis.
*
* @author Joakim Erdfelt
*
*/
@Mojo(
name = "check",
defaultPhase = LifecyclePhase.VERIFY,
requiresDependencyResolution = ResolutionScope.NONE,
threadSafe = true)
public class CheckstyleViolationCheckMojo extends AbstractMojo {
private static final String JAVA_FILES = "**\\/*.java";
private static final String DEFAULT_CONFIG_LOCATION = "sun_checks.xml";
/**
* Specifies the path and filename to save the Checkstyle output. The format
* of the output file is determined by the outputFileFormat
* parameter.
*/
@Parameter(property = "checkstyle.output.file", defaultValue = "${project.build.directory}/checkstyle-result.xml")
private File outputFile;
/**
* Specifies the format of the output to be used when writing to the output
* file. Valid values are "plain
", "sarif
" and "xml
".
*/
@Parameter(property = "checkstyle.output.format", defaultValue = "xml")
private String outputFileFormat;
/**
* Fail the build on a violation. The goal checks for the violations
* after logging them (if {@link #logViolationsToConsole} is {@code true}).
* Compare this to {@link #failsOnError} which fails the build immediately
* before examining the output log.
*/
@Parameter(property = "checkstyle.failOnViolation", defaultValue = "true")
private boolean failOnViolation;
/**
* The maximum number of allowed violations. The execution fails only if the
* number of violations is above this limit.
*
* @since 2.3
*/
@Parameter(property = "checkstyle.maxAllowedViolations", defaultValue = "0")
private int maxAllowedViolations;
/**
* The lowest severity level that is considered a violation.
* Valid values are "error
", "warning
" and "info
".
*
* @since 2.2
*/
@Parameter(property = "checkstyle.violationSeverity", defaultValue = "error")
private String violationSeverity = "error";
/**
* Violations to ignore. This is a comma-separated list, each value being either
* a rule name, a rule category or a java package name of rule class.
*
* @since 2.13
*/
@Parameter(property = "checkstyle.violation.ignore")
private String violationIgnore;
/**
* Skip entire check.
*
* @since 2.2
*/
@Parameter(property = "checkstyle.skip", defaultValue = "false")
private boolean skip;
/**
* Skip Checkstyle execution will only scan the outputFile.
*
* @since 2.5
*/
@Parameter(property = "checkstyle.skipExec", defaultValue = "false")
private boolean skipExec;
/**
* Output the detected violations to the console.
*
* @since 2.3
*/
@Parameter(property = "checkstyle.console", defaultValue = "true")
private boolean logViolationsToConsole;
/**
* Output the detected violation count to the console.
*
* @since 3.0.1
*/
@Parameter(property = "checkstyle.logViolationCount", defaultValue = "true")
private boolean logViolationCountToConsole;
/**
* Specifies the location of the resources to be used for Checkstyle.
*
* @since 2.11
*/
@Parameter(defaultValue = "${project.resources}", readonly = true)
protected List resources;
/**
* Specifies the location of the test resources to be used for Checkstyle.
*
* @since 2.16
*/
@Parameter(defaultValue = "${project.testResources}", readonly = true)
protected List testResources;
/**
*
* Specifies the location of the XML configuration to use.
*
* Potential values are a filesystem path, a URL, or a classpath resource.
* This parameter expects that the contents of the location conform to the
* xml format (Checkstyle Checker
* module) configuration of rulesets.
*
* This parameter is resolved as resource, URL, then file. If successfully
* resolved, the contents of the configuration is copied into the
* ${project.build.directory}/checkstyle-configuration.xml
* file before being passed to Checkstyle as a configuration.
*
* There are 2 predefined rulesets.
*
* sun_checks.xml
: Sun Checks.
* google_checks.xml
: Google Checks.
*
*
* @since 2.5
*/
@Parameter(property = "checkstyle.config.location", defaultValue = DEFAULT_CONFIG_LOCATION)
private String configLocation;
/**
*
* Specifies the location of the properties file.
*
* This parameter is resolved as URL, File then resource. If successfully
* resolved, the contents of the properties location is copied into the
* ${project.build.directory}/checkstyle-checker.properties
* file before being passed to Checkstyle for loading.
*
* The contents of the propertiesLocation
will be made
* available to Checkstyle for specifying values for parameters within the
* xml configuration (specified in the configLocation
* parameter).
*
* @since 2.5
*/
@Parameter(property = "checkstyle.properties.location")
private String propertiesLocation;
/**
* Allows for specifying raw property expansion information.
*/
@Parameter
private String propertyExpansion;
/**
*
* Specifies the location of the License file (a.k.a. the header file) that
* can be used by Checkstyle to verify that source code has the correct
* license header.
*
* You need to use ${checkstyle.header.file}
in your Checkstyle xml
* configuration to reference the name of this header file.
*
* For instance:
*
* <module name="RegexpHeader">
* <property name="headerFile" value="${checkstyle.header.file}"/>
* </module>
*
*
* @since 2.0-beta-2
*/
@Parameter(property = "checkstyle.header.file", defaultValue = "LICENSE.txt")
private String headerLocation;
/**
* Specifies the cache file used to speed up Checkstyle on successive runs.
*/
@Parameter(defaultValue = "${project.build.directory}/checkstyle-cachefile")
private String cacheFile;
/**
* The key to be used in the properties for the suppressions file.
*
* @since 2.1
*/
@Parameter(property = "checkstyle.suppression.expression", defaultValue = "checkstyle.suppressions.file")
private String suppressionsFileExpression;
/**
*
* Specifies the location of the suppressions XML file to use.
*
* This parameter is resolved as resource, URL, then file. If successfully
* resolved, the contents of the suppressions XML is copied into the
* ${project.build.directory}/checkstyle-suppressions.xml
file
* before being passed to Checkstyle for loading.
*
* See suppressionsFileExpression
for the property that will
* be made available to your Checkstyle configuration.
*
* @since 2.0-beta-2
*/
@Parameter(property = "checkstyle.suppressions.location")
private String suppressionsLocation;
/**
* The file encoding to use when reading the source files. If the property project.build.sourceEncoding
* is not set, the platform default encoding is used. Note: This parameter always overrides the
* property charset
from Checkstyle's TreeWalker
module.
*
* @since 2.2
*/
@Parameter(property = "encoding", defaultValue = "${project.build.sourceEncoding}")
private String inputEncoding;
/**
* @since 2.5
*/
@Component(role = CheckstyleExecutor.class, hint = "default")
protected CheckstyleExecutor checkstyleExecutor;
/**
* Output errors to console.
*/
@Parameter(property = "checkstyle.consoleOutput", defaultValue = "false")
private boolean consoleOutput;
/**
* The Maven Project Object.
*/
@Parameter(defaultValue = "${project}", readonly = true, required = true)
protected MavenProject project;
/**
* The Plugin Descriptor
*/
@Parameter(defaultValue = "${plugin}", readonly = true, required = true)
private PluginDescriptor plugin;
/**
* If null
, the Checkstyle plugin will display violations on stdout.
* Otherwise, a text file will be created with the violations.
*/
@Parameter
private File useFile;
/**
* Specifies the names filter of the source files to be excluded for
* Checkstyle.
*/
@Parameter(property = "checkstyle.excludes")
private String excludes;
/**
* Specifies the names filter of the source files to be used for Checkstyle.
*/
@Parameter(property = "checkstyle.includes", defaultValue = JAVA_FILES, required = true)
private String includes;
/**
* Specifies the names filter of the files to be excluded for
* Checkstyle when checking resources.
* @since 2.11
*/
@Parameter(property = "checkstyle.resourceExcludes")
private String resourceExcludes;
/**
* Specifies the names filter of the files to be used for Checkstyle when checking resources.
* @since 2.11
*/
@Parameter(property = "checkstyle.resourceIncludes", defaultValue = "**/*.properties", required = true)
private String resourceIncludes;
/**
* If this is true, and Checkstyle reported any violations or errors,
* the build fails immediately after running Checkstyle, before checking the log
* for {@link #logViolationsToConsole}. If you want to use {@link #logViolationsToConsole},
* use {@link #failOnViolation} instead of this.
*/
@Parameter(defaultValue = "false")
private boolean failsOnError;
/**
* Specifies the location of the test source directory to be used for Checkstyle.
*
* @since 2.2
* @deprecated instead use {@link #testSourceDirectories}. For version 3.0.0, this parameter is only defined to
* break the build if you use it!
*/
@Deprecated
@Parameter
private File testSourceDirectory;
/**
* Specifies the location of the test source directories to be used for Checkstyle.
* Default value is ${project.testCompileSourceRoots}
.
* @since 2.13
*/
// Compatibility with all Maven 3: default of 'project.testCompileSourceRoots' is done manually because of MNG-5440
@Parameter
private List testSourceDirectories;
/**
* Include or not the test source directory to be used for Checkstyle.
*
* @since 2.2
*/
@Parameter(defaultValue = "false")
private boolean includeTestSourceDirectory;
/**
* Specifies the location of the source directory to be used for Checkstyle.
*
* @deprecated instead use {@link #sourceDirectories}. For version 3.0.0, this parameter is only defined to break
* the build if you use it!
*/
@Deprecated
@Parameter
private File sourceDirectory;
/**
* Specifies the location of the source directories to be used for Checkstyle.
* Default value is ${project.compileSourceRoots}
.
* @since 2.13
*/
// Compatibility with all Maven 3: default of 'project.compileSourceRoots' is done manually because of MNG-5440
@Parameter
private List sourceDirectories;
/**
* Whether to apply Checkstyle to resource directories.
* @since 2.11
*/
@Parameter(property = "checkstyle.includeResources", defaultValue = "true", required = true)
private boolean includeResources = true;
/**
* Whether to apply Checkstyle to test resource directories.
* @since 2.11
*/
@Parameter(property = "checkstyle.includeTestResources", defaultValue = "true", required = true)
private boolean includeTestResources = true;
/**
* By using this property, you can specify the whole Checkstyle rules
* inline directly inside this pom.
*
*
* <plugin>
* ...
* <configuration>
* <checkstyleRules>
* <module name="Checker">
* <module name="FileTabCharacter">
* <property name="eachLine" value="true" />
* </module>
* <module name="TreeWalker">
* <module name="EmptyBlock"/>
* </module>
* </module>
* </checkstyleRules>
* </configuration>
* ...
*
*
* @since 2.12
*/
@Parameter
private PlexusConfiguration checkstyleRules;
/**
* Dump file for inlined Checkstyle rules.
*/
@Parameter(
property = "checkstyle.output.rules.file",
defaultValue = "${project.build.directory}/checkstyle-rules.xml")
private File rulesFiles;
/**
* The header to use for the inline configuration.
* Only used when you specify {@code checkstyleRules}.
*/
@Parameter(
defaultValue = "\n"
+ "\n")
private String checkstyleRulesHeader;
/**
* Specifies whether modules with a configured severity of ignore
should be omitted during Checkstyle
* invocation.
*
* @since 3.0.0
*/
@Parameter(defaultValue = "false")
private boolean omitIgnoredModules;
/**
* Specifies whether generated source files should be excluded from Checkstyle.
*
* @since 3.3.1
*/
@Parameter(property = "checkstyle.excludeGeneratedSources", defaultValue = "false")
private boolean excludeGeneratedSources;
private ByteArrayOutputStream stringOutputStream;
private File outputXmlFile;
/** {@inheritDoc} */
public void execute() throws MojoExecutionException, MojoFailureException {
checkDeprecatedParameterUsage(sourceDirectory, "sourceDirectory", "sourceDirectories");
checkDeprecatedParameterUsage(testSourceDirectory, "testSourceDirectory", "testSourceDirectories");
if (skip) {
return;
}
outputXmlFile = outputFile;
if (!skipExec) {
String effectiveConfigLocation = configLocation;
if (checkstyleRules != null) {
if (!DEFAULT_CONFIG_LOCATION.equals(configLocation)) {
throw new MojoExecutionException(
"If you use inline configuration for rules, don't specify " + "a configLocation");
}
if (checkstyleRules.getChildCount() > 1) {
throw new MojoExecutionException("Currently only one root module is supported");
}
PlexusConfiguration checkerModule = checkstyleRules.getChild(0);
try {
FileUtils.forceMkdir(rulesFiles.getParentFile());
FileUtils.fileWrite(rulesFiles, checkstyleRulesHeader + checkerModule.toString());
} catch (final IOException e) {
throw new MojoExecutionException(e.getMessage(), e);
}
effectiveConfigLocation = rulesFiles.getAbsolutePath();
}
ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
try {
CheckstyleExecutorRequest request = new CheckstyleExecutorRequest();
request.setConsoleListener(getConsoleListener())
.setConsoleOutput(consoleOutput)
.setExcludes(excludes)
.setFailsOnError(failsOnError)
.setIncludes(includes)
.setResourceIncludes(resourceIncludes)
.setResourceExcludes(resourceExcludes)
.setIncludeResources(includeResources)
.setIncludeTestResources(includeTestResources)
.setIncludeTestSourceDirectory(includeTestSourceDirectory)
.setListener(getListener())
.setProject(project)
.setSourceDirectories(getSourceDirectories())
.setResources(resources)
.setTestResources(testResources)
.setStringOutputStream(stringOutputStream)
.setSuppressionsLocation(suppressionsLocation)
.setTestSourceDirectories(getTestSourceDirectories())
.setConfigLocation(effectiveConfigLocation)
.setConfigurationArtifacts(collectArtifacts("config"))
.setPropertyExpansion(propertyExpansion)
.setHeaderLocation(headerLocation)
.setLicenseArtifacts(collectArtifacts("license"))
.setCacheFile(cacheFile)
.setSuppressionsFileExpression(suppressionsFileExpression)
.setEncoding(inputEncoding)
.setPropertiesLocation(propertiesLocation)
.setOmitIgnoredModules(omitIgnoredModules);
checkstyleExecutor.executeCheckstyle(request);
} catch (CheckstyleException e) {
throw new MojoExecutionException("Failed during checkstyle configuration", e);
} catch (CheckstyleExecutorException e) {
throw new MojoExecutionException("Failed during checkstyle execution", e);
} finally {
// be sure to restore original context classloader
Thread.currentThread().setContextClassLoader(currentClassLoader);
}
}
if (!"xml".equals(outputFileFormat) && skipExec) {
throw new MojoExecutionException("Output format is '" + outputFileFormat
+ "', checkstyle:check requires format to be 'xml' when using skipExec.");
}
if (!outputXmlFile.exists()) {
getLog().info("Unable to perform checkstyle:check, unable to find checkstyle:checkstyle outputFile.");
return;
}
try (Reader reader = new BufferedReader(ReaderFactory.newXmlReader(outputXmlFile))) {
XmlPullParser xpp = new MXParser();
xpp.setInput(reader);
final List violationsList = getViolations(xpp);
long violationCount = countViolations(violationsList);
printViolations(violationsList);
String msg = "You have " + violationCount + " Checkstyle violation"
+ ((violationCount > 1 || violationCount == 0) ? "s" : "") + ".";
if (violationCount > maxAllowedViolations) {
if (failOnViolation) {
if (maxAllowedViolations > 0) {
msg += " The maximum number of allowed violations is " + maxAllowedViolations + ".";
}
throw new MojoFailureException(msg);
}
getLog().warn("checkstyle:check violations detected but failOnViolation set to false");
}
if (logViolationCountToConsole) {
if (maxAllowedViolations > 0) {
msg += " The maximum number of allowed violations is " + maxAllowedViolations + ".";
}
getLog().info(msg);
}
} catch (IOException | XmlPullParserException e) {
throw new MojoExecutionException(
"Unable to read Checkstyle results xml: " + outputXmlFile.getAbsolutePath(), e);
}
}
private void checkDeprecatedParameterUsage(Object parameter, String name, String replacement)
throws MojoFailureException {
if (parameter != null) {
throw new MojoFailureException("You are using '" + name + "' which has been removed"
+ " from the maven-checkstyle-plugin. " + "Please use '" + replacement
+ "' and refer to the >>Major Version Upgrade to version 3.0.0<< " + "on the plugin site.");
}
}
private List getViolations(XmlPullParser xpp) throws XmlPullParserException, IOException {
List violations = new ArrayList<>();
String basedir = project.getBasedir().getAbsolutePath();
String file = "";
for (int eventType = xpp.getEventType(); eventType != XmlPullParser.END_DOCUMENT; eventType = xpp.next()) {
if (eventType != XmlPullParser.START_TAG) {
continue;
} else if ("file".equals(xpp.getName())) {
file = PathTool.getRelativeFilePath(basedir, xpp.getAttributeValue("", "name"));
continue;
} else if (!"error".equals(xpp.getName())) {
continue;
}
String severity = xpp.getAttributeValue("", "severity");
String source = xpp.getAttributeValue("", "source");
String line = xpp.getAttributeValue("", "line");
/* Nullable */
String column = xpp.getAttributeValue("", "column");
String message = xpp.getAttributeValue("", "message");
String rule = RuleUtil.getName(source);
String category = RuleUtil.getCategory(source);
Violation violation = new Violation(source, file, line, severity, message, rule, category);
if (column != null) {
violation.setColumn(column);
}
violations.add(violation);
}
return violations;
}
private int countViolations(List violations) {
List ignores = violationIgnore == null
? Collections.emptyList()
: RuleUtil.parseMatchers(violationIgnore.split(","));
int ignored = 0;
int countedViolations = 0;
for (Violation violation : violations) {
if (!isViolation(violation.getSeverity())) {
continue;
}
if (ignore(ignores, violation.getSource())) {
ignored++;
continue;
}
countedViolations++;
}
if (ignored > 0) {
getLog().info("Ignored " + ignored + " error" + ((ignored > 1L) ? "s" : "") + ", " + countedViolations
+ " violation" + ((countedViolations > 1) ? "s" : "") + " remaining.");
}
return countedViolations;
}
private void printViolations(List violations) {
if (!logViolationsToConsole) {
return;
}
List ignores = violationIgnore == null
? Collections.emptyList()
: RuleUtil.parseMatchers(violationIgnore.split(","));
violations.stream()
.filter(violation -> isViolation(violation.getSeverity()))
.filter(violation -> !ignore(ignores, violation.getSource()))
.forEach(violation -> {
final String message = String.format(
"%s:[%s%s] (%s) %s: %s",
violation.getFile(),
violation.getLine(),
(Violation.NO_COLUMN.equals(violation.getColumn())) ? "" : (',' + violation.getColumn()),
violation.getCategory(),
violation.getRuleName(),
violation.getMessage());
log(violation.getSeverity(), message);
});
}
private void log(String severity, String message) {
if ("info".equals(severity)) {
getLog().info(message);
} else if ("warning".equals(severity)) {
getLog().warn(message);
} else {
getLog().error(message);
}
}
/**
* Checks if the given severity is considered a violation.
*
* @param severity The severity to check
* @return true
if the given severity is a violation, otherwise false
*/
private boolean isViolation(String severity) {
if ("error".equals(severity)) {
return "error".equals(violationSeverity)
|| "warning".equals(violationSeverity)
|| "info".equals(violationSeverity);
} else if ("warning".equals(severity)) {
return "warning".equals(violationSeverity) || "info".equals(violationSeverity);
} else if ("info".equals(severity)) {
return "info".equals(violationSeverity);
} else {
return false;
}
}
private boolean ignore(List ignores, String source) {
for (RuleUtil.Matcher ignore : ignores) {
if (ignore.match(source)) {
return true;
}
}
return false;
}
private DefaultLogger getConsoleListener() throws MojoExecutionException {
DefaultLogger consoleListener;
if (useFile == null) {
stringOutputStream = new ByteArrayOutputStream();
consoleListener = new DefaultLogger(stringOutputStream, OutputStreamOptions.NONE);
} else {
OutputStream out = getOutputStream(useFile);
consoleListener = new DefaultLogger(out, OutputStreamOptions.CLOSE);
}
return consoleListener;
}
private OutputStream getOutputStream(File file) throws MojoExecutionException {
File parentFile = file.getAbsoluteFile().getParentFile();
if (!parentFile.exists()) {
parentFile.mkdirs();
}
FileOutputStream fileOutputStream;
try {
fileOutputStream = new FileOutputStream(file);
} catch (FileNotFoundException e) {
throw new MojoExecutionException("Unable to create output stream: " + file, e);
}
return fileOutputStream;
}
private AuditListener getListener() throws MojoFailureException, MojoExecutionException {
AuditListener listener = null;
if (outputFileFormat != null && !outputFileFormat.isEmpty()) {
File resultFile = outputFile;
OutputStream out = getOutputStream(resultFile);
if ("xml".equals(outputFileFormat)) {
listener = new XMLLogger(out, OutputStreamOptions.CLOSE);
} else if ("plain".equals(outputFileFormat)) {
try {
// Write a plain output file to the standard output file,
// and write an XML output file to the temp directory that can be used to count violations
outputXmlFile =
Files.createTempFile("checkstyle-result", ".xml").toFile();
outputXmlFile.deleteOnExit();
OutputStream xmlOut = getOutputStream(outputXmlFile);
CompositeAuditListener compoundListener = new CompositeAuditListener();
compoundListener.addListener(new XMLLogger(xmlOut, OutputStreamOptions.CLOSE));
compoundListener.addListener(new DefaultLogger(out, OutputStreamOptions.CLOSE));
listener = compoundListener;
} catch (IOException e) {
throw new MojoExecutionException("Unable to create temporary file", e);
}
} else if ("sarif".equals(outputFileFormat)) {
try {
// Write a sarif output file to the standard output file,
// and write an XML output file to the temp directory that can be used to count violations
outputXmlFile =
Files.createTempFile("checkstyle-result", ".xml").toFile();
outputXmlFile.deleteOnExit();
OutputStream xmlOut = getOutputStream(outputXmlFile);
CompositeAuditListener compoundListener = new CompositeAuditListener();
compoundListener.addListener(new XMLLogger(xmlOut, OutputStreamOptions.CLOSE));
compoundListener.addListener(new SarifLogger(out, OutputStreamOptions.CLOSE));
listener = compoundListener;
} catch (IOException e) {
throw new MojoExecutionException("Unable to create temporary file", e);
}
} else {
throw new MojoFailureException(
"Invalid output file format: (" + outputFileFormat + "). Must be 'plain' or 'xml'.");
}
}
return listener;
}
private List collectArtifacts(String hint) {
List artifacts = new ArrayList<>();
PluginManagement pluginManagement = project.getBuild().getPluginManagement();
if (pluginManagement != null) {
artifacts.addAll(getCheckstylePluginDependenciesAsArtifacts(pluginManagement.getPluginsAsMap(), hint));
}
artifacts.addAll(
getCheckstylePluginDependenciesAsArtifacts(project.getBuild().getPluginsAsMap(), hint));
return artifacts;
}
private List getCheckstylePluginDependenciesAsArtifacts(Map plugins, String hint) {
List artifacts = new ArrayList<>();
Plugin checkstylePlugin = plugins.get(plugin.getGroupId() + ":" + plugin.getArtifactId());
if (checkstylePlugin != null) {
for (Dependency dep : checkstylePlugin.getDependencies()) {
// @todo if we can filter on hints, it should be done here...
String depKey = dep.getGroupId() + ":" + dep.getArtifactId();
artifacts.add(plugin.getArtifactMap().get(depKey));
}
}
return artifacts;
}
private List getSourceDirectories() {
if (sourceDirectories == null) {
sourceDirectories = filterBuildTarget(project.getCompileSourceRoots());
}
List sourceDirs = new ArrayList<>(sourceDirectories.size());
for (String sourceDir : sourceDirectories) {
sourceDirs.add(FileUtils.resolveFile(project.getBasedir(), sourceDir));
}
return sourceDirs;
}
private List getTestSourceDirectories() {
if (testSourceDirectories == null) {
testSourceDirectories = filterBuildTarget(project.getTestCompileSourceRoots());
}
List testSourceDirs = new ArrayList<>(testSourceDirectories.size());
for (String testSourceDir : testSourceDirectories) {
testSourceDirs.add(FileUtils.resolveFile(project.getBasedir(), testSourceDir));
}
return testSourceDirs;
}
private List filterBuildTarget(List sourceDirectories) {
if (!excludeGeneratedSources) {
return sourceDirectories;
}
List filtered = new ArrayList<>(sourceDirectories.size());
Path buildTarget = FileUtils.resolveFile(
project.getBasedir(), project.getBuild().getDirectory())
.toPath();
for (String sourceDir : sourceDirectories) {
Path src = FileUtils.resolveFile(project.getBasedir(), sourceDir).toPath();
if (!src.startsWith(buildTarget)) {
filtered.add(sourceDir);
}
}
return filtered;
}
}