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

Add a property to specify the icon of the result #1919

Draft
wants to merge 5 commits into
base: fix-icon-JENKINS-72777
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@

import org.apache.commons.lang3.StringUtils;

import edu.hm.hafner.analysis.Issue;
import edu.hm.hafner.analysis.Report;
import edu.hm.hafner.util.Generated;
import edu.hm.hafner.util.VisibleForTesting;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

import org.kohsuke.stapler.StaplerProxy;
import org.kohsuke.stapler.bind.JavaScriptMethod;
import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.Whitelisted;
import org.jvnet.localizer.Localizable;
import hudson.model.Action;
import hudson.model.HealthReport;
import hudson.model.HealthReportingAction;
Expand Down Expand Up @@ -45,29 +50,9 @@ public class ResultAction implements HealthReportingAction, LastBuildAction, Run
private final HealthDescriptor healthDescriptor;
private final String id;
private final String name;
private /* almost final */ String icon;
private final String charset;
private TrendChartType trendChartType;

/**
* Creates a new instance of {@link ResultAction}.
*
* @param owner
* the associated build/run that created the static analysis result
* @param result
* the result of the static analysis run
* @param healthDescriptor
* the health descriptor of the static analysis run
* @param id
* the ID of the results
* @param name
* the optional name of the results
* @param charset
* the charset to use to display source files
*/
public ResultAction(final Run<?, ?> owner, final AnalysisResult result, final HealthDescriptor healthDescriptor,
final String id, final String name, final Charset charset) {
this(owner, result, healthDescriptor, id, name, charset, TrendChartType.AGGREGATION_TOOLS);
}
private /* almost final */ TrendChartType trendChartType;

/**
* Creates a new instance of {@link ResultAction}.
Expand All @@ -82,18 +67,23 @@ public ResultAction(final Run<?, ?> owner, final AnalysisResult result, final He
* the ID of the results
* @param name
* the optional name of the results
* @param icon
* the optional icon of the results
* @param charset
* the charset to use to display source files
* @param trendChartType
* determines if the trend chart will be shown
*/
@SuppressWarnings("checkstyle:ParameterNumber")
public ResultAction(final Run<?, ?> owner, final AnalysisResult result, final HealthDescriptor healthDescriptor,
final String id, final String name, final Charset charset, final TrendChartType trendChartType) {
final String id, final String name, final String icon,
final Charset charset, final TrendChartType trendChartType) {
this.owner = owner;
this.result = result;
this.healthDescriptor = healthDescriptor;
this.id = id;
this.name = name;
this.icon = icon;
this.charset = charset.name();
this.trendChartType = trendChartType;
}
Expand All @@ -107,6 +97,9 @@ protected Object readResolve() {
if (trendChartType == null) {
trendChartType = TrendChartType.TOOLS_ONLY;
}
if (icon == null) {
icon = StringUtils.EMPTY;
}
return this;
}

Expand Down Expand Up @@ -276,7 +269,6 @@ public String getSmallImageName() {
*
* @return the URL of the image
*/
@SuppressWarnings({"unused", "WeakerAccess"}) // Called by jelly view
public String getSmallImage() {
return getLabelProvider().getSmallIconUrl();
}
Expand Down Expand Up @@ -314,7 +306,12 @@ public String toString() {
* @return the label provider for this tool
*/
public StaticAnalysisLabelProvider getLabelProvider() {
return new LabelProviderFactory().create(getParserId(), name);
var registeredLabelProvider = new LabelProviderFactory().create(getParserId(), name);
if (StringUtils.isBlank(icon)) {
return registeredLabelProvider;
}

return new CustomIconLabelProvider(registeredLabelProvider, icon);
}

private String getParserId() {
Expand Down Expand Up @@ -346,4 +343,98 @@ public String resetReference() {
// Empty method as workaround for Stapler bug that does not find JavaScript proxy methods in target object IssueDetail
return "{}";
}

private static class CustomIconLabelProvider extends StaticAnalysisLabelProvider {
@Override
public DetailsTableModel getIssuesModel(final Run<?, ?> build, final String url, final Report report) {
return decorated.getIssuesModel(build, url, report);
}

@Override
public DefaultAgeBuilder getAgeBuilder(final Run<?, ?> owner, final String url) {
return decorated.getAgeBuilder(owner, url);
}

@Override
public FileNameRenderer getFileNameRenderer(final Run<?, ?> owner) {
return decorated.getFileNameRenderer(owner);
}

@VisibleForTesting
@Override
public String getDefaultName() {
return decorated.getDefaultName();
}

@Override
public String getId() {
return decorated.getId();
}

@Override
public String getName() {
return decorated.getName();
}

@Override
public StaticAnalysisLabelProvider setName(@CheckForNull final String name) {
return decorated.setName(name);
}

@Override
@Generated
public String toString() {
return decorated.toString();
}

@Override
public String getLinkName() {
return decorated.getLinkName();
}

@Override
public String getTrendName() {
return decorated.getTrendName();
}

@Override
public String getToolTip(final int numberOfItems) {
return decorated.getToolTip(numberOfItems);
}

@Override
public Localizable getToolTipLocalizable(final int numberOfItems) {
return decorated.getToolTipLocalizable(numberOfItems);
}

@Override
public String getDescription(final Issue issue) {
return decorated.getDescription(issue);
}

@Override
public String getSourceCodeDescription(final Run<?, ?> build, final Issue issue) {
return decorated.getSourceCodeDescription(build, issue);
}

private final StaticAnalysisLabelProvider decorated;
private final String icon;

CustomIconLabelProvider(final StaticAnalysisLabelProvider decorated, final String icon) {
super(decorated.getId(), decorated.getName());
this.decorated = decorated;

this.icon = icon;
}

@Override
public String getSmallIconUrl() {
return icon;
}

@Override
public String getLargeIconUrl() {
return icon;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public abstract class Tool extends AbstractDescribableImpl<Tool> implements Seri

private String id = StringUtils.EMPTY;
private String name = StringUtils.EMPTY;
private String icon = StringUtils.EMPTY; // @since 12.0.0: by default no custom icon is set

private JenkinsFacade jenkins = new JenkinsFacade();

Expand All @@ -57,6 +58,10 @@ public void setJenkinsFacade(final JenkinsFacade jenkinsFacade) {
protected Object readResolve() {
jenkins = new JenkinsFacade();

if (icon == null) {
icon = StringUtils.EMPTY;
}

return this;
}

Expand Down Expand Up @@ -120,6 +125,21 @@ public String getActualName() {
return StringUtils.defaultIfBlank(getName(), getDescriptor().getDisplayName());
}

/**
* Defines the custom icon of the tool. If no icon is given, then the default icon of the tool is used.
*
* @param icon
* the icon of the tool
*/
@DataBoundSetter
public void setIcon(final String icon) {
this.icon = icon;
}

public String getIcon() {
return icon;
}

/**
* Returns the {@link Symbol} name of this tool.
*
Expand Down Expand Up @@ -149,7 +169,7 @@ public ToolDescriptor getDescriptor() {

/**
* Scans the results of a build for issues. This method is invoked on Jenkins master. I.e., if a tool wants to
* process some build results it is required to run a {@link MasterToSlaveCallable}.
* process some build results, it is required to run a {@link MasterToSlaveCallable}.
*
* @param run
* the build
Expand All @@ -162,9 +182,9 @@ public ToolDescriptor getDescriptor() {
*
* @return the created report
* @throws ParsingException
* Signals that during parsing a non recoverable error has been occurred
* signals that during parsing a non-recoverable error has been occurred
* @throws ParsingCanceledException
* Signals that the parsing has been aborted by the user
* signals that the user has aborted the parsing
*/
public abstract Report scan(Run<?, ?> run, FilePath workspace, Charset sourceCodeEncoding, LogHandler logger)
throws ParsingException, ParsingCanceledException;
Expand Down Expand Up @@ -246,6 +266,10 @@ public StaticAnalysisLabelProvider getLabelProvider() {
return new StaticAnalysisLabelProvider(getId(), getDisplayName());
}

public String getIcon() {
return getLabelProvider().getSmallIconUrl();
}

/**
* Returns an optional help text that can provide useful hints on how to configure the static analysis tool so
* that the report files could be parsed by Jenkins. This help can be a plain text message or an HTML snippet.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@
import hudson.util.ListBoxModel;
import jenkins.model.Jenkins;

import io.jenkins.plugins.analysis.core.model.StaticAnalysisLabelProvider;
import io.jenkins.plugins.analysis.core.steps.WarningChecksPublisher.ChecksAnnotationScope;
import io.jenkins.plugins.analysis.core.util.ModelValidation;
import io.jenkins.plugins.prism.SourceCodeRetention;
import io.jenkins.plugins.util.JenkinsFacade;
import io.jenkins.plugins.util.ValidationUtilities;

/**
* Descriptor base class for all analysis steps. Provides generic validation methods, and list box models for UI select
* Descriptor base class for all analysis steps. Provides generic validation methods and list box models for UI select
* elements.
*
* @author Ullrich Hafner
Expand All @@ -32,6 +33,18 @@ public abstract class AnalysisStepDescriptor extends StepDescriptor {
private static final JenkinsFacade JENKINS = new JenkinsFacade();
private final ModelValidation model = new ModelValidation();

public String getDefaultId() {
return IssuesRecorder.DEFAULT_ID;
}

public String getDefaultName() {
return Messages.Tool_Default_Name();
}

public String getDefaultIcon() {
return StaticAnalysisLabelProvider.ANALYSIS_SVG_ICON;
}

/**
* Returns a model with all available charsets.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.google.errorprone.annotations.FormatMethod;

import edu.hm.hafner.analysis.Report;
import edu.hm.hafner.util.Ensure;
import edu.umd.cs.findbugs.annotations.CheckForNull;

import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.Whitelisted;
Expand Down Expand Up @@ -40,6 +41,8 @@ public class AnnotatedReport implements Serializable {
* the ID of the report
*/
public AnnotatedReport(final String id) {
Ensure.that(id).isNotBlank("The ID of the report must not be empty");

this.id = id;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public boolean endBuild() {
resultsPerTool.forEachKeyMultiValues((tool, reports) -> {
AnnotatedReport aggregatedReport = new AnnotatedReport(tool, reports);
recorder.publishResult(build, build.getWorkspace(), listener, Messages.Tool_Default_Name(),
aggregatedReport, StringUtils.EMPTY, new RunResultHandler(build));
aggregatedReport, StringUtils.EMPTY, recorder.getIcon(), new RunResultHandler(build));
});
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class IssuesPublisher {
private final DeltaCalculator deltaCalculator;
private final HealthDescriptor healthDescriptor;
private final String name;
private final String icon;
private final Charset sourceCodeEncoding;
private final List<WarningsQualityGate> qualityGates;
private final QualityGateEvaluationMode qualityGateEvaluationMode;
Expand All @@ -59,13 +60,14 @@ class IssuesPublisher {
@SuppressWarnings("ParameterNumber")
IssuesPublisher(final Run<?, ?> run, final AnnotatedReport report, final DeltaCalculator deltaCalculator,
final HealthDescriptor healthDescriptor, final List<WarningsQualityGate> qualityGates,
final String name, final boolean ignoreQualityGate, final Charset sourceCodeEncoding,
final String name, final String icon, final boolean ignoreQualityGate, final Charset sourceCodeEncoding,
final LogHandler logger, final ResultHandler notifier, final boolean failOnErrors) {
this.report = report;
this.run = run;
this.deltaCalculator = deltaCalculator;
this.healthDescriptor = healthDescriptor;
this.name = name;
this.icon = icon;
this.sourceCodeEncoding = sourceCodeEncoding;
this.qualityGates = qualityGates;
qualityGateEvaluationMode = ignoreQualityGate ? IGNORE_QUALITY_GATE : SUCCESSFUL_QUALITY_GATE;
Expand Down Expand Up @@ -120,8 +122,8 @@ ResultAction attachAction(final TrendChartType trendChartType) {
previous))
.orElseGet(() -> new AnalysisResult(run, getId(), deltaReport, report.getBlames(),
report.getStatistics(), qualityGateResult, report.getSizeOfOrigin()));
ResultAction action
= new ResultAction(run, result, healthDescriptor, getId(), name, sourceCodeEncoding, trendChartType);
ResultAction action = new ResultAction(run, result, healthDescriptor, getId(), name, icon,
sourceCodeEncoding, trendChartType);
run.addAction(action);

if (trendChartType == TrendChartType.TOOLS_AGGREGATION || trendChartType == TrendChartType.AGGREGATION_ONLY) {
Expand Down
Loading
Loading