PMD exit with status 4 if violations have been found.

This commit is contained in:
Andreas Dangel
2015-03-21 19:03:03 +01:00
parent 741a9470bd
commit 0c69ed6f8b
9 changed files with 80 additions and 16 deletions

View File

@ -17,6 +17,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -30,6 +31,7 @@ import net.sourceforge.pmd.lang.*;
import net.sourceforge.pmd.processor.MonoThreadProcessor;
import net.sourceforge.pmd.processor.MultiThreadProcessor;
import net.sourceforge.pmd.renderers.Renderer;
import net.sourceforge.pmd.stat.Metric;
import net.sourceforge.pmd.util.FileUtil;
import net.sourceforge.pmd.util.IOUtil;
import net.sourceforge.pmd.util.SystemUtils;
@ -209,14 +211,15 @@ public class PMD {
* This method is the main entry point for command line usage.
*
* @param configuration the configure to use
* @return number of violations found.
*/
public static void doPMD(PMDConfiguration configuration) {
public static int doPMD(PMDConfiguration configuration) {
// Load the RuleSets
RuleSetFactory ruleSetFactory = RulesetsFactoryUtils.getRulesetFactory(configuration);
RuleSets ruleSets = RulesetsFactoryUtils.getRuleSetsWithBenchmark(configuration.getRuleSets(), ruleSetFactory);
if (ruleSets == null) {
return;
return 0;
}
Set<Language> languages = getApplicableLanguages(configuration, ruleSets);
@ -234,12 +237,23 @@ public class PMD {
Benchmarker.mark(Benchmark.Reporting, System.nanoTime() - reportStart, 0);
RuleContext ctx = new RuleContext();
final AtomicInteger violations = new AtomicInteger(0);
ctx.getReport().addListener(new ReportListener() {
@Override
public void ruleViolationAdded(RuleViolation ruleViolation) {
violations.incrementAndGet();
}
@Override
public void metricAdded(Metric metric) {
}
});
processFiles(configuration, ruleSetFactory, files, ctx, renderers);
reportStart = System.nanoTime();
renderer.end();
renderer.flush();
return violations.get();
} catch (Exception e) {
String message = e.getMessage();
if (message != null) {
@ -249,6 +263,7 @@ public class PMD {
}
LOG.log(Level.FINE, "Exception during processing", e);
LOG.info(PMDCommandLineInterface.buildUsageText());
return 0;
} finally {
Benchmarker.mark(Benchmark.Reporting, System.nanoTime() - reportStart, 0);
}
@ -420,7 +435,8 @@ public class PMD {
/**
* Parses the command line arguments and executes PMD.
* @param args command line arguments
* @return the exit code, where <code>0</code> means successful execution.
* @return the exit code, where <code>0</code> means successful execution, <code>1</code> means error,
* <code>4</code> means there have been violations found.
*/
public static int run(String[] args) {
int status = 0;
@ -435,7 +451,12 @@ public class PMD {
LOG.setLevel(logLevel); // Need to do this, since the static logger has
// already been initialized at this point
try {
PMD.doPMD(configuration);
int violations = PMD.doPMD(configuration);
if (violations > 0) {
status = PMDCommandLineInterface.VIOLATIONS_FOUND;
} else {
status = 0;
}
} catch (Exception e) {
System.out.println(PMDCommandLineInterface.buildUsageText());
System.out.println();

View File

@ -26,6 +26,7 @@ public class PMDCommandLineInterface {
public static final String STATUS_CODE_PROPERTY = "net.sourceforge.pmd.cli.status";
public static final int ERROR_STATUS = 1;
public static final int VIOLATIONS_FOUND = 4;
public static PMDParameters extractParameters(PMDParameters arguments, String[] args, String progName) {
JCommander jcommander = new JCommander(arguments);

View File

@ -20,31 +20,44 @@ import org.junit.Test;
public class CLITest extends BaseCLITest {
@Test
public void minimalArgs() {
String[] args = { "-d", SOURCE_FOLDER, "-f", "text", "-R", "java-basic,java-design" };
String[] args = { "-d", SOURCE_FOLDER, "-f", "text", "-R", "java-unnecessary,java-design" };
runTest(args, "minimalArgs");
}
@Test
public void minimumPriority() {
String[] args = { "-d", SOURCE_FOLDER, "-f", "text", "-R", "java-basic,java-design", "-min", "1"};
String[] args = { "-d", SOURCE_FOLDER, "-f", "text", "-R", "java-design", "-min", "1"};
runTest(args,"minimumPriority");
}
@Test
public void usingDebug() {
String[] args = { "-d", SOURCE_FOLDER, "-f", "text", "-R", "java-basic,java-design", "-debug" };
String[] args = { "-d", SOURCE_FOLDER, "-f", "text", "-R", "java-design", "-debug" };
runTest(args, "minimalArgsWithDebug");
}
@Test
public void changeJavaVersion() {
String[] args = { "-d", SOURCE_FOLDER, "-f", "text", "-R", "java-basic,java-design", "-version", "1.5",
String[] args = { "-d", SOURCE_FOLDER, "-f", "text", "-R", "java-design", "-version", "1.5",
"-language", "java", "-debug" };
String resultFilename = runTest(args, "chgJavaVersion");
assertTrue("Invalid Java version",
FileUtil.findPatternInFile(new File(resultFilename), "Using Java version: Java 1.5"));
}
@Test
public void exitStatusNoViolations() {
String[] args = { "-d", SOURCE_FOLDER, "-f", "text", "-R", "java-design" };
runTest(args, "exitStatusNoViolations");
}
@Test
public void exitStatusWithViolations() {
String[] args = { "-d", SOURCE_FOLDER, "-f", "text", "-R", "java-empty" };
String resultFilename = runTest(args, "exitStatusWithViolations", 4);
assertTrue(FileUtil.findPatternInFile(new File(resultFilename), "Avoid empty if"));
}
/**
* See https://sourceforge.net/p/pmd/bugs/1231/
*/

View File

@ -0,0 +1,13 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
/**
* Source code file used for
* {@link net.sourceforge.pmd.cli.CLITest}
*/
public class EmptyIfStatement {
public void foo() {
if (1 == 2) { }
}
}

View File

@ -21,7 +21,7 @@ public class CLITest extends BaseCLITest {
String[] args = { "-d", SOURCE_FOLDER, "-f", "xml", "-R", "ecmascript-basic", "-version", "3", "-l",
"ecmascript", "-debug" };
String resultFilename = runTest(args, "useEcmaScript");
assertTrue("Invalid Java version",
assertTrue("Invalid JavaScript version",
FileUtil.findPatternInFile(new File(resultFilename), "Using Ecmascript version: Ecmascript 3"));
}
}

View File

@ -0,0 +1,4 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
// just some js file for net.sourceforge.pmd.cli.CLITest

View File

@ -25,12 +25,12 @@ public abstract class BaseCLITest {
protected static final String TEST_OUPUT_DIRECTORY = "target/cli-tests/";
// Points toward a folder without any source files, to avoid actually PMD
// Points toward a folder with not many source files, to avoid actually PMD
// and slowing down tests
protected static final String SOURCE_FOLDER = "src/main/resources";
protected static final String SOURCE_FOLDER = "src/test/resources/net/sourceforge/pmd/cli";
private PrintStream originalOut;
private PrintStream originalErr;
protected PrintStream originalOut;
protected PrintStream originalErr;
/**
* @throws java.lang.Exception
@ -68,12 +68,15 @@ public abstract class BaseCLITest {
}
protected String runTest(String[] args, String testname) {
return runTest(args, testname, 0);
}
protected String runTest(String[] args, String testname, int expectedExitCode) {
String filename = TEST_OUPUT_DIRECTORY + testname + ".txt";
long start = System.currentTimeMillis();
createTestOutputFile(filename);
System.out.println("Start running test " + testname);
runPMDWith(args);
checkStatusCode();
checkStatusCode(expectedExitCode);
System.out.println("Test finished successfully after " + (System.currentTimeMillis() - start) + "ms.");
return filename;
}
@ -82,9 +85,9 @@ public abstract class BaseCLITest {
PMD.main(args);
}
protected void checkStatusCode() {
protected void checkStatusCode(int expectedExitCode) {
int statusCode = getStatusCode();
if (statusCode > 0) {
if (statusCode != expectedExitCode) {
fail("PMD failed with status code:" + statusCode);
}
}

View File

@ -14,6 +14,8 @@
* XML: Line numbers for XML documents are more accurate. This is a further improvement of [#1054](https://sourceforge.net/p/pmd/bugs/1054/).
* CPD: New output format 'csv_with_linecount_per_file'
* [#1320](https://sourceforge.net/p/pmd/bugs/1320/): Enhance SimplifyBooleanReturns checks
* PMD exits with status `4` if any violations have been found. This behavior has been introduced to ease PMD
integration into scripts or hooks, such as SVN hooks.
**New/Modified/Deprecated Rules:**

View File

@ -193,6 +193,13 @@ The tool comes with a rather extensive help text, simply running with `-help`!
</table>
Exit Status
-----------
Please note that if PMD detects any violations, it will exit with status 4 (since 5.3).
This behavior has been introduced to ease PMD integration into scripts or hooks, such as SVN hooks.
Supported Languages
-------------------