Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JENKINS-39203] Mark publishIssues steps with QualityGateStatus.WARNING with WarningAction #58

Merged
merged 5 commits into from
Jun 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
64 changes: 21 additions & 43 deletions pom.xml
Expand Up @@ -4,8 +4,8 @@
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>3.42</version>
<relativePath />
<version>3.43</version>
<relativePath/>
</parent>

<groupId>io.jenkins.plugins</groupId>
Expand All @@ -23,7 +23,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

<!-- Override properties defined in parent POM -->
<jenkins.version>2.121.1</jenkins.version>
<jenkins.version>2.138.4</jenkins.version>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Required by the new version of workflow-api.

<java.level>8</java.level>
<jenkins-test-harness.version>2.49</jenkins-test-harness.version>

Expand Down Expand Up @@ -60,6 +60,7 @@
<matrix-project.version>1.13</matrix-project.version>
<junit-plugin.version>1.24</junit-plugin.version>
<git-plugin.version>3.9.1</git-plugin.version>
<workflow-api.version>2.34</workflow-api.version>
<workflow-step.version>2.19</workflow-step.version>
<workflow-job.version>2.32</workflow-job.version>
<structs.version>1.17</structs.version>
Expand Down Expand Up @@ -253,6 +254,11 @@
<artifactId>script-security</artifactId>
<version>${script-security.version}</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-api</artifactId>
<version>${workflow-api.version}</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-step-api</artifactId>
Expand Down Expand Up @@ -495,12 +501,6 @@
</dependency>

<!-- Declarative Pipeline -->
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-api</artifactId>
<version>2.33</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-support</artifactId>
Expand Down Expand Up @@ -752,7 +752,8 @@
</dependency>
</dependencies>
<configuration>
<failBuildOnProblemsFound>false</failBuildOnProblemsFound>
<!-- Including provided-scope dependencies like Jenkins core results in too many false positives -->
<checkDependencies>false</checkDependencies>
<analysisConfiguration>
<revapi.semver.ignore>
<enabled>true</enabled>
Expand All @@ -771,47 +772,24 @@
</item>
<item>
<regex>true</regex>
<code>.*</code>
<classQualifiedName>io.jenkins.plugins.analysis.warnings.WarningsPlugin</classQualifiedName>
<justification>The tool is not part of API.</justification>
<code>java.missing.*</code>
<justification>Dependencies are not being checked, so they are reported as missing</justification>
</item>
</revapi.ignore>
<!-- Always ignore Jenkins API -->
<revapi.ignore>
<item>
<code>.*</code>
<regex>true</regex>
<classQualifiedName>hudson.*</classQualifiedName>
<justification>Jenkins API</justification>
<code>java.annotation.removed</code>
<classQualifiedName>io.jenkins.plugins.analysis.core.steps.IssuesRecorder.Descriptor</classQualifiedName>
<justification>Symbol-based usage migrated transparently to RecordIssuesStep</justification>
</item>
<item>
<code>.*</code>
<regex>true</regex>
<classQualifiedName>jenkins.*</classQualifiedName>
<justification>Jenkins API</justification>
<code>java.method.removed</code>
<classQualifiedName>io.jenkins.plugins.analysis.core.util.QualityGateStatus</classQualifiedName>
<justification>Not part of the plugin's public API</justification>
</item>
<item>
<code>.*</code>
<regex>true</regex>
<classQualifiedName>org.jvnet.hudson.*</classQualifiedName>
<justification>Jenkins API</justification>
</item>
<item>
<code>.*</code>
<regex>true</regex>
<classQualifiedName>org.kohsuke.stapler.*</classQualifiedName>
<justification>Jenkins API</justification>
</item>
<item>
<code>java.class.nonPublicPartOfAPI</code>
<classQualifiedName>net.sf.json.AbstractJSON.WritingVisitor</classQualifiedName>
<justification>Not relevant</justification>
</item>
<item>
<code>java.class.nonPublicPartOfAPI</code>
<regex>true</regex>
<classQualifiedName>com.fasterxml.jackson.databind.*</classQualifiedName>
<justification>Not relevant</justification>
<classQualifiedName>io.jenkins.plugins.analysis.warnings.WarningsPlugin</classQualifiedName>
<justification>The tool is not part of API.</justification>
</item>
</revapi.ignore>
</analysisConfiguration>
Expand Down
Expand Up @@ -17,6 +17,7 @@

import io.jenkins.plugins.analysis.core.model.AnalysisResult;
import io.jenkins.plugins.analysis.core.model.ResultAction;
import io.jenkins.plugins.analysis.core.util.QualityGateStatusHandler;

/**
* Aggregates the {@link AnalysisResult}s of all {@link ResultAction}s of several {@link MatrixRun}s into {@link
Expand Down Expand Up @@ -91,7 +92,8 @@ private void updateMap(final List<ResultAction> actions) {
public boolean endBuild() {
for (Entry<String, List<AnnotatedReport>> reportsPerId : results.entrySet()) {
AnnotatedReport aggregatedReport = new AnnotatedReport(reportsPerId.getKey(), reportsPerId.getValue());
recorder.publishResult(build, listener, Messages.Tool_Default_Name(), aggregatedReport, StringUtils.EMPTY);
recorder.publishResult(build, listener, Messages.Tool_Default_Name(), aggregatedReport, StringUtils.EMPTY,
new QualityGateStatusHandler.SetBuildResultStatusHandler(build));
}
return true;
}
Expand Down
Expand Up @@ -27,6 +27,7 @@
import io.jenkins.plugins.analysis.core.util.LogHandler;
import io.jenkins.plugins.analysis.core.util.QualityGateEvaluator;
import io.jenkins.plugins.analysis.core.util.QualityGateStatus;
import io.jenkins.plugins.analysis.core.util.QualityGateStatusHandler;

import static io.jenkins.plugins.analysis.core.model.AnalysisHistory.JobResultEvaluationMode.*;
import static io.jenkins.plugins.analysis.core.model.AnalysisHistory.QualityGateEvaluationMode.*;
Expand All @@ -48,12 +49,14 @@ class IssuesPublisher {
private final QualityGateEvaluationMode qualityGateEvaluationMode;
private final JobResultEvaluationMode jobResultEvaluationMode;
private final LogHandler logger;
private final QualityGateStatusHandler qualityGateStatusHandler;

@SuppressWarnings("ParameterNumber")
IssuesPublisher(final Run<?, ?> run, final AnnotatedReport report,
final HealthDescriptor healthDescriptor, final QualityGateEvaluator qualityGate,
final String name, final String referenceJobName, final boolean ignoreQualityGate,
final boolean ignoreFailedBuilds, final Charset sourceCodeEncoding, final LogHandler logger) {
final boolean ignoreFailedBuilds, final Charset sourceCodeEncoding, final LogHandler logger,
final QualityGateStatusHandler qualityGateStatusHandler) {
this.report = report;
this.run = run;
this.healthDescriptor = healthDescriptor;
Expand All @@ -64,6 +67,7 @@ class IssuesPublisher {
qualityGateEvaluationMode = ignoreQualityGate ? IGNORE_QUALITY_GATE : SUCCESSFUL_QUALITY_GATE;
jobResultEvaluationMode = ignoreFailedBuilds ? NO_JOB_FAILURE : IGNORE_JOB_RESULT;
this.logger = logger;
this.qualityGateStatusHandler = qualityGateStatusHandler;
}

private String getId() {
Expand Down Expand Up @@ -142,7 +146,7 @@ private QualityGateStatus evaluateQualityGate(final Report filtered, final Delta
else {
filtered.logInfo("-> Some quality gates have been missed: overall result is %s", qualityGateStatus);
}
qualityGateStatus.setResult(run);
qualityGateStatusHandler.handleStatus(qualityGateStatus);
}
else {
filtered.logInfo("No quality gates have been set - skipping");
Expand Down
Expand Up @@ -16,7 +16,6 @@
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.QueryParameter;
import org.jenkinsci.Symbol;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
Expand Down Expand Up @@ -52,6 +51,7 @@
import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateResult;
import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateType;
import io.jenkins.plugins.analysis.core.util.QualityGateEvaluator;
import io.jenkins.plugins.analysis.core.util.QualityGateStatusHandler;

/**
* Freestyle or Maven job {@link Recorder} that scans report files or the console log for issues. Stores the created
Expand All @@ -73,7 +73,7 @@
*/
@SuppressWarnings({"PMD.ExcessivePublicCount", "PMD.ExcessiveClassLength", "PMD.ExcessiveImports", "PMD.TooManyFields", "PMD.DataClass", "ClassDataAbstractionCoupling", "ClassFanOutComplexity"})
public class IssuesRecorder extends Recorder implements SimpleBuildStep {
private static final String NO_REFERENCE_JOB = "-";
static final String NO_REFERENCE_JOB = "-";

private List<Tool> analysisTools = new ArrayList<>();

Expand Down Expand Up @@ -284,7 +284,7 @@ public void setTool(final Tool tool) {
analysisTools = Collections.singletonList(tool);
}

private void ensureThatToolIsValid(final Tool tool) {
static void ensureThatToolIsValid(final Tool tool) {
if (tool == null) {
throw new IllegalArgumentException("No valid tool defined! You probably used a symbol in the tools "
+ "definition that is also a symbol in another plugin. "
Expand Down Expand Up @@ -504,9 +504,19 @@ public Descriptor getDescriptor() {
public void perform(@NonNull final Run<?, ?> run, @NonNull final FilePath workspace,
@NonNull final Launcher launcher, @NonNull final TaskListener listener)
throws InterruptedException, IOException {
perform(run, workspace, listener, new QualityGateStatusHandler.SetBuildResultStatusHandler(run));
}

/**
* Executes the build step. Used from {@link RecordIssuesStep} to provide a {@link QualityGateStatusHandler}
* that has Pipeline-specific behavior.
*/
void perform(@NonNull final Run<?, ?> run, @NonNull final FilePath workspace,
@NonNull final TaskListener listener, @NonNull final QualityGateStatusHandler statusHandler)
throws InterruptedException, IOException {
Result overallResult = run.getResult();
if (isEnabledForFailure || overallResult == null || overallResult.isBetterOrEqualTo(Result.UNSTABLE)) {
record(run, workspace, listener);
record(run, workspace, listener, statusHandler);
}
else {
LogHandler logHandler = new LogHandler(listener, createLoggerPrefix());
Expand All @@ -518,7 +528,8 @@ private String createLoggerPrefix() {
return analysisTools.stream().map(Tool::getActualName).collect(Collectors.joining());
}

private void record(final Run<?, ?> run, final FilePath workspace, final TaskListener listener)
private void record(final Run<?, ?> run, final FilePath workspace, final TaskListener listener,
final QualityGateStatusHandler statusHandler)
throws IOException, InterruptedException {
for (Tool tool : getTools()) {
ensureThatToolIsValid(tool);
Expand All @@ -529,7 +540,7 @@ private void record(final Run<?, ?> run, final FilePath workspace, final TaskLis
totalIssues.add(scanWithTool(run, workspace, listener, tool), tool.getActualId());
}
String toolName = StringUtils.defaultIfEmpty(getName(), Messages.Tool_Default_Name());
publishResult(run, listener, toolName, totalIssues, toolName);
publishResult(run, listener, toolName, totalIssues, toolName, statusHandler);
}
else {
for (Tool tool : analysisTools) {
Expand All @@ -543,7 +554,7 @@ private void record(final Run<?, ?> run, final FilePath workspace, final TaskLis
report.logInfo("Ignoring name='%s' and id='%s' when publishing non-aggregating reports",
name, id);
}
publishResult(run, listener, tool.getActualName(), report, getReportName(tool));
publishResult(run, listener, tool.getActualName(), report, getReportName(tool), statusHandler);
}
}
}
Expand Down Expand Up @@ -605,7 +616,7 @@ private Charset getCharset(final String encoding) {
*/
@SuppressWarnings("deprecation")
void publishResult(final Run<?, ?> run, final TaskListener listener, final String loggerName,
final AnnotatedReport report, final String reportName) {
final AnnotatedReport report, final String reportName, final QualityGateStatusHandler statusHandler) {
QualityGateEvaluator qualityGate = new QualityGateEvaluator();
if (qualityGates.isEmpty()) {
qualityGates.addAll(QualityGate.map(thresholds));
Expand All @@ -614,7 +625,7 @@ void publishResult(final Run<?, ?> run, final TaskListener listener, final Strin
IssuesPublisher publisher = new IssuesPublisher(run, report,
new HealthDescriptor(healthy, unhealthy, minimumSeverity), qualityGate,
reportName, referenceJobName, ignoreQualityGate, ignoreFailedBuilds, getSourceCodeCharset(),
new LogHandler(listener, loggerName, report.getReport()));
new LogHandler(listener, loggerName, report.getReport()), statusHandler);
publisher.attachAction();
}

Expand Down Expand Up @@ -1030,7 +1041,6 @@ public int getFailedNewLow() {
* Descriptor for this step: defines the context and the UI elements.
*/
@Extension
@Symbol("recordIssues")
@SuppressWarnings("unused") // most methods are used by the corresponding jelly view
public static class Descriptor extends BuildStepDescriptor<Publisher> {
/** Retain backward compatibility. */
Expand Down
Expand Up @@ -15,6 +15,7 @@
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.QueryParameter;
import org.jenkinsci.plugins.workflow.graph.FlowNode;
import org.jenkinsci.plugins.workflow.steps.Step;
import org.jenkinsci.plugins.workflow.steps.StepContext;
import org.jenkinsci.plugins.workflow.steps.StepDescriptor;
Expand All @@ -38,6 +39,7 @@
import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateResult;
import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateType;
import io.jenkins.plugins.analysis.core.util.QualityGateEvaluator;
import io.jenkins.plugins.analysis.core.util.QualityGateStatusHandler;

/**
* Publish issues created by a static analysis build. The recorded issues are stored as a {@link ResultAction} in the
Expand Down Expand Up @@ -569,9 +571,11 @@ protected ResultAction run() throws IOException, InterruptedException, IllegalSt
}
report.addAll(reports);

QualityGateStatusHandler statusHandler = new QualityGateStatusHandler.PipelineStatusHandler(getRun(),
getContext().get(FlowNode.class));
IssuesPublisher publisher = new IssuesPublisher(getRun(), report, healthDescriptor, qualityGate,
name, referenceJobName, ignoreQualityGate, ignoreFailedBuilds,
getCharset(sourceCodeEncoding), getLogger(report));
getCharset(sourceCodeEncoding), getLogger(report), statusHandler);
return publisher.attachAction();
}

Expand All @@ -590,7 +594,7 @@ public static class Descriptor extends StepDescriptor {

@Override
public Set<Class<?>> getRequiredContext() {
return Sets.immutable.of(Run.class, TaskListener.class).castToSet();
return Sets.immutable.of(FlowNode.class, Run.class, TaskListener.class).castToSet();
}

@Override
Expand Down