Skip to content

Commit

Permalink
Use the new reference job API of the forensics plugin.
Browse files Browse the repository at this point in the history
Remove the warnings plugin specific reference job implementation.
  • Loading branch information
uhafner committed Feb 4, 2024
1 parent 8f5b5f4 commit 48b46c8
Show file tree
Hide file tree
Showing 19 changed files with 200 additions and 511 deletions.
144 changes: 26 additions & 118 deletions doc/Documentation.md

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@
<testcontainers.version>1.19.3</testcontainers.version>

<!-- Jenkins Plug-in Dependencies Versions -->
<git-forensics.version>2.0.0</git-forensics.version>
<forensics-api.version>2.4.0-SNAPSHOT</forensics-api.version>
<git-forensics.version>2.1.0-SNAPSHOT</git-forensics.version>

<jenkins-maven-plugin.version>3.22</jenkins-maven-plugin.version>
<job-dsl.version>1.84</job-dsl.version>
<flexible-publish.version>0.15.2</flexible-publish.version>
Expand Down Expand Up @@ -171,6 +173,7 @@
<dependency>
<groupId>io.jenkins.plugins</groupId>
<artifactId>forensics-api</artifactId>
<version>${forensics-api.version}</version>
</dependency>

<!-- AxivionSuite Dependencies -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,42 +28,52 @@ public class DeltaReport {
private final Report referenceIssues;
private final String referenceBuildId;

/**
* Creates a new {@link DeltaReport}. Since no reference build is available, all issues are considered outstanding.
*
* @param report
* the current report
* @param currentBuildNumber
* the number of the current build, the reference of all new warnings will be set to this number
*/
public DeltaReport(final Report report, final int currentBuildNumber) {
allIssues = report;
outstandingIssues = report;
referenceIssues = EMPTY_REPORT;
newIssues = EMPTY_REPORT;
fixedIssues = EMPTY_REPORT;
referenceBuildId = StringUtils.EMPTY;

report.logInfo("No valid reference build found");
report.logInfo("All reported issues will be considered outstanding");
report.forEach(issue -> issue.setReference(String.valueOf(currentBuildNumber)));
}

/**
* Creates a new instance of {@link DeltaReport}.
*
* @param report
* the current report
* @param history
* the history that will provide the reference build (if there is any)
* @param referenceBuild
* the reference build
* @param currentBuildNumber
* the number of the current build, the reference of all new warnings will be set to this number
* @param referenceIssues
* the issues in the reference build
*/
public DeltaReport(final Report report, final History history, final int currentBuildNumber) {
public DeltaReport(final Report report, final Run<?, ?> referenceBuild, final int currentBuildNumber, final Report referenceIssues) {
report.logInfo("Using reference build '%s' to compute new, fixed, and outstanding issues",
referenceBuild);

allIssues = report;
if (history.getBuild().isPresent()) {
Run<?, ?> build = history.getBuild().get();
report.logInfo("Using reference build '%s' to compute new, fixed, and outstanding issues",
build);

referenceIssues = history.getIssues();
IssueDifference difference = new IssueDifference(report, String.valueOf(currentBuildNumber), referenceIssues);
outstandingIssues = difference.getOutstandingIssues();
newIssues = difference.getNewIssues();
fixedIssues = difference.getFixedIssues();
report.logInfo("Issues delta (vs. reference build): outstanding: %d, new: %d, fixed: %d",
outstandingIssues.size(), newIssues.size(), fixedIssues.size());
referenceBuildId = build.getExternalizableId();
}
else {
report.logInfo("No valid reference build found that meets the criteria (%s)", history);
report.logInfo("All reported issues will be considered outstanding");
report.forEach(issue -> issue.setReference(String.valueOf(currentBuildNumber)));
outstandingIssues = report;
referenceIssues = EMPTY_REPORT;
newIssues = EMPTY_REPORT;
fixedIssues = EMPTY_REPORT;
referenceBuildId = StringUtils.EMPTY;
}
this.referenceIssues = referenceIssues;
IssueDifference difference = new IssueDifference(report, String.valueOf(currentBuildNumber), referenceIssues);
outstandingIssues = difference.getOutstandingIssues();
newIssues = difference.getNewIssues();
fixedIssues = difference.getFixedIssues();
report.logInfo("Issues delta (vs. reference build): outstanding: %d, new: %d, fixed: %d",
outstandingIssues.size(), newIssues.size(), fixedIssues.size());
referenceBuildId = referenceBuild.getExternalizableId();
}

/**
Expand Down Expand Up @@ -124,7 +134,7 @@ public Report getFixedIssues() {

/**
* Returns statistics for the number of issues (total, new, delta).
*
*
* @return the issues statistics
*/
public IssuesStatistics getStatistics() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import edu.hm.hafner.analysis.Report;
import edu.hm.hafner.util.FilteredLog;

import hudson.model.Job;
import hudson.model.Result;
import hudson.model.Run;

Expand All @@ -28,7 +27,6 @@
import io.jenkins.plugins.analysis.core.util.WarningsQualityGate;
import io.jenkins.plugins.analysis.core.util.WarningsQualityGateEvaluator;
import io.jenkins.plugins.forensics.reference.ReferenceFinder;
import io.jenkins.plugins.util.JenkinsFacade;
import io.jenkins.plugins.util.LogHandler;
import io.jenkins.plugins.util.QualityGateResult;
import io.jenkins.plugins.util.ResultHandler;
Expand All @@ -50,8 +48,6 @@ class IssuesPublisher {
private final String name;
private final Charset sourceCodeEncoding;
private final List<WarningsQualityGate> qualityGates;
private final String referenceJobName;
private final String referenceBuildId;
private final QualityGateEvaluationMode qualityGateEvaluationMode;
private final JobResultEvaluationMode jobResultEvaluationMode;
private final LogHandler logger;
Expand All @@ -61,18 +57,15 @@ class IssuesPublisher {
@SuppressWarnings("ParameterNumber")
IssuesPublisher(final Run<?, ?> run, final AnnotatedReport report,
final HealthDescriptor healthDescriptor, final List<WarningsQualityGate> qualityGates,
final String name, final String referenceJobName, final String referenceBuildId,
final boolean ignoreQualityGate,
final boolean ignoreFailedBuilds, final Charset sourceCodeEncoding, final LogHandler logger,
final String name, final boolean ignoreQualityGate, final boolean ignoreFailedBuilds,
final Charset sourceCodeEncoding, final LogHandler logger,
final ResultHandler notifier, final boolean failOnErrors) {
this.report = report;
this.run = run;
this.healthDescriptor = healthDescriptor;
this.name = name;
this.sourceCodeEncoding = sourceCodeEncoding;
this.qualityGates = qualityGates;
this.referenceJobName = referenceJobName;
this.referenceBuildId = referenceBuildId;
qualityGateEvaluationMode = ignoreQualityGate ? IGNORE_QUALITY_GATE : SUCCESSFUL_QUALITY_GATE;
jobResultEvaluationMode = ignoreFailedBuilds ? NO_JOB_FAILURE : IGNORE_JOB_RESULT;
this.logger = logger;
Expand All @@ -97,7 +90,14 @@ ResultAction attachAction(final TrendChartType trendChartType) {
ResultSelector selector = ensureThatIdIsUnique();

Report issues = report.getReport();
DeltaReport deltaReport = new DeltaReport(issues, createAnalysisHistory(selector, issues), run.getNumber());
var history = createAnalysisHistory(selector, issues);
DeltaReport deltaReport;
if (history.getBuild().isPresent()) {
deltaReport = new DeltaReport(issues, history.getBuild().get(), run.getNumber(), history.getIssues());
}
else {
deltaReport = new DeltaReport(issues, run.getNumber());
}
QualityGateResult qualityGateResult = evaluateQualityGate(issues, deltaReport);
reportHealth(issues);

Expand Down Expand Up @@ -171,63 +171,19 @@ private QualityGateResult evaluateQualityGate(final Report issues, final DeltaRe
}

private History createAnalysisHistory(final ResultSelector selector, final Report issues) {
if (isValidReference(referenceJobName)) {
return findConfiguredReference(selector, issues);
}

return new AnalysisHistory(findReference(issues), selector,
determineQualityGateEvaluationMode(issues), jobResultEvaluationMode);
}

private boolean isValidReference(final String referenceName) {
return !IssuesRecorder.NO_REFERENCE_DEFINED.equals(referenceName);
}

private History findConfiguredReference(final ResultSelector selector, final Report issues) {
final String message = "Setting the reference job has been deprecated, please use the new reference recorder";
if (failOnErrors) {
// Log at info level otherwise this will fail the step, even if everything else is ok.
issues.logInfo(message);
var reference = findReference(issues);
if (reference.isPresent()) {
return new AnalysisHistory(reference.get(), selector,
determineQualityGateEvaluationMode(issues), jobResultEvaluationMode);
}
else {
issues.logError(message);
}

Optional<Job<?, ?>> referenceJob = new JenkinsFacade().getJob(referenceJobName);
if (referenceJob.isPresent()) {
Job<?, ?> job = referenceJob.get();

Run<?, ?> baseline;
if (isValidReference(referenceBuildId)) {
baseline = job.getBuild(referenceBuildId);
if (baseline == null) {
issues.logError("Reference job '%s' does not contain configured build '%s'",
job.getFullDisplayName(), referenceBuildId);
return new NullAnalysisHistory();
}
}
else {
baseline = job.getLastCompletedBuild();
if (baseline == null) {
issues.logInfo("Reference job '%s' has no completed build yet", job.getFullDisplayName());
return new NullAnalysisHistory();
}
}
return new AnalysisHistory(baseline, selector, determineQualityGateEvaluationMode(issues),
jobResultEvaluationMode);
return new NullAnalysisHistory();
}
issues.logError("Configured reference job '%s' does not exist", referenceJobName);
return new NullAnalysisHistory();
}

private Run<?, ?> findReference(final Report issues) {
ReferenceFinder referenceFinder = new ReferenceFinder();
private Optional<Run<?, ?>> findReference(final Report issues) {
FilteredLog log = new FilteredLog("Errors while resolving the reference build:");
Run<?, ?> reference = referenceFinder.findReference(run, log)
.orElseGet(() -> {
log.logInfo("Obtaining reference build from same job (%s)", run.getParent().getDisplayName());
return run;
});
Optional<Run<?, ?>> reference = new ReferenceFinder().findReference(run, log);
issues.mergeLogMessages(log);
return reference;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,6 @@ public class IssuesRecorder extends Recorder {

private boolean ignoreQualityGate = false; // by default, a successful quality gate is mandatory;
private boolean ignoreFailedBuilds = true; // by default, failed builds are ignored;
private String referenceJobName;
private String referenceBuildId;

private boolean failOnError = false;

Expand Down Expand Up @@ -531,61 +529,6 @@ public boolean getIgnoreFailedBuilds() {
return ignoreFailedBuilds;
}

/**
* Sets the reference job to get the results for the issue difference computation.
*
* @param referenceJobName
* the name of reference job
*/
@DataBoundSetter
public void setReferenceJobName(final String referenceJobName) {
if (NO_REFERENCE_DEFINED.equals(referenceJobName)) {
this.referenceJobName = StringUtils.EMPTY;
}
this.referenceJobName = referenceJobName;
}

/**
* Returns the reference job to get the results for the issue difference computation. If the job is not defined,
* then {@link #NO_REFERENCE_DEFINED} is returned.
*
* @return the name of reference job, or {@link #NO_REFERENCE_DEFINED} if undefined
*/
public String getReferenceJobName() {
if (StringUtils.isBlank(referenceJobName)) {
return NO_REFERENCE_DEFINED;
}
return referenceJobName;
}

/**
* Sets the reference build id to get the results for the issue difference computatation.
*
* @param referenceBuildId
* the build id of the reference job
*/
public void setReferenceBuildId(final String referenceBuildId) {
if (NO_REFERENCE_DEFINED.equals(referenceBuildId)) {
this.referenceBuildId = StringUtils.EMPTY;
}
else {
this.referenceBuildId = referenceBuildId;
}
}

/**
* Returns the reference build id to get the results for the issue difference computation. If the build id not
* defined, then {@link #NO_REFERENCE_DEFINED} is returned.
*
* @return the build id of the reference job, or {@link #NO_REFERENCE_DEFINED} if undefined.
*/
public String getReferenceBuildId() {
if (StringUtils.isBlank(referenceBuildId)) {
return NO_REFERENCE_DEFINED;
}
return referenceBuildId;
}

public int getHealthy() {
return healthy;
}
Expand Down Expand Up @@ -804,7 +747,7 @@ AnalysisResult publishResult(final Run<?, ?> run, final TaskListener listener, f

IssuesPublisher publisher = new IssuesPublisher(run, annotatedReport,
new HealthDescriptor(healthy, unhealthy, minimumSeverity), qualityGates,
reportName, getReferenceJobName(), getReferenceBuildId(), ignoreQualityGate, ignoreFailedBuilds,
reportName, ignoreQualityGate, ignoreFailedBuilds,
getSourceCodeCharset(), logHandler, resultHandler, failOnError);
ResultAction action = publisher.attachAction(trendChartType);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public class PublishIssuesStep extends Step implements Serializable {
private boolean ignoreQualityGate = false; // by default, a successful quality gate is mandatory
private boolean ignoreFailedBuilds = true; // by default, failed builds are ignored
private String referenceJobName = StringUtils.EMPTY;
private String referenceBuildId = StringUtils.EMPTY;
private final String referenceBuildId = StringUtils.EMPTY;
private boolean failOnError = false; // by default, it should not fail on error

private boolean skipPublishingChecks; // by default, warnings should be published to SCM platforms
Expand Down Expand Up @@ -253,48 +253,6 @@ public void setReferenceJobName(final String referenceJobName) {
this.referenceJobName = referenceJobName;
}

/**
* Returns the reference job to get the results for the issue difference computation. If the job is not defined,
* then {@link IssuesRecorder#NO_REFERENCE_DEFINED} is returned.
*
* @return the name of reference job, or {@link IssuesRecorder#NO_REFERENCE_DEFINED} if undefined
*/
public String getReferenceJobName() {
if (StringUtils.isBlank(referenceJobName)) {
return IssuesRecorder.NO_REFERENCE_DEFINED;
}
return referenceJobName;
}

/**
* Sets the reference build id of the reference job for the issue difference computation.
*
* @param referenceBuildId
* the build id of the reference job
*/
@DataBoundSetter
public void setReferenceBuildId(final String referenceBuildId) {
if (IssuesRecorder.NO_REFERENCE_DEFINED.equals(referenceBuildId)) {
this.referenceBuildId = StringUtils.EMPTY;
}
else {
this.referenceBuildId = referenceBuildId;
}
}

/**
* Returns the reference build id of the reference job to get the results for the issue difference computation.
* If the build id is not defined, then {@link IssuesRecorder#NO_REFERENCE_DEFINED} is returned.
*
* @return the reference build id, or {@link IssuesRecorder#NO_REFERENCE_DEFINED} if undefined
*/
public String getReferenceBuildId() {
if (StringUtils.isBlank(referenceBuildId)) {
return IssuesRecorder.NO_REFERENCE_DEFINED;
}
return referenceBuildId;
}

@CheckForNull
public String getSourceCodeEncoding() {
return sourceCodeEncoding;
Expand Down Expand Up @@ -453,7 +411,7 @@ protected ResultAction run() throws IOException, InterruptedException, IllegalSt
IssuesPublisher publisher = new IssuesPublisher(getRun(), report,
new HealthDescriptor(step.getHealthy(), step.getUnhealthy(),
step.getMinimumSeverityAsSeverity()), step.getQualityGates(),
StringUtils.defaultString(step.getName()), step.getReferenceJobName(), step.getReferenceBuildId(),
StringUtils.defaultString(step.getName()),
step.getIgnoreQualityGate(), step.getIgnoreFailedBuilds(),
getCharset(step.getSourceCodeEncoding()), getLogger(report), notifier, step.getFailOnError());
ResultAction action = publisher.attachAction(step.getTrendChartType());
Expand Down
Loading

0 comments on commit 48b46c8

Please sign in to comment.