Skip to content
This repository has been archived by the owner on Apr 6, 2022. It is now read-only.

Commit

Permalink
[FIXED JENKINS-50926] Invoke issue post processing on the agent.
Browse files Browse the repository at this point in the history
  • Loading branch information
uhafner committed May 19, 2018
1 parent d7a8c63 commit 2a00182
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 65 deletions.
Expand Up @@ -76,8 +76,8 @@ private void updateMap(final List<ResultAction> actions) {
@Override
public boolean endBuild() throws IOException, InterruptedException {
for (Entry<String, List<Report>> reportsPerId : results.entrySet()) {
Report report = new Report(reportsPerId.getValue());
recorder.publishResult(build, launcher, listener, report, StringUtils.EMPTY);
Report aggregatedReport = new Report(reportsPerId.getValue());
recorder.publishResult(build, launcher, listener, Messages.Tool_Default_Name(), aggregatedReport, StringUtils.EMPTY);
}
return true;
}
Expand Down
Expand Up @@ -456,6 +456,10 @@ public void perform(@Nonnull final Run<?, ?> run, @Nonnull final FilePath worksp
}
}

private String createLoggerPrefix() {
return tools.stream().map(tool -> tool.getTool().getName()).collect(Collectors.joining());
}

private void record(final Run<?, ?> run, final FilePath workspace, final Launcher launcher,
final TaskListener listener)
throws IOException, InterruptedException {
Expand All @@ -465,12 +469,14 @@ private void record(final Run<?, ?> run, final FilePath workspace, final Launche
totalIssues.addAll(scanWithTool(run, workspace, listener, toolConfiguration));
}
totalIssues.setOrigin("analysis");
publishResult(run, launcher, listener, totalIssues, Messages.Tool_Default_Name());
publishResult(run, launcher, listener, Messages.Tool_Default_Name(),
totalIssues, Messages.Tool_Default_Name());
}
else {
for (ToolConfiguration toolConfiguration : tools) {
Report report = scanWithTool(run, workspace, listener, toolConfiguration);
publishResult(run, launcher, listener, report, StringUtils.EMPTY);
publishResult(run, launcher, listener, toolConfiguration.getTool().getName(), report,
StringUtils.EMPTY);
}
}
}
Expand Down Expand Up @@ -502,6 +508,8 @@ private Charset getReportCharset() {
* the launcher
* @param listener
* the listener
* @param loggerName
* the name of the logger
* @param report
* the analysis report to publish
* @param name
Expand All @@ -513,12 +521,12 @@ private Charset getReportCharset() {
* the the copying has been canceled by the user
*/
public void publishResult(final Run<?, ?> run, final Launcher launcher,
final TaskListener listener, final Report report, final String name)
final TaskListener listener, final String loggerName, final Report report, final String name)
throws IOException, InterruptedException {
IssuesPublisher publisher = new IssuesPublisher(run, report, getFilters(),
new HealthDescriptor(healthy, unHealthy, minimumPriority), new QualityGate(thresholds),
name, referenceJobName, ignoreAnalysisResult, overallResultMustBeSuccess, getSourceCodeCharset(),
new LogHandler(listener, report.getOrigin()));
new LogHandler(listener, loggerName, report));

VirtualChannel channel = launcher.getChannel();
if (channel == null) {
Expand All @@ -529,10 +537,6 @@ name, referenceJobName, ignoreAnalysisResult, overallResultMustBeSuccess, getSou
}
}

private String createLoggerPrefix() {
return tools.stream().map(tool -> tool.getTool().getId()).collect(Collectors.joining());
}

private String expandEnvironmentVariables(final Run<?, ?> run, final TaskListener listener, final String pattern)
throws IOException, InterruptedException {
return new EnvironmentResolver().expandEnvironmentVariables(run.getEnvironment(listener), pattern);
Expand Down
Expand Up @@ -12,19 +12,22 @@
import edu.hm.hafner.analysis.FingerprintGenerator;
import edu.hm.hafner.analysis.FullTextFingerprint;
import edu.hm.hafner.analysis.IssueBuilder;
import edu.hm.hafner.analysis.Report;
import edu.hm.hafner.analysis.ModuleDetector;
import edu.hm.hafner.analysis.ModuleDetector.FileSystem;
import edu.hm.hafner.analysis.PackageNameResolver;
import edu.hm.hafner.analysis.Report;
import edu.hm.hafner.util.Ensure;
import io.jenkins.plugins.analysis.core.model.StaticAnalysisTool;
import io.jenkins.plugins.analysis.core.util.AbsolutePathGenerator;
import io.jenkins.plugins.analysis.core.util.FilesScanner;
import io.jenkins.plugins.analysis.core.util.ModuleResolver;
import jenkins.MasterToSlaveFileCallable;

import hudson.FilePath;
import hudson.console.ConsoleNote;
import hudson.model.Computer;
import hudson.plugins.analysis.util.FileFinder;
import hudson.remoting.VirtualChannel;

/**
* Scans report files or the console log for issues.
Expand Down Expand Up @@ -70,6 +73,7 @@ public Report scan(final String pattern, final File consoleLog) throws IOExcepti
*
* @param pattern
* the pattern of files
*
* @throws InterruptedException
* if the step is interrupted
* @throws IOException
Expand All @@ -88,8 +92,13 @@ public Report scanInWorkspace(final String pattern) throws InterruptedException,
*
* @param consoleLog
* file containing the console log
*
* @throws InterruptedException
* if the step is interrupted
* @throws IOException
* if something goes wrong
*/
public Report scanInConsoleLog(final File consoleLog) {
public Report scanInConsoleLog(final File consoleLog) throws InterruptedException, IOException {
Ensure.that(tool.canScanConsoleLog()).isTrue(
"Static analysis tool %s cannot scan console log output, please define a file pattern",
tool.getName());
Expand All @@ -115,53 +124,92 @@ private void waitForConsoleToFlush() {
}
}

private Report postProcess(final Report report) {
private Report postProcess(final Report report) throws IOException, InterruptedException {
report.setOrigin(tool.getId());
report.forEach(issue -> issue.setOrigin(tool.getId()));

resolveAbsolutePaths(report);
resolveModuleNames(report);
resolvePackageNames(report);
createFingerprints(report);
Report postProcessed;
if (report.isEmpty()) {
postProcessed = report; // nothing to post process
}
else {

report.logInfo("Post processing issues on '%s' with encoding '%s'", getAgentName(), sourceCodeEncoding);

return report;
postProcessed = workspace.act(new ReportPostProcessor(report, sourceCodeEncoding.name()));
}
logger.log(postProcessed);
return postProcessed;
}

private void resolveAbsolutePaths(final Report report) {
logger.log("Resolving absolute file names for all issues");

AbsolutePathGenerator generator = new AbsolutePathGenerator();
generator.run(report, workspace);
private String getAgentName() {
return StringUtils.defaultIfBlank(getComputerName(), "Master");
}

logger.log(report);
private String getComputerName() {
Computer computer = workspace.toComputer();
if (computer != null) {
return computer.getName();
}
return StringUtils.EMPTY;
}

private void resolveModuleNames(final Report report) {
logger.log("Resolving module names from module definitions (build.xml, pom.xml, or Manifest.mf files)");
/**
* Post processes the report on the build agent. Assigns absolute paths, package names, and module names and
* computes fingerprints for each issue.
*/
private static class ReportPostProcessor extends MasterToSlaveFileCallable<Report> {
private static final long serialVersionUID = -9138045560271783096L;

private Report report;
private String sourceCodeEncoding;

ModuleResolver resolver = new ModuleResolver();
File workspaceAsFile = new File(workspace.getRemote());
resolver.run(report, new ModuleDetector(workspaceAsFile, new DefaultFileSystem()));
ReportPostProcessor(final Report report, final String sourceCodeEncoding) {
this.report = report;
this.sourceCodeEncoding = sourceCodeEncoding;
}

logger.log(report);
}
@Override
public Report invoke(final File workspace, final VirtualChannel channel) {
resolveAbsolutePaths(workspace);
resolveModuleNames(workspace);
resolvePackageNames();
createFingerprints();

private void resolvePackageNames(final Report report) {
logger.log("Using encoding '%s' to resolve package names (or namespaces)", sourceCodeEncoding);
return report;
}

PackageNameResolver resolver = new PackageNameResolver();
resolver.run(report, new IssueBuilder(), sourceCodeEncoding);
private void resolveAbsolutePaths(final File workspace) {
report.logInfo("Resolving absolute file names for all issues");

logger.log(report);
}
AbsolutePathGenerator generator = new AbsolutePathGenerator();
generator.run(report, workspace);
}

private void createFingerprints(final Report report) {
logger.log("Using encoding '%s' to read source files", sourceCodeEncoding);
private void resolveModuleNames(final File workspace) {
report.logInfo("Resolving module names from module definitions (build.xml, pom.xml, or Manifest.mf files)");

FingerprintGenerator generator = new FingerprintGenerator();
generator.run(new FullTextFingerprint(), report, sourceCodeEncoding);
ModuleResolver resolver = new ModuleResolver();
resolver.run(report, new ModuleDetector(workspace, new DefaultFileSystem()));
}

logger.log(report);
private void resolvePackageNames() {
report.logInfo("Resolving package names (or namespaces) by parsing the affected files");

PackageNameResolver resolver = new PackageNameResolver();
resolver.run(report, new IssueBuilder(), getCharset());
}

private Charset getCharset() {
return Charset.forName(sourceCodeEncoding);
}

private void createFingerprints() {
report.logInfo("Creating fingerprints for all affected code blocks to track issues over different builds");

FingerprintGenerator generator = new FingerprintGenerator();
generator.run(new FullTextFingerprint(), report, getCharset());
}
}

/**
Expand Down
Expand Up @@ -25,12 +25,30 @@ class LogHandler {
*
* @param listener
* the task listener that will print all log messages
* @param id
* the ID of the logger
* @param name
* the name of the logger
*/
LogHandler(final TaskListener listener, final String id) {
logger = createLogger(listener, id);
errorLogger = createErrorLogger(listener, id);
LogHandler(final TaskListener listener, final String name) {
this(listener, name, 0, 0);
}

/**
* Creates a new {@link LogHandler}.
*
* @param listener
* the task listener that will print all log messages
* @param name
* the name of the logger
*/
LogHandler(final TaskListener listener, final String name, final Report report) {
this(listener, name, report.getInfoMessages().size(), report.getErrorMessages().size());
}

private LogHandler(final TaskListener listener, final String name, final int infoPosition, final int errorPosition) {
logger = createLogger(listener, name);
errorLogger = createErrorLogger(listener, name);
this.infoPosition = infoPosition;
this.errorPosition = errorPosition;
}

private Logger createErrorLogger(final TaskListener listener, final String name) {
Expand Down
Expand Up @@ -452,7 +452,8 @@ protected ResultAction run() throws IOException, InterruptedException, IllegalSt
}

private LogHandler getLogger() throws InterruptedException {
return new LogHandler(getTaskListener(), new LabelProviderFactory().create(report.getOrigin(), name).getName());
String toolName = new LabelProviderFactory().create(report.getOrigin(), this.name).getName();
return new LogHandler(getTaskListener(), toolName, report);
}

private Charset getSourceCodeCharset() {
Expand Down
@@ -1,6 +1,6 @@
package io.jenkins.plugins.analysis.core.util;

import java.io.IOException;
import java.io.File;
import java.nio.file.InvalidPathException;
import java.nio.file.Paths;
import java.util.HashMap;
Expand All @@ -13,8 +13,6 @@
import edu.hm.hafner.analysis.Report;
import edu.hm.hafner.util.VisibleForTesting;

import hudson.FilePath;

/**
* Resolves absolute paths of the affected files of a set of issues.
*
Expand Down Expand Up @@ -46,7 +44,7 @@ public AbsolutePathGenerator() {
* @param workspace
* the workspace containing the affected files
*/
public void run(final Report report, final FilePath workspace) {
public void run(final Report report, final File workspace) {
Set<String> relativeFileNames = report.getFiles()
.stream()
.filter(fileName -> fileSystem.isRelative(fileName) && !IssueParser.SELF.equals(fileName))
Expand Down Expand Up @@ -90,7 +88,7 @@ public void run(final Report report, final FilePath workspace) {
}
}

private Map<String, String> resolveAbsoluteNames(final Set<String> relativeFileNames, final FilePath workspace) {
private Map<String, String> resolveAbsoluteNames(final Set<String> relativeFileNames, final File workspace) {
Map<String, String> relativeToAbsoluteMapping = new HashMap<>();
for (String fileName : relativeFileNames) {
String absolute = fileSystem.resolveFile(fileName, workspace);
Expand All @@ -106,15 +104,10 @@ private Map<String, String> resolveAbsoluteNames(final Set<String> relativeFileN
*/
@VisibleForTesting
static class FileSystem {
String resolveFile(final String fileName, final FilePath workspace) {
try {
FilePath remoteFile = workspace.child(fileName);
if (remoteFile.exists()) {
return remoteFile.getRemote();
}
}
catch (IOException | InterruptedException ignored) {
// ignore
String resolveFile(final String fileName, final File workspace) {
File remoteFile = new File(workspace, fileName);
if (remoteFile.exists()) {
return remoteFile.getAbsolutePath();
}
return fileName;
}
Expand Down
Expand Up @@ -14,16 +14,14 @@
import io.jenkins.plugins.analysis.core.util.AbsolutePathGenerator.FileSystem;
import static org.mockito.Mockito.*;

import hudson.FilePath;

/**
* Tests the class {@link AbsolutePathGenerator}.
*
* @author Ullrich Hafner
*/
class AbsolutePathGeneratorTest {
private static final String WORKSPACE_PATH = "path";
private static final FilePath WORKSPACE = new FilePath(new File(WORKSPACE_PATH));
private static final File WORKSPACE = new File(WORKSPACE_PATH);
private static final IssueBuilder ISSUE_BUILDER = new IssueBuilder();
private static final String ID = "ID";

Expand Down

0 comments on commit 2a00182

Please sign in to comment.