[cli] CPD: Add new exit code 5: VIOLATIONS_OR_PROCESSING_ERRORS

This commit is contained in:
Andreas Dangel 2024-05-02 18:51:16 +02:00
parent a2139be00b
commit 468266d58d
No known key found for this signature in database
GPG Key ID: 93450DF2DF9A3FA3
3 changed files with 53 additions and 10 deletions

View File

@ -133,6 +133,11 @@ public class CpdCommand extends AbstractAnalysisPmdSubcommand<CPDConfiguration>
MutableBoolean hasViolations = new MutableBoolean(); MutableBoolean hasViolations = new MutableBoolean();
cpd.performAnalysis(report -> hasViolations.setValue(!report.getMatches().isEmpty())); cpd.performAnalysis(report -> hasViolations.setValue(!report.getMatches().isEmpty()));
boolean hasProcessingErrors = configuration.getReporter().numErrors() > 0;
if (hasProcessingErrors) {
return CliExitCode.VIOLATIONS_OR_PROCESSING_ERRORS;
}
if (hasViolations.booleanValue() && configuration.isFailOnViolation()) { if (hasViolations.booleanValue() && configuration.isFailOnViolation()) {
return CliExitCode.VIOLATIONS_FOUND; return CliExitCode.VIOLATIONS_FOUND;
} }

View File

@ -10,10 +10,10 @@ import net.sourceforge.pmd.PMDConfiguration;
* The execution result of any given command. * The execution result of any given command.
*/ */
public enum CliExitCode { public enum CliExitCode {
/** No errors, no violations. This is exit code {@code 0}. */ /** No errors, no processing errors, no violations. This is exit code {@code 0}. */
OK(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}. * This is exit code {@code 1}.
*/ */
ERROR(1), ERROR(1),
@ -23,11 +23,23 @@ public enum CliExitCode {
*/ */
USAGE_ERROR(2), USAGE_ERROR(2),
/** /**
* No errors, but PMD found violations. This is exit code {@code 4}. * No errors, but PMD found either duplications/violations or couldn't analyze all
* This is only returned if {@link PMDConfiguration#isFailOnViolation()} * files due to parsing/lexing problems. This is exit code {@code 4}.
* is set (CLI flag {@code --failOnViolation}). *
* <p>This is only returned if {@link PMDConfiguration#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 were either duplications/violations
* or processing errors or both.
*
* <p>In case you find processing errors: Please report them</p>
*
* <p>If cli flag --no-fail-on-processing-errors is used, then this
* exit code is not used. In such case, either 0 or 4 is returned.</p>
*/
VIOLATIONS_OR_PROCESSING_ERRORS(5);
private final int exitCode; private final int exitCode;
@ -45,6 +57,7 @@ public enum CliExitCode {
case 1: return ERROR; case 1: return ERROR;
case 2: return USAGE_ERROR; case 2: return USAGE_ERROR;
case 4: return VIOLATIONS_FOUND; case 4: return VIOLATIONS_FOUND;
case 5: return VIOLATIONS_OR_PROCESSING_ERRORS;
default: default:
throw new IllegalArgumentException("Not a known exit code: " + i); throw new IllegalArgumentException("Not a known exit code: " + i);
} }

View File

@ -6,6 +6,7 @@ package net.sourceforge.pmd.cli;
import static net.sourceforge.pmd.cli.internal.CliExitCode.OK; import static net.sourceforge.pmd.cli.internal.CliExitCode.OK;
import static net.sourceforge.pmd.cli.internal.CliExitCode.VIOLATIONS_FOUND; import static net.sourceforge.pmd.cli.internal.CliExitCode.VIOLATIONS_FOUND;
import static net.sourceforge.pmd.cli.internal.CliExitCode.VIOLATIONS_OR_PROCESSING_ERRORS;
import static net.sourceforge.pmd.util.CollectionUtil.listOf; import static net.sourceforge.pmd.util.CollectionUtil.listOf;
import static org.hamcrest.CoreMatchers.startsWith; import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
@ -128,14 +129,14 @@ class CpdCliTest extends BaseCliTest {
@Test @Test
void testWrongCliOptionResultsInErrorLoggingAfterDir() throws Exception { void testWrongCliOptionResultsInErrorLoggingAfterDir() throws Exception {
// --ignore-identifiers doesn't take an argument anymore - it is interpreted as a file for inputPaths // --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(VIOLATIONS_OR_PROCESSING_ERRORS, "--minimum-tokens", "34", "--dir", SRC_DIR, "--ignore-identifiers", "false");
result.checkStdErr(containsString("No such file false")); result.checkStdErr(containsString("No such file false"));
} }
@Test @Test
void testWrongCliOptionResultsInErrorLoggingBeforeDir() throws Exception { void testWrongCliOptionResultsInErrorLoggingBeforeDir() throws Exception {
// --ignore-identifiers doesn't take an argument anymore - it is interpreted as a file for inputPaths // --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(VIOLATIONS_OR_PROCESSING_ERRORS, "--minimum-tokens", "34", "--ignore-identifiers", "false", "--dir", SRC_DIR);
result.checkStdErr(containsString("No such file false")); result.checkStdErr(containsString("No such file false"));
} }
@ -152,7 +153,7 @@ class CpdCliTest extends BaseCliTest {
*/ */
@Test @Test
void testIgnoreIdentifiers() throws Exception { 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( .verify(result -> result.checkStdOut(containsString(
"Found a 14 line (89 tokens) duplication" "Found a 14 line (89 tokens) duplication"
))); )));
@ -220,7 +221,7 @@ class CpdCliTest extends BaseCliTest {
*/ */
@Test @Test
void testSkipLexicalErrors() throws Exception { void testSkipLexicalErrors() throws Exception {
runCli(VIOLATIONS_FOUND, runCli(VIOLATIONS_OR_PROCESSING_ERRORS,
"--minimum-tokens", "10", "--minimum-tokens", "10",
"-d", BASE_RES_PATH + "badandgood/", "-d", BASE_RES_PATH + "badandgood/",
"--format", "text", "--format", "text",
@ -231,6 +232,30 @@ class CpdCliTest extends BaseCliTest {
}); });
} }
@Test
void testExitCodeWithLexicalErrors() throws Exception {
runCli(VIOLATIONS_OR_PROCESSING_ERRORS,
"--minimum-tokens", "10",
"-d", Paths.get(BASE_RES_PATH, "badandgood", "BadFile.java").toString(),
"--format", "text")
.verify(r -> {
r.checkStdErr(containsPattern("Error while tokenizing: Lexical error in file '.*?BadFile\\.java'"));
r.checkStdOut(emptyString());
});
}
@Test
void testExitCodeWithLexicalErrorsAndSkipLexical() throws Exception {
runCli(VIOLATIONS_OR_PROCESSING_ERRORS,
"--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 @Test
void jsShouldFindDuplicatesWithDifferentFileExtensions() throws Exception { void jsShouldFindDuplicatesWithDifferentFileExtensions() throws Exception {