Skip to content

Commit

Permalink
Merge pull request #47 from jenkinsci/single-logger
Browse files Browse the repository at this point in the history
[JENKINS-72448] Make sure that logging statements are in correct order
  • Loading branch information
uhafner committed Dec 22, 2023
2 parents 7a14a23 + b36eaa8 commit 2236038
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,6 @@ void perform(final Run<?, ?> run, final FilePath workspace, final TaskListener t
else {
perform(run, workspace, taskListener, resultHandler, log, logHandler);
}

}
else {
logHandler.log("Skipping execution of coverage recorder since overall result is '%s'", overallResult);
Expand All @@ -410,7 +409,7 @@ void perform(final Run<?, ?> run, final FilePath workspace, final TaskListener t

private void perform(final Run<?, ?> run, final FilePath workspace, final TaskListener taskListener,
final StageResultHandler resultHandler, final FilteredLog log, final LogHandler logHandler) throws InterruptedException {
var results = recordCoverageResults(run, workspace, taskListener, resultHandler, log);
var results = recordCoverageResults(run, workspace, resultHandler, log, logHandler);
Node aggregatedResult = aggregateResults(log, results);

if (!aggregatedResult.isEmpty()) {
Expand All @@ -424,7 +423,9 @@ private void perform(final Run<?, ?> run, final FilePath workspace, final TaskLi

var action = reporter.publishAction(getActualId(), getName(), getIcon(), aggregatedResult, run,
workspace, taskListener, getQualityGates(), getScm(),
getSourceCodeEncoding(), getSourceCodeRetention(), resultHandler);
getSourceCodeEncoding(), getSourceCodeRetention(), resultHandler, log);
logHandler.log(log);

if (!skipPublishingChecks) {
var checksPublisher = new CoverageChecksPublisher(action, aggregatedResult, getChecksName(), getChecksAnnotationScope());
checksPublisher.publishCoverageReport(taskListener);
Expand Down Expand Up @@ -462,15 +463,15 @@ private static void failStage(final StageResultHandler resultHandler, final LogH
logHandler.log(log);
}

private Map<Parser, List<ModuleNode>> recordCoverageResults(final Run<?, ?> run, final FilePath workspace, final TaskListener taskListener,
final StageResultHandler resultHandler, final FilteredLog log) throws InterruptedException {
private Map<Parser, List<ModuleNode>> recordCoverageResults(final Run<?, ?> run, final FilePath workspace,
final StageResultHandler resultHandler, final FilteredLog log, final LogHandler logHandler) throws InterruptedException {
Map<Parser, List<ModuleNode>> results = new HashMap<>();

for (CoverageTool tool : tools) {
LogHandler toolHandler = new LogHandler(taskListener, tool.getDisplayName());
Parser parser = tool.getParser();
log.logInfo("Creating parser for %s", tool.getDisplayName());
if (StringUtils.isBlank(tool.getPattern())) {
toolHandler.log("Using default pattern '%s' since user defined pattern is not set",
log.logInfo("Using default pattern '%s' since user defined pattern is not set",
parser.getDefaultPattern());
}

Expand Down Expand Up @@ -502,7 +503,7 @@ private Map<Parser, List<ModuleNode>> recordCoverageResults(final Run<?, ?> run,
log.logException(exception, "Exception while parsing with tool " + tool);
}

toolHandler.log(log);
logHandler.log(log);
}

return results;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import io.jenkins.plugins.forensics.delta.FileChanges;
import io.jenkins.plugins.forensics.reference.ReferenceFinder;
import io.jenkins.plugins.prism.SourceCodeRetention;
import io.jenkins.plugins.util.LogHandler;
import io.jenkins.plugins.util.QualityGateResult;
import io.jenkins.plugins.util.StageResultHandler;

Expand All @@ -41,96 +40,131 @@ public class CoverageReporter {
private static final List<Value> EMPTY_VALUES = List.of();

@SuppressWarnings({"checkstyle:ParameterNumber", "checkstyle:JavaNCSS"})
CoverageBuildAction publishAction(final String id, final String optionalName, final String icon, final Node rootNode,
CoverageBuildAction publishAction(final String id, final String optionalName, final String icon,
final Node rootNode,
final Run<?, ?> build, final FilePath workspace, final TaskListener listener,
final List<CoverageQualityGate> qualityGates, final String scm, final String sourceCodeEncoding,
final SourceCodeRetention sourceCodeRetention, final StageResultHandler resultHandler)
final SourceCodeRetention sourceCodeRetention, final StageResultHandler resultHandler,
final FilteredLog log)
throws InterruptedException {
FilteredLog log = new FilteredLog("Errors while reporting code coverage results:");

Optional<CoverageBuildAction> possibleReferenceResult = getReferenceBuildAction(build, id, log);

List<FileNode> filesToStore;
CoverageBuildAction action;
if (possibleReferenceResult.isPresent()) {
CoverageBuildAction referenceAction = possibleReferenceResult.get();
Node referenceRoot = referenceAction.getResult();

log.logInfo("Calculating the code delta...");
CodeDeltaCalculator codeDeltaCalculator = new CodeDeltaCalculator(build, workspace, listener, scm);
Optional<Delta> delta = codeDeltaCalculator.calculateCodeDeltaToReference(referenceAction.getOwner(), log);
delta.ifPresent(value -> createDeltaReports(rootNode, log, referenceRoot, codeDeltaCalculator, value));
action = computeCoverageBasedOnReferenceBuild(id, optionalName, icon, rootNode, build, workspace,
qualityGates, sourceCodeEncoding, sourceCodeRetention, resultHandler, possibleReferenceResult.get(),
scm,
listener,
log);
}
else {
action = computeActionWithoutHistory(id, optionalName, icon, rootNode, build, workspace, qualityGates,
sourceCodeEncoding,
sourceCodeRetention, resultHandler, log);
}

log.logInfo("Calculating coverage deltas...");
build.addAction(action);
return action;
}

Node modifiedLinesCoverageRoot = rootNode.filterByModifiedLines();
@SuppressWarnings("checkstyle:ParameterNumber")
private CoverageBuildAction computeActionWithoutHistory(
final String id, final String optionalName, final String icon,
final Node rootNode, final Run<?, ?> build, final FilePath workspace,
final List<CoverageQualityGate> qualityGates, final String sourceCodeEncoding,
final SourceCodeRetention sourceCodeRetention, final StageResultHandler resultHandler,
final FilteredLog log) throws InterruptedException {
var statistics = new CoverageStatistics(rootNode.aggregateValues(),
EMPTY_DELTA, EMPTY_VALUES, EMPTY_DELTA, EMPTY_VALUES, EMPTY_DELTA);
QualityGateResult qualityGateStatus = evaluateQualityGates(qualityGates,
statistics, resultHandler, log);

paintSourceFiles(build, workspace, sourceCodeEncoding, sourceCodeRetention, id, rootNode,
rootNode.getAllFileNodes(), log);

return new CoverageBuildAction(build, id, optionalName, icon, rootNode, qualityGateStatus, log);
}

NavigableMap<Metric, Fraction> modifiedLinesDelta;
List<Value> modifiedFilesValues;
NavigableMap<Metric, Fraction> modifiedFilesDelta;
if (hasModifiedLinesCoverage(modifiedLinesCoverageRoot)) {
Node modifiedFilesCoverageRoot = rootNode.filterByModifiedFiles();
modifiedFilesValues = modifiedFilesCoverageRoot.aggregateValues();
modifiedFilesDelta = modifiedFilesCoverageRoot.computeDelta(
referenceRoot.filterByFileNames(modifiedFilesCoverageRoot.getFiles()));
@SuppressWarnings("checkstyle:ParameterNumber")
private CoverageBuildAction computeCoverageBasedOnReferenceBuild(
final String id, final String optionalName, final String icon,
final Node rootNode, final Run<?, ?> build, final FilePath workspace,
final List<CoverageQualityGate> qualityGates, final String sourceCodeEncoding,
final SourceCodeRetention sourceCodeRetention, final StageResultHandler resultHandler,
final CoverageBuildAction referenceAction, final String scm,
final TaskListener listener, final FilteredLog log) throws InterruptedException {
log.logInfo("Calculating the code delta...");
CodeDeltaCalculator codeDeltaCalculator = new CodeDeltaCalculator(build, workspace, listener, scm);
Optional<Delta> delta = codeDeltaCalculator.calculateCodeDeltaToReference(referenceAction.getOwner(), log);

Node referenceRoot = referenceAction.getResult();
delta.ifPresent(value -> createDeltaReports(rootNode, log, referenceRoot, codeDeltaCalculator, value));

log.logInfo("Calculating coverage deltas...");

Node modifiedLinesCoverageRoot = rootNode.filterByModifiedLines();

NavigableMap<Metric, Fraction> modifiedLinesDelta;
List<Value> modifiedFilesValues;
NavigableMap<Metric, Fraction> modifiedFilesDelta;
if (hasModifiedLinesCoverage(modifiedLinesCoverageRoot)) {
Node modifiedFilesCoverageRoot = rootNode.filterByModifiedFiles();
modifiedFilesValues = modifiedFilesCoverageRoot.aggregateValues();
modifiedFilesDelta = modifiedFilesCoverageRoot.computeDelta(
referenceRoot.filterByFileNames(modifiedFilesCoverageRoot.getFiles()));

modifiedLinesDelta = modifiedLinesCoverageRoot.computeDelta(modifiedFilesCoverageRoot);
}
else {
modifiedLinesDelta = EMPTY_DELTA;
modifiedFilesValues = EMPTY_VALUES;
modifiedFilesDelta = EMPTY_DELTA;

modifiedLinesDelta = modifiedLinesCoverageRoot.computeDelta(modifiedFilesCoverageRoot);
if (rootNode.hasModifiedLines()) {
log.logInfo("No detected code changes affect the code coverage");
}
else {
modifiedLinesDelta = EMPTY_DELTA;
modifiedFilesValues = EMPTY_VALUES;
modifiedFilesDelta = EMPTY_DELTA;
}

if (rootNode.hasModifiedLines()) {
log.logInfo("No detected code changes affect the code coverage");
}
}
var overallValues = rootNode.aggregateValues();
NavigableMap<Metric, Fraction> overallDelta = rootNode.computeDelta(referenceRoot);
var modifiedLinesValues = modifiedLinesCoverageRoot.aggregateValues();

var overallValues = rootNode.aggregateValues();
NavigableMap<Metric, Fraction> overallDelta = rootNode.computeDelta(referenceRoot);
var modifiedLinesValues = modifiedLinesCoverageRoot.aggregateValues();
var statistics = new CoverageStatistics(overallValues, overallDelta,
modifiedLinesValues, modifiedLinesDelta, modifiedFilesValues, modifiedFilesDelta);
QualityGateResult qualityGateResult = evaluateQualityGates(qualityGates, statistics, resultHandler, log);

var statistics = new CoverageStatistics(overallValues, overallDelta,
modifiedLinesValues, modifiedLinesDelta, modifiedFilesValues, modifiedFilesDelta);
QualityGateResult qualityGateResult = evaluateQualityGates(qualityGates, statistics, resultHandler, log);
var filesToStore = computePaintedFiles(rootNode, sourceCodeRetention, log, modifiedLinesCoverageRoot);
paintSourceFiles(build, workspace, sourceCodeEncoding, sourceCodeRetention, id, rootNode, filesToStore, log);

if (sourceCodeRetention == SourceCodeRetention.MODIFIED) {
filesToStore = modifiedLinesCoverageRoot.getAllFileNodes();
log.logInfo("-> Selecting %d modified files for source code painting", filesToStore.size());
}
else {
filesToStore = rootNode.getAllFileNodes();
}
return new CoverageBuildAction(build, id, optionalName, icon, rootNode, qualityGateResult, log,
referenceAction.getOwner().getExternalizableId(), overallDelta,
modifiedLinesValues, modifiedLinesDelta,
modifiedFilesValues, modifiedFilesDelta,
rootNode.filterByIndirectChanges().aggregateValues());
}

action = new CoverageBuildAction(build, id, optionalName, icon, rootNode, qualityGateResult, log,
referenceAction.getOwner().getExternalizableId(), overallDelta,
modifiedLinesValues, modifiedLinesDelta,
modifiedFilesValues, modifiedFilesDelta,
rootNode.filterByIndirectChanges().aggregateValues());
private List<FileNode> computePaintedFiles(final Node rootNode, final SourceCodeRetention sourceCodeRetention,
final FilteredLog log, final Node modifiedLinesCoverageRoot) {
List<FileNode> filesToStore;
if (sourceCodeRetention == SourceCodeRetention.MODIFIED) {
filesToStore = modifiedLinesCoverageRoot.getAllFileNodes();
log.logInfo("-> Selecting %d modified files for source code painting", filesToStore.size());
}
else {
var statistics = new CoverageStatistics(rootNode.aggregateValues(),
EMPTY_DELTA, EMPTY_VALUES, EMPTY_DELTA, EMPTY_VALUES, EMPTY_DELTA);
QualityGateResult qualityGateStatus = evaluateQualityGates(qualityGates,
statistics, resultHandler, log);

filesToStore = rootNode.getAllFileNodes();

action = new CoverageBuildAction(build, id, optionalName, icon, rootNode, qualityGateStatus, log);
}
return filesToStore;
}

@SuppressWarnings("checkstyle:ParameterNumber")
private void paintSourceFiles(final Run<?, ?> build, final FilePath workspace, final String sourceCodeEncoding,
final SourceCodeRetention sourceCodeRetention, final String id, final Node rootNode,
final List<FileNode> filesToStore, final FilteredLog log) throws InterruptedException {
log.logInfo("Executing source code painting...");
SourceCodePainter sourceCodePainter = new SourceCodePainter(build, workspace, id);
sourceCodePainter.processSourceCodePainting(rootNode, filesToStore,
sourceCodeEncoding, sourceCodeRetention, log);

log.logInfo("Finished coverage processing - adding the action to the build...");

LogHandler logHandler = new LogHandler(listener, "Coverage");
logHandler.log(log);

build.addAction(action);
return action;
}

private void createDeltaReports(final Node rootNode, final FilteredLog log, final Node referenceRoot,
Expand Down Expand Up @@ -198,7 +232,8 @@ private boolean hasLineCoverageSet(final Value value) {
return ((edu.hm.hafner.coverage.Coverage) value).isSet();
}

private Optional<CoverageBuildAction> getReferenceBuildAction(final Run<?, ?> build, final String id, final FilteredLog log) {
private Optional<CoverageBuildAction> getReferenceBuildAction(final Run<?, ?> build, final String id,
final FilteredLog log) {
log.logInfo("Obtaining action of reference build");

ReferenceFinder referenceFinder = new ReferenceFinder();
Expand Down Expand Up @@ -236,7 +271,8 @@ private Optional<CoverageBuildAction> getReferenceBuildAction(final Run<?, ?> bu
return Optional.of(referenceAction);
}

private Optional<CoverageBuildAction> getPreviousResult(final String id, @CheckForNull final Run<?, ?> startSearch) {
private Optional<CoverageBuildAction> getPreviousResult(final String id,
@CheckForNull final Run<?, ?> startSearch) {
for (Run<?, ?> build = startSearch; build != null; build = build.getPreviousBuild()) {
List<CoverageBuildAction> actions = build.getActions(CoverageBuildAction.class);
for (CoverageBuildAction action : actions) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import edu.hm.hafner.coverage.Percentage;
import edu.hm.hafner.echarts.LabeledTreeMapNode;
import edu.hm.hafner.util.FilteredLog;
import edu.hm.hafner.util.VisibleForTesting;
import edu.umd.cs.findbugs.annotations.CheckForNull;

import org.kohsuke.stapler.StaplerRequest;
Expand Down Expand Up @@ -117,6 +118,11 @@ public class CoverageViewModel extends DefaultAsyncTableContentProvider implemen
this.trendChartFunction = trendChartFunction;
}

@VisibleForTesting
FilteredLog getLog() {
return log;
}

public String getId() {
return id;
}
Expand Down Expand Up @@ -440,16 +446,16 @@ public boolean isSourceFileAvailable(final FileNode coverageNode) {
}

/**
* Returns a new sub-page for the selected link.
* Returns a new subpage for the selected link.
*
* @param link
* the link to identify the sub-page to show
* the link to identify the subpage to show
* @param request
* Stapler request
* @param response
* Stapler response
*
* @return the new sub-page
* @return the new subpage
*/
@SuppressWarnings("unused") // Called by jelly view
@CheckForNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,11 @@ else if (sourceDirectories.size() == 1) {
mapping.size(), relativePaths.size() - mapping.size());
}

var changedFilesMapping = mapping.entrySet()
var changedFileMapping = mapping.entrySet()
.stream()
.filter(entry -> !entry.getKey().equals(entry.getValue()))
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
var result = new RemoteResultWrapper<>(new HashMap<>(changedFilesMapping), "Errors during source path resolving:");
var result = new RemoteResultWrapper<>(new HashMap<>(changedFileMapping), "Errors during source path resolving:");
result.merge(log);
return result;
}
Expand All @@ -149,7 +149,6 @@ private Set<String> filterSourceDirectories(final File workspace, final Filtered

private Optional<String> locateSource(final String relativePath, final FilePath workspace,
final Set<String> sourceSearchDirectories, final FilteredLog log) {

try {
FilePath absolutePath = new FilePath(new File(relativePath));
if (absolutePath.exists()) {
Expand Down
Loading

0 comments on commit 2236038

Please sign in to comment.