Skip to content
Open
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ Cppcheck Plugin

This [Jenkins CI](http://jenkins-ci.org/) plug-in generates the trend report for [Cppcheck](http://cppcheck.sourceforge.net/), a tool for static C/C++ code analysis.

To setup your environment for development of this plugin, see the "Setting up a productive environment with your IDE" part of: <https://wiki.jenkins.io/display/JENKINS/Plugin+tutorial#Plugintutorial-Eclipse>

For more information, visit the wiki page <https://wiki.jenkins-ci.org/display/JENKINS/Cppcheck+Plugin>.
212 changes: 163 additions & 49 deletions src/main/java/org/jenkinsci/plugins/cppcheck/CppcheckPublisher.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ public class CppcheckPublisher extends Recorder implements SimpleBuildStep {
* @since 1.15
*/
public static final String XML_FILE_DETAILS = "cppcheck_details.xml";

/**
* XML file with source container data for baseline data. Also used in lazy loading.
*/
public static final String XML_FILE_BASELINE_DETAILS = "cppcheck_baseline_details.xml";

private static final String BASELINE_SUBDIRECTORY = "/baseline";

private CppcheckConfig config;

Expand Down Expand Up @@ -121,6 +128,15 @@ public void setPattern(String pattern) {
public String getPattern() {
return config.getPattern();
}

@DataBoundSetter
public void setBaselinePattern(String baselinePattern) {
config.setBaselinePattern(baselinePattern);
}
public String getBaselinePattern() {
return config.getBaselinePattern();
}

@DataBoundSetter
public void setThreshold(String threshold) {
config.getConfigSeverityEvaluation().setThreshold(threshold);
Expand Down Expand Up @@ -297,6 +313,7 @@ public int getYSize() {
public void setNumBuildsInGraph(int numBuildsInGraph) {
config.getConfigGraph().setNumBuildsInGraph(numBuildsInGraph);
}

public int getNumBuildsInGraph() {
return config.getConfigGraph().getNumBuildsInGraph();
}
Expand Down Expand Up @@ -326,20 +343,7 @@ public void perform(@Nonnull Run<?,?> build, @Nonnull FilePath workspace, @Nonnu
if (this.canContinue(build.getResult())) {
CppcheckLogger.log(listener, "Starting the cppcheck analysis.");

EnvVars env = build.getEnvironment(listener);
String expandedPattern = env.expand(config.getPattern());


CppcheckParserResult parser = new CppcheckParserResult(listener,
expandedPattern, config.isIgnoreBlankFiles());
CppcheckReport cppcheckReport;
try {
cppcheckReport = workspace.act(parser);
} catch (Exception e) {
CppcheckLogger.log(listener, "Error on cppcheck analysis: " + e);
build.setResult(Result.FAILURE);
return;
}
CppcheckReport cppcheckReport = generateCppcheckReport(build, workspace, listener, config.getPattern());

if (cppcheckReport == null) {
// Check if we're configured to allow not having a report
Expand All @@ -356,6 +360,8 @@ public void perform(@Nonnull Run<?,?> build, @Nonnull FilePath workspace, @Nonnu
workspace, cppcheckReport.getAllErrors());

CppcheckResult result = new CppcheckResult(cppcheckReport.getStatistics(), build);
result.setSourceContainerPath(XML_FILE_DETAILS);

CppcheckConfigSeverityEvaluation severityEvaluation
= config.getConfigSeverityEvaluation();

Expand All @@ -373,13 +379,28 @@ public void perform(@Nonnull Run<?,?> build, @Nonnull FilePath workspace, @Nonnu

build.addAction(buildAction);

XmlFile xmlSourceContainer = new XmlFile(new File(build.getRootDir(),
XML_FILE_DETAILS));
xmlSourceContainer.write(cppcheckSourceContainer);

copyFilesToBuildDirectory(build.getRootDir(), launcher.getChannel(),
cppcheckSourceContainer.getInternalMap().values());

writeAndCopyXmlFiles(build.getRootDir(), null, launcher, result.getSourceContainerPath(),
cppcheckSourceContainer);

/**
* If config has a baseline pattern (optional), do the required parsing,
* report creation and writing to the build/baseline subdirectory
*/
if(config.isHasBaselinePattern()) {

CppcheckReport cppcheckBaselineReport = generateCppcheckReport(build, workspace, listener, config.getBaselinePattern());

if (cppcheckBaselineReport != null) {
CppcheckResult baselineResult = new CppcheckResult(cppcheckBaselineReport.getStatistics(), build);
baselineResult.setSourceContainerPath(XML_FILE_BASELINE_DETAILS);
result.setBaselineResult(baselineResult);
CppcheckSourceContainer cppcheckBaselineSourceContainer = new CppcheckSourceContainer(listener, workspace.withSuffix(BASELINE_SUBDIRECTORY),
workspace.withSuffix(BASELINE_SUBDIRECTORY), cppcheckBaselineReport.getAllErrors());

writeAndCopyXmlFiles(build.getRootDir(), BASELINE_SUBDIRECTORY, launcher, baselineResult.getSourceContainerPath(), cppcheckBaselineSourceContainer);
}
}

CppcheckLogger.log(listener, "Ending the cppcheck analysis.");
}
return;
Expand All @@ -393,25 +414,8 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher,
if (this.canContinue(build.getResult())) {
CppcheckLogger.log(listener, "Starting the cppcheck analysis.");

EnvVars env = build.getEnvironment(listener);
String expandedPattern = env.expand(config.getPattern());


CppcheckParserResult parser = new CppcheckParserResult(listener,
expandedPattern, config.isIgnoreBlankFiles());
CppcheckReport cppcheckReport = null;
try {
FilePath oWorkspacePath = build.getWorkspace();
if( oWorkspacePath != null) {
cppcheckReport = oWorkspacePath.act(parser);
}

} catch (Exception e) {
CppcheckLogger.log(listener, "Error on cppcheck analysis: " + e);
build.setResult(Result.FAILURE);
return false;
}

CppcheckReport cppcheckReport = generateCppcheckReport(build, listener, config.getPattern());

if (cppcheckReport == null) {
// Check if we're configured to allow not having a report
if (config.getAllowNoReport()) {
Expand All @@ -421,12 +425,18 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher,
return false;
}
}


FilePath workspace = build.getWorkspace();
FilePath moduleRoot = build.getModuleRoot();


CppcheckSourceContainer cppcheckSourceContainer
= new CppcheckSourceContainer(listener, build.getWorkspace(),
build.getModuleRoot(), cppcheckReport.getAllErrors());
= new CppcheckSourceContainer(listener, workspace,
moduleRoot, cppcheckReport.getAllErrors());

CppcheckResult result = new CppcheckResult(cppcheckReport.getStatistics(), build);
result.setSourceContainerPath(XML_FILE_DETAILS);

CppcheckConfigSeverityEvaluation severityEvaluation
= config.getConfigSeverityEvaluation();

Expand All @@ -443,18 +453,122 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher,
CppcheckBuildAction.computeHealthReportPercentage(result, severityEvaluation));

build.addAction(buildAction);

writeAndCopyXmlFiles(build.getRootDir(), null, launcher, result.getSourceContainerPath(),
cppcheckSourceContainer);

XmlFile xmlSourceContainer = new XmlFile(new File(build.getRootDir(),
XML_FILE_DETAILS));
xmlSourceContainer.write(cppcheckSourceContainer);

copyFilesToBuildDirectory(build.getRootDir(), launcher.getChannel(),
cppcheckSourceContainer.getInternalMap().values());

/**
* If config has a baseline pattern (optional), do the required parsing,
* report creation and writing to the build directory
*/
if(config.isHasBaselinePattern() && workspace != null && moduleRoot != null) {
CppcheckReport cppcheckBaselineReport = generateCppcheckReport(build, listener, config.getBaselinePattern());

if (cppcheckBaselineReport != null) {
CppcheckResult baselineResult = new CppcheckResult(cppcheckBaselineReport.getStatistics(), build);
baselineResult.setSourceContainerPath(XML_FILE_BASELINE_DETAILS);

result.setBaselineResult(new CppcheckResult(cppcheckBaselineReport.getStatistics(), build));

CppcheckSourceContainer cppcheckBaselineSourceContainer = new CppcheckSourceContainer(listener,
workspace.withSuffix(BASELINE_SUBDIRECTORY),
moduleRoot.withSuffix(BASELINE_SUBDIRECTORY),
cppcheckBaselineReport.getAllErrors());

writeAndCopyXmlFiles(build.getRootDir(), BASELINE_SUBDIRECTORY, launcher, baselineResult.getSourceContainerPath(),
cppcheckBaselineSourceContainer);

}
}

CppcheckLogger.log(listener, "Ending the cppcheck analysis.");
}
return true;
}

/**
*
* @param build The current build
* @param workspace The workspace the build is performing in
* @param launcher
* @param listener
* @param pattern The pattern found from either config.getPattern() or config.getBaselinePattern()
* @return The corresponding CppcheckReport
* @throws IOException If the files could not be read
* @throws InterruptedException If the user cancels the processing
*/
private CppcheckReport generateCppcheckReport(@Nonnull Run<?, ?> build, @Nonnull FilePath workspace,
@Nonnull TaskListener listener, String pattern) throws IOException, InterruptedException {

EnvVars env = build.getEnvironment(listener);
String expandedPattern = env.expand(pattern);

CppcheckParserResult parser = new CppcheckParserResult(listener,
expandedPattern, config.isIgnoreBlankFiles());

CppcheckReport cppcheckReport;

try {
cppcheckReport = workspace.act(parser);
} catch (Exception e) {
CppcheckLogger.log(listener, "Error on cppcheck analysis: " + e);
build.setResult(Result.FAILURE);
return null;
}

return cppcheckReport;


}

private CppcheckReport generateCppcheckReport(AbstractBuild<?, ?> build, BuildListener listener, String pattern) {

try {
FilePath oWorkspacePath = build.getWorkspace();
if (oWorkspacePath != null) {
return generateCppcheckReport(build, oWorkspacePath, listener, pattern);
}

} catch (Exception e) {
CppcheckLogger.log(listener, "Error on cppcheck analysis: " + e);
build.setResult(Result.FAILURE);
return null;

}

return null;
}


/**
* Handles writing and copying of Xml files generated from the Cppcheck analysis to the workspace.
*
* @param rootDir The root directory of the build
* @param child An optional child parameter. Used when baseline is specified.
* @param launcher
* @param sourceContainerPath The name of the file on disk for the sourceContainer
* @param sourceContainer
* @throws IOException If the files could not be written
* @throws InterruptedException If the user cancels the processing
*/
private void writeAndCopyXmlFiles(@Nonnull File rootDir, String child, @Nonnull Launcher launcher, @Nonnull String sourceContainerPath,
@Nonnull CppcheckSourceContainer sourceContainer) throws IOException, InterruptedException {

XmlFile xmlSourceContainer = new XmlFile(new File(rootDir, sourceContainerPath));
xmlSourceContainer.write(sourceContainer);
boolean allDirectoriesExist = rootDir.isDirectory();

if (child != null) {
rootDir = new File(rootDir, child);
allDirectoriesExist = rootDir.mkdirs();
}

if(allDirectoriesExist) {
copyFilesToBuildDirectory(rootDir, launcher.getChannel(), sourceContainer.getInternalMap().values());
}

}


/**
Expand Down
Loading