forked from phoedos/pmd
[cli] Add exit code for processing errors (#4991)
Merge pull request #4991 from adangel:cli-exit-codes-processing-errors
This commit is contained in:
commit
e93ca46b5a
@ -5,6 +5,7 @@ tags: [userdocs]
|
||||
keywords: [command, line, options, help, formats, renderers]
|
||||
permalink: pmd_userdocs_cli_reference.html
|
||||
author: Tom Copeland <tom@infoether.com>, Xavier Le Vourch <xlv@users.sourceforge.net>, Juan Martín Sotuyo Dodero <juansotuyo@gmail.com>
|
||||
last_updated: June 2024 (7.3.0)
|
||||
---
|
||||
|
||||
|
||||
@ -19,7 +20,6 @@ The tool comes with a rather extensive help text, simply running with `--help`!
|
||||
<th>Default value</th>
|
||||
<th>Applies to</th>
|
||||
</tr>
|
||||
|
||||
{% include custom/cli_option_row.html options="--rulesets,-R"
|
||||
option_arg="refs"
|
||||
description="Path to a ruleset xml file. The path may reference
|
||||
@ -55,7 +55,6 @@ The tool comes with a rather extensive help text, simply running with `--help`!
|
||||
(\":\" on Linux, \";\" on Windows) is used to separate the entries.
|
||||
Alternatively, a single `file:` URL
|
||||
to a text file containing path elements on consecutive lines can be specified.
|
||||
|
||||
<p>See also [Providing the auxiliary classpath](pmd_languages_java.html#providing-the-auxiliary-classpath).</p>"
|
||||
languages="Java"
|
||||
%}
|
||||
@ -80,10 +79,15 @@ The tool comes with a rather extensive help text, simply running with `--help`!
|
||||
The valid values are the standard character sets of `java.nio.charset.Charset`."
|
||||
default="UTF-8"
|
||||
%}
|
||||
{% include custom/cli_option_row.html options="--[no-]fail-on-error"
|
||||
description="Specifies whether PMD exits with non-zero status if recoverable errors occurred.
|
||||
By default PMD exits with status 5 if recoverable errors occurred (whether there are violations or not).
|
||||
Disable this option with `--no-fail-on-error` to exit with 0 instead. In any case, a report with the found violations will be written."
|
||||
%}
|
||||
{% include custom/cli_option_row.html options="--[no-]fail-on-violation"
|
||||
description="Specifies whether PMD exits with non-zero status if violations are found.
|
||||
By default PMD exits with status 4 if violations are found.
|
||||
Disable this feature with `--no-fail-on-violation` to exit with 0 instead and just output the report."
|
||||
Disable this feature with `--no-fail-on-violation` to exit with 0 instead. In any case a report with the found violations will be written."
|
||||
%}
|
||||
{% include custom/cli_option_row.html options="--file-list"
|
||||
option_arg="filepath"
|
||||
@ -98,9 +102,7 @@ The tool comes with a rather extensive help text, simply running with `--help`!
|
||||
by extension is disabled and PMD tries to parse all files with
|
||||
the given language `<lang>`. Parsing errors are ignored and unparsable files
|
||||
are skipped.
|
||||
|
||||
<p>Use `--use-version` to specify the language version to use, if it is not the default.</p>
|
||||
|
||||
<p>This option allows to use the xml language for files, that don't
|
||||
use xml as extension. See [example](#analyze-other-xml-formats) below.</p>"
|
||||
%}
|
||||
@ -125,7 +127,7 @@ The tool comes with a rather extensive help text, simply running with `--help`!
|
||||
{% include custom/cli_option_row.html options="--minimum-priority"
|
||||
option_arg="priority"
|
||||
description="Rule priority threshold; rules with lower priority than configured here won't be used.
|
||||
Valid values (case insensitive): High, Medium_High, Medium, Medium_Low, Low.
|
||||
Valid values (case-insensitive): High, Medium_High, Medium, Medium_Low, Low.
|
||||
An integer between 1 (High) and 5 (Low) is also supported. See [Configuring rules](pmd_userdocs_configuring_rules.html)
|
||||
on how to override priorities in custom rulesets."
|
||||
default="Low"
|
||||
@ -141,7 +143,7 @@ The tool comes with a rather extensive help text, simply running with `--help`!
|
||||
description="Enables / disable progress bar indicator of live analysis progress. This ie enabled by default."
|
||||
%}
|
||||
{% include custom/cli_option_row.html options="--property,-P"
|
||||
option_arg="name>=<value"
|
||||
option_arg="name>=<value"
|
||||
description="Specifies a property for the report renderer. The option can be specified several times.
|
||||
<p>Using `--help` will provide a complete list of supported properties for each report format</p>"
|
||||
%}
|
||||
@ -208,16 +210,23 @@ Or you can set the environment variable `CLASSPATH` before starting PMD, e.g.
|
||||
|
||||
## Exit Status
|
||||
|
||||
Please note that if PMD detects any violations, it will exit with status 4 (since 5.3).
|
||||
Please note that if PMD detects any violations, it will exit with status 4 (since 5.3) or 5 (since 7.3.0).
|
||||
This behavior has been introduced to ease PMD integration into scripts or hooks, such as SVN hooks.
|
||||
|
||||
<table>
|
||||
<tr><td>0</td><td>Everything is fine, no violations found.</td></tr>
|
||||
<tr><td>0</td><td>Everything is fine, no violations found and no recoverable error occurred.</td></tr>
|
||||
<tr><td>1</td><td>PMD exited with an exception.</td></tr>
|
||||
<tr><td>2</td><td>Usage error. Command-line parameters are invalid or missing.</td></tr>
|
||||
<tr><td>4</td><td>At least one violation has been detected, unless <code>--no-fail-on-violation</code> is set.</td></tr>
|
||||
<tr><td>4</td><td>At least one violation has been detected, unless <code>--no-fail-on-violation</code> is set.<p>Since PMD 5.3.</p></td></tr>
|
||||
<tr><td>5</td><td>At least one recoverable error has occurred. There might be additionally zero or more violations detected.
|
||||
To ignore recoverable errors, use <code>--no-fail-on-error</code>.<p>Since PMD 7.3.0.</p></td></tr>
|
||||
</table>
|
||||
|
||||
{%include note.html content="If PMD exits with 5, then PMD had either trouble parsing one or more files or a rule failed with an exception.
|
||||
That means, that either no violations for the entire file or for that rule are reported. These cases can be considered as false-negatives.
|
||||
In any case, the root cause should be investigated. If it's a problem in PMD itself, please create a bug report. Recoverable errors
|
||||
are usually part of the generated PMD report." %}
|
||||
|
||||
## Logging
|
||||
|
||||
PMD internally uses [slf4j](https://www.slf4j.org/) and ships with slf4j-simple as the logging implementation.
|
||||
|
@ -4,7 +4,7 @@ tags: [cpd, userdocs]
|
||||
summary: "Learn how to use CPD, the copy-paste detector shipped with PMD."
|
||||
permalink: pmd_userdocs_cpd.html
|
||||
author: Tom Copeland <tom@infoether.com>
|
||||
last_updated: August 2023 (7.0.0)
|
||||
last_updated: June 2024 (7.3.0)
|
||||
---
|
||||
|
||||
## Overview
|
||||
@ -132,8 +132,8 @@ exactly identical.
|
||||
description="Don't scan subdirectories. By default, subdirectories are considered."
|
||||
%}
|
||||
{% include custom/cli_option_row.html options="--skip-lexical-errors"
|
||||
description="Skip files which can't be tokenized due to invalid characters instead of aborting CPD.
|
||||
By default, CPD analysis is stopped on the first error."
|
||||
description="<span class='label label-primary'>Deprecated</span> Skip files which can't be tokenized due to invalid characters instead of aborting CPD.
|
||||
By default, CPD analysis is stopped on the first error. This is deprecated. Use `--fail-on-error` instead."
|
||||
%}
|
||||
{% include custom/cli_option_row.html options="--format,-f"
|
||||
option_arg="format"
|
||||
@ -150,6 +150,11 @@ exactly identical.
|
||||
If the root path is mentioned (e.g. \"/\" or \"C:\\\"), then the paths will be rendered
|
||||
as absolute."
|
||||
%}
|
||||
{% include custom/cli_option_row.html options="--[no-]fail-on-error"
|
||||
description="Specifies whether CPD exits with non-zero status if recoverable errors occurred.
|
||||
By default CPD exits with status 5 if recoverable errors occurred (whether there are duplications or not).
|
||||
Disable this option with `--no-fail-on-error` to exit with 0 instead. In any case, a report with the found duplications will be written."
|
||||
%}
|
||||
{% include custom/cli_option_row.html options="--[no-]fail-on-violation"
|
||||
description="Specifies whether CPD exits with non-zero status if violations are found.
|
||||
By default CPD exits with status 4 if violations are found.
|
||||
@ -279,16 +284,22 @@ If you specify a source directory but don't want to scan the sub-directories, yo
|
||||
|
||||
### Exit status
|
||||
|
||||
Please note that if CPD detects duplicated source code, it will exit with status 4 (since 5.0).
|
||||
Please note that if CPD detects duplicated source code, it will exit with status 4 (since 5.0) or 5 (since 7.3.0).
|
||||
This behavior has been introduced to ease CPD integration into scripts or hooks, such as SVN hooks.
|
||||
|
||||
<table>
|
||||
<tr><td>0</td><td>Everything is fine, no code duplications found.</td></tr>
|
||||
<tr><td>0</td><td>Everything is fine, no code duplications found and no recoverable errors occurred.</td></tr>
|
||||
<tr><td>1</td><td>CPD exited with an exception.</td></tr>
|
||||
<tr><td>2</td><td>Usage error. Command-line parameters are invalid or missing.</td></tr>
|
||||
<tr><td>4</td><td>At least one code duplication has been detected unless <code>--no-fail-on-violation</code> is set.</td></tr>
|
||||
<tr><td>4</td><td>At least one code duplication has been detected unless <code>--no-fail-on-violation</code> is set.<p>Since PMD 5.0.</p></td></tr>
|
||||
<tr><td>5</td><td>At least one recoverable error has occurred. There might be additionally zero or more duplications detected.
|
||||
To ignore recoverable errors, use <code>--no-fail-on-error</code>.<p>Since PMD 7.3.0.</p></td></tr>
|
||||
</table>
|
||||
|
||||
{%include note.html content="If PMD exits with 5, then PMD had trouble lexing one or more files.
|
||||
That means, that no duplications for the entire file are reported. This can be considered as false-negative.
|
||||
In any case, the root cause should be investigated. If it's a problem in PMD itself, please create a bug report." %}
|
||||
|
||||
## Logging
|
||||
|
||||
PMD internally uses [slf4j](https://www.slf4j.org/) and ships with slf4j-simple as the logging implementation.
|
||||
@ -390,6 +401,10 @@ Andy Glover wrote an Ant task for CPD; here's how to use it:
|
||||
keep their encoding.<br />
|
||||
If not specified, CPD uses the system default encoding."
|
||||
%}
|
||||
{% include custom/cli_option_row.html options="failOnError"
|
||||
description="Whether to fail the build if any errors occurred while processing the files. Since PMD 7.3.0."
|
||||
default="true"
|
||||
%}
|
||||
{% include custom/cli_option_row.html options="format"
|
||||
description="The format of the report (e.g. `csv`, `text`, `xml`)."
|
||||
default="text"
|
||||
@ -424,8 +439,10 @@ Andy Glover wrote an Ant task for CPD; here's how to use it:
|
||||
default="false"
|
||||
%}
|
||||
{% include custom/cli_option_row.html options="skipLexicalErrors"
|
||||
description="Skip files which can't be tokenized due to invalid characters instead of aborting CPD."
|
||||
default="false"
|
||||
description="<span class='label label-primary'>Deprecated</span> Skip files which can't be tokenized
|
||||
due to invalid characters instead of aborting CPD. This parameter is deprecated and
|
||||
ignored since PMD 7.3.0. It is now by default true. Use `failOnError` instead to fail the build."
|
||||
default="true"
|
||||
%}
|
||||
{% include custom/cli_option_row.html options="skipBlocks"
|
||||
description="Enables or disabled skipping of blocks like a pre-processor. See also option skipBlocksPattern."
|
||||
|
@ -6,6 +6,7 @@ author: >
|
||||
David Dixon-Peugh <dpeugh@users.sourceforge.net>,
|
||||
Tom Copeland <tom@infoether.com>,
|
||||
Xavier Le Vourch <xlv@users.sourceforge.net>
|
||||
last_updated: June 2024 (7.3.0)
|
||||
---
|
||||
|
||||
## PMD
|
||||
@ -63,8 +64,8 @@ The examples below won't repeat this taskdef element, as this is always required
|
||||
<td>Yes, unless the ruleset nested element is used</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>failonerror</td>
|
||||
<td>Whether or not to fail the build if any errors occur while processing the files</td>
|
||||
<td>failOnError</td>
|
||||
<td>Whether or not to fail the build if any recoverable errors occurred while analyzing files.</td>
|
||||
<td>No</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -19,6 +19,8 @@ This is a {{ site.pmd.release_type }} release.
|
||||
when the keys are of an enum type. The specialized enum collections are more space- and time-efficient.
|
||||
|
||||
### 🐛 Fixed Issues
|
||||
* cli
|
||||
* [#2827](https://github.com/pmd/pmd/issues/2827): \[cli] Consider processing errors in exit status
|
||||
* core
|
||||
* [#4992](https://github.com/pmd/pmd/pull/4992): \[core] CPD: Include processing errors in XML report
|
||||
* apex
|
||||
@ -58,11 +60,42 @@ go back using the old format with the renderer "xmlold" ({%jdoc core::cpd.XMLOld
|
||||
this old renderer is deprecated and only there for compatibility reasons. Whatever tooling is used to
|
||||
read the XML format should be updated.
|
||||
|
||||
#### Deprecated for removal
|
||||
#### CLI
|
||||
|
||||
* core
|
||||
* New exit code 5 introduced. PMD and CPD will exit now by default with exit code 5, if any recoverable error
|
||||
(e.g. parsing exception, lexing exception or rule exception) occurred. PMD will still create a report with
|
||||
all detected violations or duplications if recoverable errors occurred. Such errors mean, that the report
|
||||
might be incomplete, as either violations or duplications for an entire file or for a specific rule are missing.
|
||||
These cases can be considered as false-negatives.
|
||||
|
||||
In any case, the root cause should be investigated. If it's a problem in PMD itself, please create a bug report.
|
||||
|
||||
* New CLI parameter `--no-fail-on-error` to ignore such errors and not exit with code 5. By default,
|
||||
a build with errors will now fail and with that parameter, the previous behavior can be restored.
|
||||
This parameter is available for both PMD and CPD.
|
||||
|
||||
* The CLI parameter `--skip-lexical-errors` is deprecated. By default, lexical errors are skipped but the
|
||||
build is failed. Use the new parameter `--[no-]fail-on-error` instead to control whether to fail the build or not.
|
||||
|
||||
#### Ant
|
||||
|
||||
* CPDTask has a new parameter `failOnError`. It controls, whether to fail the build if any recoverable error occurred.
|
||||
By default, the build will fail. CPD will still create a report with all detected duplications, but the report might
|
||||
be incomplete.
|
||||
* The parameter `skipLexicalError` in CPDTask is deprecated and ignored. Lexical errors are now always skipped.
|
||||
Use the new parameter `failOnError` instead to control whether to fail the build or not.
|
||||
|
||||
#### Deprecated API
|
||||
|
||||
* pmd-ant
|
||||
* {% jdoc !!ant::ant.CPDTask#setSkipLexicalErrors(boolean) %}: Use {% jdoc ant::ant.CPDTask#setFailOnError(boolean) %}
|
||||
instead to control, whether to ignore errors or fail the build.
|
||||
* pmd-core
|
||||
* {% jdoc !!core::cpd.CPDConfiguration#isSkipLexicalErrors() %} and {% jdoc core::cpd.CPDConfiguration#setSkipLexicalErrors(boolean) %}:
|
||||
Use {%jdoc core::AbstractConfiguration#setFailOnError(boolean) %} to control whether to ignore errors or fail the build.
|
||||
* {%jdoc !!core::cpd.XMLOldRenderer %} (the CPD format "xmlold").
|
||||
* pmd-java
|
||||
* {% jdoc !!java::lang.java.ast.ASTResource#getStableName() %} and the corresponding attribute `@StableName`.
|
||||
* {%jdoc !!java::lang.java.ast.ASTRecordPattern#getVarId() %} This method was added here by mistake. Record
|
||||
patterns don't declare a pattern variable for the whole pattern, but rather for individual record
|
||||
components, which can be accessed via {%jdoc java::lang.java.ast.ASTRecordPattern#getComponentPatterns() %}.
|
||||
|
@ -78,6 +78,7 @@ public class CPDTask extends Task {
|
||||
private boolean ignoreIdentifiers;
|
||||
private boolean ignoreAnnotations;
|
||||
private boolean ignoreUsings;
|
||||
@Deprecated
|
||||
private boolean skipLexicalErrors;
|
||||
private boolean skipDuplicateFiles;
|
||||
private boolean skipBlocks = true;
|
||||
@ -85,6 +86,7 @@ public class CPDTask extends Task {
|
||||
private File outputFile;
|
||||
private String encoding = System.getProperty("file.encoding");
|
||||
private List<FileSet> filesets = new ArrayList<>();
|
||||
private boolean failOnError = true;
|
||||
|
||||
@Override
|
||||
public void execute() throws BuildException {
|
||||
@ -102,7 +104,15 @@ public class CPDTask extends Task {
|
||||
config.setOnlyRecognizeLanguage(config.getLanguageRegistry().getLanguageById(language));
|
||||
config.setSourceEncoding(Charset.forName(encoding));
|
||||
config.setSkipDuplicates(skipDuplicateFiles);
|
||||
config.setSkipLexicalErrors(skipLexicalErrors);
|
||||
|
||||
if (skipLexicalErrors) {
|
||||
log("skipLexicalErrors is deprecated since 7.3.0 and the property is ignored. "
|
||||
+ "Lexical errors are now skipped by default and the build is failed. "
|
||||
+ "Use failOnError=\"false\" to not fail the build.", Project.MSG_WARN);
|
||||
}
|
||||
|
||||
// implicitly enable skipLexicalErrors, so that we can fail the build at the end. A report is created in any case.
|
||||
config.setSkipLexicalErrors(true);
|
||||
|
||||
config.setIgnoreAnnotations(ignoreAnnotations);
|
||||
config.setIgnoreLiterals(ignoreLiterals);
|
||||
@ -121,12 +131,20 @@ public class CPDTask extends Task {
|
||||
long timeTaken = System.currentTimeMillis() - start;
|
||||
log("Done analyzing code; that took " + timeTaken + " milliseconds");
|
||||
|
||||
int errors = config.getReporter().numErrors();
|
||||
if (errors > 0) {
|
||||
String message = String.format("There were %d recovered errors during analysis.", errors);
|
||||
if (failOnError) {
|
||||
throw new BuildException(message + " Ignore these with failOnError=\"true\".");
|
||||
} else {
|
||||
log(message + " Not failing build, because failOnError=\"false\".", Project.MSG_WARN);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
log(ioe.toString(), Project.MSG_ERR);
|
||||
throw new BuildException("IOException during task execution", ioe);
|
||||
} catch (ReportException re) {
|
||||
re.printStackTrace();
|
||||
log(re.toString(), Project.MSG_ERR);
|
||||
throw new BuildException("ReportException during task execution", re);
|
||||
} finally {
|
||||
@ -225,6 +243,10 @@ public class CPDTask extends Task {
|
||||
this.ignoreUsings = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #setFailOnError(boolean)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setSkipLexicalErrors(boolean skipLexicalErrors) {
|
||||
this.skipLexicalErrors = skipLexicalErrors;
|
||||
}
|
||||
@ -257,6 +279,15 @@ public class CPDTask extends Task {
|
||||
this.skipBlocksPattern = skipBlocksPattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to fail the build if any recoverable errors occurred while processing the files.
|
||||
*
|
||||
* @since 7.3.0
|
||||
*/
|
||||
public void setFailOnError(boolean failOnError) {
|
||||
this.failOnError = failOnError;
|
||||
}
|
||||
|
||||
public static class FormatAttribute extends EnumeratedAttribute {
|
||||
private static final String[] FORMATS = new String[] { XML_FORMAT, TEXT_FORMAT, CSV_FORMAT, XMLOLD_FORMAT };
|
||||
|
||||
|
@ -144,7 +144,7 @@ public class PMDTaskImpl {
|
||||
pmd.performAnalysis();
|
||||
stats = reportStatsListener.getResult();
|
||||
if (failOnError && pmd.getReporter().numErrors() > 0) {
|
||||
throw new BuildException("Some errors occurred while running PMD");
|
||||
throw new BuildException("Some recoverable errors occurred while running PMD");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ package net.sourceforge.pmd.ant;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -14,6 +15,7 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import org.apache.tools.ant.BuildException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@ -34,7 +36,25 @@ class CPDTaskTest extends AbstractAntTest {
|
||||
@Test
|
||||
void testBasic() throws IOException {
|
||||
executeTarget("testBasic");
|
||||
Path report = Paths.get("target/cpd.ant.tests");
|
||||
assertReport("target/cpd.ant.tests");
|
||||
}
|
||||
|
||||
@Test
|
||||
void failOnErrorDefault() throws IOException {
|
||||
BuildException buildException = assertThrows(BuildException.class, () -> executeTarget("failOnErrorDefault"));
|
||||
assertThat(buildException.getMessage(), containsString("There were 1 recovered errors during analysis."));
|
||||
assertReport("target/cpd.ant.tests");
|
||||
}
|
||||
|
||||
@Test
|
||||
void failOnErrorIgnore() throws IOException {
|
||||
executeTarget("failOnErrorIgnore");
|
||||
assertReport("target/cpd.ant.tests");
|
||||
assertThat(log.toString(), containsString("There were 1 recovered errors during analysis."));
|
||||
}
|
||||
|
||||
private static void assertReport(String path) throws IOException {
|
||||
Path report = Paths.get(path);
|
||||
assertTrue(Files.exists(report), "Report was not created");
|
||||
String reportContent = IOUtil.readFileToString(report.toFile(), StandardCharsets.UTF_8);
|
||||
assertThat(reportContent, containsString("Found a 1 line (21 tokens) duplication in the following files:"));
|
||||
|
@ -0,0 +1 @@
|
||||
:throw_lex_source_exception:
|
@ -11,7 +11,24 @@
|
||||
<cpd minimumTokenCount="20" outputFile="${pmd.home}/target/cpd.ant.tests" language="dummy">
|
||||
<fileset dir="${pmd.home}/${src}">
|
||||
<include name="**/*.dummy"/>
|
||||
<exclude name="sampleLexError.dummy"/>
|
||||
</fileset>
|
||||
</cpd>
|
||||
</target>
|
||||
|
||||
<target name="failOnErrorDefault">
|
||||
<cpd minimumTokenCount="20" outputFile="${pmd.home}/target/cpd.ant.tests" language="dummy">
|
||||
<fileset dir="${pmd.home}/${src}">
|
||||
<include name="**/*.dummy"/>
|
||||
</fileset>
|
||||
</cpd>
|
||||
</target>
|
||||
|
||||
<target name="failOnErrorIgnore">
|
||||
<cpd minimumTokenCount="20" outputFile="${pmd.home}/target/cpd.ant.tests" language="dummy" failOnError="false">
|
||||
<fileset dir="${pmd.home}/${src}">
|
||||
<include name="**/*.dummy"/>
|
||||
</fileset>
|
||||
</cpd>
|
||||
</target>
|
||||
</project>
|
||||
|
@ -16,4 +16,12 @@ Test Rule 2
|
||||
Test Rule 3
|
||||
</violation>
|
||||
</file>
|
||||
<file name="sampleLexError.dummy">
|
||||
<violation beginline="1" endline="1" begincolumn="1" endcolumn="30" rule="SampleXPathRule" ruleset="Test Ruleset" package="foo" externalInfoUrl="${pmd.website.baseurl}/rules/dummy/basic.xml#SampleXPathRule" priority="3">
|
||||
Test Rule 2
|
||||
</violation>
|
||||
<violation beginline="1" endline="1" begincolumn="1" endcolumn="30" rule="DeprecatedRule" ruleset="Test Ruleset" package="foo" externalInfoUrl="${pmd.website.baseurl}/rules/dummy/basic.xml#deprecatedrule" priority="3">
|
||||
Test Rule 3
|
||||
</violation>
|
||||
</file>
|
||||
</pmd>
|
||||
|
@ -43,11 +43,17 @@ public abstract class AbstractAnalysisPmdSubcommand<C extends AbstractConfigurat
|
||||
protected URI uri;
|
||||
|
||||
@Option(names = "--no-fail-on-violation",
|
||||
description = "By default PMD exits with status 4 if violations are found. "
|
||||
+ "Disable this option with '--no-fail-on-violation' to exit with 0 instead and just write the report.",
|
||||
description = "By default PMD exits with status 4 if violations or duplications are found. "
|
||||
+ "Disable this option with '--no-fail-on-violation' to exit with 0 instead. In any case a report with the found violations or duplications will be written.",
|
||||
defaultValue = "true", negatable = true)
|
||||
protected boolean failOnViolation;
|
||||
|
||||
@Option(names = "--no-fail-on-error",
|
||||
description = "By default PMD exits with status 5 if recoverable errors occurred (whether or not there are violations or duplications). "
|
||||
+ "Disable this option with '--no-fail-on-error' to exit with 0 instead. In any case, a report with the found violations or duplications will be written.",
|
||||
defaultValue = "true", negatable = true)
|
||||
protected boolean failOnError;
|
||||
|
||||
protected List<Path> relativizeRootPaths;
|
||||
|
||||
@Option(names = { "--relativize-paths-with", "-z"}, description = "Path relative to which directories are rendered in the report. "
|
||||
|
@ -68,8 +68,12 @@ public class CpdCommand extends AbstractAnalysisPmdSubcommand<CPDConfiguration>
|
||||
@Option(names = "--ignore-sequences", description = "Ignore sequences of identifiers and literals")
|
||||
private boolean ignoreIdentifierAndLiteralSequences;
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #failOnError} instead.
|
||||
*/
|
||||
@Option(names = "--skip-lexical-errors",
|
||||
description = "Skip files which can't be tokenized due to invalid characters, instead of aborting with an error.")
|
||||
description = "Skip files which can't be tokenized due to invalid characters, instead of aborting with an error. Deprecated - use --[no-]fail-on-error instead.")
|
||||
@Deprecated
|
||||
private boolean skipLexicalErrors;
|
||||
|
||||
@Option(names = "--no-skip-blocks",
|
||||
@ -103,6 +107,7 @@ public class CpdCommand extends AbstractAnalysisPmdSubcommand<CPDConfiguration>
|
||||
configuration.addRelativizeRoots(relativizeRootPaths);
|
||||
}
|
||||
configuration.setFailOnViolation(failOnViolation);
|
||||
configuration.setFailOnError(failOnError);
|
||||
configuration.setInputFilePath(fileListPath);
|
||||
if (inputPaths != null) {
|
||||
configuration.setInputPathList(new ArrayList<>(inputPaths));
|
||||
@ -123,6 +128,14 @@ public class CpdCommand extends AbstractAnalysisPmdSubcommand<CPDConfiguration>
|
||||
configuration.setSourceEncoding(encoding.getEncoding());
|
||||
configuration.setInputUri(uri);
|
||||
|
||||
if (skipLexicalErrors) {
|
||||
configuration.getReporter().warn("--skip-lexical-errors is deprecated. Use --no-fail-on-error instead.");
|
||||
configuration.setFailOnError(false);
|
||||
}
|
||||
|
||||
// implicitly enable skipLexicalErrors, so that we can fail the build at the end. A report is created in any case.
|
||||
configuration.setSkipLexicalErrors(true);
|
||||
|
||||
return configuration;
|
||||
}
|
||||
|
||||
@ -133,6 +146,11 @@ public class CpdCommand extends AbstractAnalysisPmdSubcommand<CPDConfiguration>
|
||||
MutableBoolean hasViolations = new MutableBoolean();
|
||||
cpd.performAnalysis(report -> hasViolations.setValue(!report.getMatches().isEmpty()));
|
||||
|
||||
boolean hasErrors = configuration.getReporter().numErrors() > 0;
|
||||
if (hasErrors && configuration.isFailOnError()) {
|
||||
return CliExitCode.RECOVERED_ERRORS_OR_VIOLATIONS;
|
||||
}
|
||||
|
||||
if (hasViolations.booleanValue() && configuration.isFailOnViolation()) {
|
||||
return CliExitCode.VIOLATIONS_FOUND;
|
||||
}
|
||||
|
@ -270,6 +270,7 @@ public class PmdCommand extends AbstractAnalysisPmdSubcommand<PMDConfiguration>
|
||||
configuration.setSuppressMarker(suppressMarker);
|
||||
configuration.setThreads(threads);
|
||||
configuration.setFailOnViolation(failOnViolation);
|
||||
configuration.setFailOnError(failOnError);
|
||||
configuration.setAnalysisCacheLocation(cacheLocation != null ? cacheLocation.toString() : null);
|
||||
configuration.setIgnoreIncrementalAnalysis(noCache);
|
||||
|
||||
@ -330,6 +331,8 @@ public class PmdCommand extends AbstractAnalysisPmdSubcommand<PMDConfiguration>
|
||||
if (pmdReporter.numErrors() > 0) {
|
||||
// processing errors are ignored
|
||||
return CliExitCode.ERROR;
|
||||
} else if (stats.getNumErrors() > 0 && configuration.isFailOnError()) {
|
||||
return CliExitCode.RECOVERED_ERRORS_OR_VIOLATIONS;
|
||||
} else if (stats.getNumViolations() > 0 && configuration.isFailOnViolation()) {
|
||||
return CliExitCode.VIOLATIONS_FOUND;
|
||||
} else {
|
||||
|
@ -4,30 +4,39 @@
|
||||
|
||||
package net.sourceforge.pmd.cli.internal;
|
||||
|
||||
import net.sourceforge.pmd.PMDConfiguration;
|
||||
import net.sourceforge.pmd.AbstractConfiguration;
|
||||
|
||||
/**
|
||||
* The execution result of any given command.
|
||||
*/
|
||||
public enum CliExitCode {
|
||||
/** No errors, no violations. This is exit code {@code 0}. */
|
||||
/** No errors, no recoverable errors, no violations, no duplications. This is exit code {@code 0}. */
|
||||
OK(0),
|
||||
/**
|
||||
* Errors were detected, PMD may have not run to the end.
|
||||
* Unexpected errors were detected, PMD may have not run to the end.
|
||||
* This is exit code {@code 1}.
|
||||
*/
|
||||
ERROR(1),
|
||||
/**
|
||||
* Indicates a problem with the CLI parameters: either a required
|
||||
* parameter is missing or an invalid parameter was provided.
|
||||
* parameter is missing or an invalid parameter was provided. This is exit code {@code 2}.
|
||||
*/
|
||||
USAGE_ERROR(2),
|
||||
/**
|
||||
* No errors, but PMD found violations. This is exit code {@code 4}.
|
||||
* This is only returned if {@link PMDConfiguration#isFailOnViolation()}
|
||||
* is set (CLI flag {@code --failOnViolation}).
|
||||
* No errors, but PMD found either duplications/violations. This is exit code {@code 4}.
|
||||
*
|
||||
* <p>This is only returned if {@link AbstractConfiguration#isFailOnViolation()}
|
||||
* is set. It can be disabled by using CLI flag {@code --no-fail-on-violation}.
|
||||
*/
|
||||
VIOLATIONS_FOUND(4);
|
||||
VIOLATIONS_FOUND(4),
|
||||
/**
|
||||
* PMD did run, but there was at least one recoverable error. There
|
||||
* might be additionally duplications or violations. This is exit code {@code 5}.
|
||||
*
|
||||
* <p>This is only returned if {@link AbstractConfiguration#isFailOnError()}
|
||||
* is set. It can be disabled by using CLI flag {@code --no-fail-on-error}.
|
||||
*/
|
||||
RECOVERED_ERRORS_OR_VIOLATIONS(5);
|
||||
|
||||
private final int exitCode;
|
||||
|
||||
@ -45,6 +54,7 @@ public enum CliExitCode {
|
||||
case 1: return ERROR;
|
||||
case 2: return USAGE_ERROR;
|
||||
case 4: return VIOLATIONS_FOUND;
|
||||
case 5: return RECOVERED_ERRORS_OR_VIOLATIONS;
|
||||
default:
|
||||
throw new IllegalArgumentException("Not a known exit code: " + i);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
package net.sourceforge.pmd.cli;
|
||||
|
||||
import static net.sourceforge.pmd.cli.internal.CliExitCode.OK;
|
||||
import static net.sourceforge.pmd.cli.internal.CliExitCode.RECOVERED_ERRORS_OR_VIOLATIONS;
|
||||
import static net.sourceforge.pmd.cli.internal.CliExitCode.VIOLATIONS_FOUND;
|
||||
import static net.sourceforge.pmd.util.CollectionUtil.listOf;
|
||||
import static org.hamcrest.CoreMatchers.startsWith;
|
||||
@ -138,14 +139,14 @@ class CpdCliTest extends BaseCliTest {
|
||||
@Test
|
||||
void testWrongCliOptionResultsInErrorLoggingAfterDir() throws Exception {
|
||||
// --ignore-identifiers doesn't take an argument anymore - it is interpreted as a file for inputPaths
|
||||
final CliExecutionResult result = runCli(VIOLATIONS_FOUND, "--minimum-tokens", "34", "--dir", SRC_DIR, "--ignore-identifiers", "false");
|
||||
final CliExecutionResult result = runCli(RECOVERED_ERRORS_OR_VIOLATIONS, "--minimum-tokens", "34", "--dir", SRC_DIR, "--ignore-identifiers", "false");
|
||||
result.checkStdErr(containsString("No such file false"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testWrongCliOptionResultsInErrorLoggingBeforeDir() throws Exception {
|
||||
// --ignore-identifiers doesn't take an argument anymore - it is interpreted as a file for inputPaths
|
||||
final CliExecutionResult result = runCli(VIOLATIONS_FOUND, "--minimum-tokens", "34", "--ignore-identifiers", "false", "--dir", SRC_DIR);
|
||||
final CliExecutionResult result = runCli(RECOVERED_ERRORS_OR_VIOLATIONS, "--minimum-tokens", "34", "--ignore-identifiers", "false", "--dir", SRC_DIR);
|
||||
result.checkStdErr(containsString("No such file false"));
|
||||
}
|
||||
|
||||
@ -162,7 +163,7 @@ class CpdCliTest extends BaseCliTest {
|
||||
*/
|
||||
@Test
|
||||
void testIgnoreIdentifiers() throws Exception {
|
||||
runCli(VIOLATIONS_FOUND, "--minimum-tokens", "34", "--dir", SRC_DIR, "--ignore-identifiers", "false", "--debug")
|
||||
runCli(VIOLATIONS_FOUND, "--minimum-tokens", "34", "--dir", SRC_DIR, "--ignore-identifiers", "--debug")
|
||||
.verify(result -> result.checkStdOut(containsString(
|
||||
"Found a 14 line (89 tokens) duplication"
|
||||
)));
|
||||
@ -242,6 +243,43 @@ class CpdCliTest extends BaseCliTest {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExitCodeWithLexicalErrors() throws Exception {
|
||||
runCli(RECOVERED_ERRORS_OR_VIOLATIONS,
|
||||
"--minimum-tokens", "10",
|
||||
"-d", Paths.get(BASE_RES_PATH, "badandgood", "BadFile.java").toString(),
|
||||
"--format", "text")
|
||||
.verify(r -> {
|
||||
r.checkStdErr(containsPattern("Skipping file: Lexical error in file '.*?BadFile\\.java'"));
|
||||
r.checkStdOut(emptyString());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExitCodeWithLexicalErrorsNoFail() throws Exception {
|
||||
runCli(OK,
|
||||
"--minimum-tokens", "10",
|
||||
"-d", Paths.get(BASE_RES_PATH, "badandgood", "BadFile.java").toString(),
|
||||
"--format", "text",
|
||||
"--no-fail-on-error")
|
||||
.verify(r -> {
|
||||
r.checkStdErr(containsPattern("Skipping file: Lexical error in file '.*?BadFile\\.java'"));
|
||||
r.checkStdOut(emptyString());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExitCodeWithLexicalErrorsAndSkipLexical() throws Exception {
|
||||
runCli(OK,
|
||||
"--minimum-tokens", "10",
|
||||
"-d", Paths.get(BASE_RES_PATH, "badandgood", "BadFile.java").toString(),
|
||||
"--format", "text",
|
||||
"--skip-lexical-errors")
|
||||
.verify(r -> {
|
||||
r.checkStdErr(containsPattern("Skipping file: Lexical error in file .*?BadFile\\.java"));
|
||||
r.checkStdOut(emptyString());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void jsShouldFindDuplicatesWithDifferentFileExtensions() throws Exception {
|
||||
|
@ -6,6 +6,7 @@ package net.sourceforge.pmd.cli;
|
||||
|
||||
import static net.sourceforge.pmd.cli.internal.CliExitCode.ERROR;
|
||||
import static net.sourceforge.pmd.cli.internal.CliExitCode.OK;
|
||||
import static net.sourceforge.pmd.cli.internal.CliExitCode.RECOVERED_ERRORS_OR_VIOLATIONS;
|
||||
import static net.sourceforge.pmd.cli.internal.CliExitCode.USAGE_ERROR;
|
||||
import static net.sourceforge.pmd.cli.internal.CliExitCode.VIOLATIONS_FOUND;
|
||||
import static net.sourceforge.pmd.util.CollectionUtil.listOf;
|
||||
@ -318,6 +319,27 @@ class PmdCliTest extends BaseCliTest {
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
void exitStatusWithErrors() throws Exception {
|
||||
runCli(RECOVERED_ERRORS_OR_VIOLATIONS, "--use-version", "dummy-parserThrows",
|
||||
"-d", srcDir.toString(), "-f", "text", "-R", RULESET_WITH_VIOLATION)
|
||||
.verify(r -> {
|
||||
r.checkStdOut(containsString("someSource.dummy\t-\tParseException: Parse exception: ohio"));
|
||||
r.checkStdErr(containsString("An error occurred while executing PMD."));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void exitStatusWithErrorsNoFail() throws Exception {
|
||||
runCli(OK, "--use-version", "dummy-parserThrows",
|
||||
"-d", srcDir.toString(), "-f", "text", "-R", RULESET_WITH_VIOLATION,
|
||||
"--no-fail-on-error")
|
||||
.verify(r -> {
|
||||
r.checkStdOut(containsString("someSource.dummy\t-\tParseException: Parse exception: ohio"));
|
||||
r.checkStdErr(containsString("An error occurred while executing PMD."));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testZipFileAsSource() throws Exception {
|
||||
Path zipArchive = createTemporaryZipArchive("sources.zip");
|
||||
|
@ -3,12 +3,12 @@
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
|
||||
|
||||
<description>
|
||||
Ruleset used by test RuleSetFactoryTest
|
||||
Ruleset used by test net.sourceforge.pmd.cli.PmdCliTest
|
||||
</description>
|
||||
|
||||
<rule name="ReportAllRootNodes" language="dummy" since="1.0" message="Violation from ReportAllRootNodes"
|
||||
class="net.sourceforge.pmd.lang.rule.xpath.XPathRule"
|
||||
externalInfoUrl="${pmd.website.baseurl}/rules/test/TestRuleset3.xml#Ruleset3Rule1">
|
||||
externalInfoUrl="${pmd.website.baseurl}/rules/test/RuleSetWithViolations.xml#ReportAllRootNodes">
|
||||
<description>Just for test</description>
|
||||
<priority>3</priority>
|
||||
<properties>
|
||||
|
@ -445,6 +445,7 @@ public class PMDConfiguration extends AbstractConfiguration {
|
||||
*
|
||||
* @return failOnViolation
|
||||
*/
|
||||
@Override
|
||||
public boolean isFailOnViolation() {
|
||||
return failOnViolation;
|
||||
}
|
||||
@ -456,6 +457,7 @@ public class PMDConfiguration extends AbstractConfiguration {
|
||||
* @param failOnViolation
|
||||
* failOnViolation
|
||||
*/
|
||||
@Override
|
||||
public void setFailOnViolation(boolean failOnViolation) {
|
||||
this.failOnViolation = failOnViolation;
|
||||
}
|
||||
|
@ -275,10 +275,12 @@ public class CPDConfiguration extends AbstractConfiguration {
|
||||
this.skipBlocksPattern = skipBlocksPattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFailOnViolation() {
|
||||
return failOnViolation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFailOnViolation(boolean failOnViolation) {
|
||||
this.failOnViolation = failOnViolation;
|
||||
}
|
||||
|
@ -46,6 +46,8 @@ public abstract class AbstractConfiguration {
|
||||
private Path ignoreFilePath;
|
||||
private List<Path> excludes = new ArrayList<>();
|
||||
private boolean collectRecursive = true;
|
||||
private boolean failOnViolation = true;
|
||||
private boolean failOnError = true;
|
||||
|
||||
|
||||
protected AbstractConfiguration(LanguageRegistry languageRegistry, PmdReporter messageReporter) {
|
||||
@ -377,4 +379,68 @@ public abstract class AbstractConfiguration {
|
||||
public void collectFilesRecursively(boolean collectRecursive) {
|
||||
this.collectRecursive = collectRecursive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether PMD should exit with status 4 (the default behavior, true) if
|
||||
* violations are found or just with 0 (to not break the build, e.g.).
|
||||
*
|
||||
* <p>Note: If additionally recoverable errors occurred, the exit status is 5. See
|
||||
* {@link #isFailOnError()}.
|
||||
*
|
||||
* @return failOnViolation
|
||||
*
|
||||
* @see #isFailOnError()
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public boolean isFailOnViolation() {
|
||||
return failOnViolation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether PMD should exit with status 4 (the default behavior, true)
|
||||
* if violations are found or just with 0 (to not break the build, e.g.).
|
||||
*
|
||||
* <p>Note: If additionally recoverable errors occurred, the exit status is 5. See
|
||||
* {@link #isFailOnError()}.
|
||||
*
|
||||
* @param failOnViolation whether to exit with 4 and fail the build if violations are found.
|
||||
*
|
||||
* @see #isFailOnError()
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public void setFailOnViolation(boolean failOnViolation) {
|
||||
this.failOnViolation = failOnViolation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether PMD should exit with status 5 (the default behavior, true) if
|
||||
* recoverable errors occurred or just with 0 (to not break the build, e.g.).
|
||||
*
|
||||
* <p>Note: If only violations are found, the exit status is 4. See
|
||||
* {@link #isFailOnViolation()}.
|
||||
*
|
||||
* @return failOnError
|
||||
*
|
||||
* @see #isFailOnViolation()
|
||||
* @since 7.3.0
|
||||
*/
|
||||
public boolean isFailOnError() {
|
||||
return failOnError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether PMD should exit with status 5 (the default behavior, true)
|
||||
* if recoverable errors occurred or just with 0 (to not break the build, e.g.).
|
||||
*
|
||||
* <p>Note: If only violations are found, the exit status is 4. See
|
||||
* {@link #isFailOnViolation()}.
|
||||
*
|
||||
* @param failOnError whether to exit with 5 and fail the build if recoverable errors occurred.
|
||||
*
|
||||
* @see #isFailOnViolation()
|
||||
* @since 7.3.0
|
||||
*/
|
||||
public void setFailOnError(boolean failOnError) {
|
||||
this.failOnError = failOnError;
|
||||
}
|
||||
}
|
||||
|
@ -108,7 +108,6 @@ public class PMDConfiguration extends AbstractConfiguration {
|
||||
private String reportFormat;
|
||||
private Properties reportProperties = new Properties();
|
||||
private boolean showSuppressedViolations = false;
|
||||
private boolean failOnViolation = true;
|
||||
|
||||
private AnalysisCache analysisCache = new NoopAnalysisCache();
|
||||
private boolean ignoreIncrementalAnalysis;
|
||||
@ -362,27 +361,6 @@ public class PMDConfiguration extends AbstractConfiguration {
|
||||
this.reportProperties = reportProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether PMD should exit with status 4 (the default behavior, true) if
|
||||
* violations are found or just with 0 (to not break the build, e.g.).
|
||||
*
|
||||
* @return failOnViolation
|
||||
*/
|
||||
public boolean isFailOnViolation() {
|
||||
return failOnViolation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether PMD should exit with status 4 (the default behavior, true)
|
||||
* if violations are found or just with 0 (to not break the build, e.g.).
|
||||
*
|
||||
* @param failOnViolation
|
||||
* failOnViolation
|
||||
*/
|
||||
public void setFailOnViolation(boolean failOnViolation) {
|
||||
this.failOnViolation = failOnViolation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the currently used analysis cache. Will never be null.
|
||||
*
|
||||
|
@ -66,6 +66,7 @@ public class CPDConfiguration extends AbstractConfiguration {
|
||||
|
||||
private boolean ignoreIdentifierAndLiteralSequences = false;
|
||||
|
||||
@Deprecated
|
||||
private boolean skipLexicalErrors = false;
|
||||
|
||||
private boolean noSkipBlocks = false;
|
||||
@ -74,8 +75,6 @@ public class CPDConfiguration extends AbstractConfiguration {
|
||||
|
||||
private boolean help;
|
||||
|
||||
private boolean failOnViolation = true;
|
||||
|
||||
|
||||
public CPDConfiguration() {
|
||||
this(LanguageRegistry.CPD);
|
||||
@ -229,10 +228,20 @@ public class CPDConfiguration extends AbstractConfiguration {
|
||||
this.ignoreIdentifierAndLiteralSequences = ignoreIdentifierAndLiteralSequences;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This option will be removed. With {@link #isFailOnError()}, you can
|
||||
* control whether lexical errors should fail the build or not.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isSkipLexicalErrors() {
|
||||
return skipLexicalErrors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This option will be removed. With {@link #setFailOnError(boolean)}, you can
|
||||
* control whether lexical errors should fail the build or not.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setSkipLexicalErrors(boolean skipLexicalErrors) {
|
||||
this.skipLexicalErrors = skipLexicalErrors;
|
||||
}
|
||||
@ -261,14 +270,6 @@ public class CPDConfiguration extends AbstractConfiguration {
|
||||
this.skipBlocksPattern = skipBlocksPattern;
|
||||
}
|
||||
|
||||
public boolean isFailOnViolation() {
|
||||
return failOnViolation;
|
||||
}
|
||||
|
||||
public void setFailOnViolation(boolean failOnViolation) {
|
||||
this.failOnViolation = failOnViolation;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkLanguageIsAcceptable(Language lang) throws UnsupportedOperationException {
|
||||
if (!(lang instanceof CpdCapableLanguage)) {
|
||||
|
@ -153,6 +153,9 @@ public final class CpdAnalysis implements AutoCloseable {
|
||||
|
||||
@SuppressWarnings("PMD.CloseResource")
|
||||
public void performAnalysis(Consumer<CPDReport> consumer) {
|
||||
if (configuration.isSkipLexicalErrors()) {
|
||||
LOGGER.warn("The option skipLexicalErrors is deprecated. Use failOnError instead.");
|
||||
}
|
||||
|
||||
try (SourceManager sourceManager = new SourceManager(files.getCollectedFiles())) {
|
||||
Map<Language, CpdLexer> tokenizers =
|
||||
|
@ -22,8 +22,8 @@ import net.sourceforge.pmd.lang.rule.Rule;
|
||||
import net.sourceforge.pmd.util.BaseResultProducingCloseable;
|
||||
|
||||
/**
|
||||
* A {@link Report} collects all information during a PMD execution. This
|
||||
* includes violations, suppressed violations, metrics, error during processing
|
||||
* A {@link Report} collects all information during a PMD execution. This includes violations,
|
||||
* suppressed violations, metrics, recoverable errors (that occurred during processing)
|
||||
* and configuration errors.
|
||||
*
|
||||
* <p>A report may be created by a {@link GlobalReportBuilderListener} that you
|
||||
@ -50,7 +50,10 @@ public final class Report {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a configuration error.
|
||||
* Represents a configuration error for a specific rule.
|
||||
*
|
||||
* <p>This might be a missing rule property
|
||||
* or rule property with pointless values.
|
||||
*/
|
||||
public static class ConfigurationError {
|
||||
|
||||
@ -90,7 +93,15 @@ public final class Report {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a processing error, such as a parse error.
|
||||
* Represents a recovered error that occurred during analysis.
|
||||
*
|
||||
* <p>This might be a parse error or an unexpected error originating from a rule.
|
||||
* Such errors are called recoverable, because PMD can just skip
|
||||
* the problematic file, continue the analysis with the other files and still create a report.
|
||||
* However, due to these errors, the report might be incomplete.
|
||||
*
|
||||
* <p>Some report formats, such as {@link net.sourceforge.pmd.renderers.XMLRenderer}, include these
|
||||
* errors for further investigation.
|
||||
*/
|
||||
public static class ProcessingError {
|
||||
|
||||
@ -98,7 +109,7 @@ public final class Report {
|
||||
private final FileId file;
|
||||
|
||||
/**
|
||||
* Creates a new processing error
|
||||
* Creates a new processing error.
|
||||
*
|
||||
* @param error
|
||||
* the error
|
||||
|
@ -23,10 +23,16 @@ public final class ReportStats {
|
||||
return new ReportStats(0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count of processing errors.
|
||||
*/
|
||||
public int getNumErrors() {
|
||||
return numErrors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count of found rule violations.
|
||||
*/
|
||||
public int getNumViolations() {
|
||||
return numViolations;
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ class BinaryDistributionIT extends AbstractBinaryDistributionTest {
|
||||
|
||||
ExecutionResult result = PMDExecutor.runPMDRules(createTemporaryReportFile(), tempDir, srcDir, "src/test/resources/rulesets/sample-ruleset.xml");
|
||||
|
||||
result.assertExitCode(0).assertStdErr(containsString("Run in verbose mode to see a stack-trace."));
|
||||
result.assertExitCode(5).assertStdErr(containsString("Run in verbose mode to see a stack-trace."));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Loading…
x
Reference in New Issue
Block a user