Skip to content

Commit

Permalink
Support for annotations in publish checks step. (#87)
Browse files Browse the repository at this point in the history
* Support for annotations in publish checks step.

* Test for annotations dropdown list view

* Fix checkstyle warning
  • Loading branch information
XiongKezhi authored Feb 28, 2021
1 parent 6fda320 commit 1e1ac7e
Show file tree
Hide file tree
Showing 16 changed files with 358 additions and 15 deletions.
191 changes: 177 additions & 14 deletions src/main/java/io/jenkins/plugins/checks/steps/PublishChecksStep.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.util.ListBoxModel;
import io.jenkins.plugins.checks.api.*;
import io.jenkins.plugins.checks.api.ChecksAction;
import io.jenkins.plugins.checks.api.ChecksAnnotation;
import io.jenkins.plugins.checks.api.ChecksConclusion;
import io.jenkins.plugins.checks.api.ChecksDetails;
import io.jenkins.plugins.checks.api.ChecksOutput;
import io.jenkins.plugins.checks.api.ChecksPublisherFactory;
import io.jenkins.plugins.checks.api.ChecksStatus;
import org.apache.commons.lang3.StringUtils;
import org.jenkinsci.plugins.workflow.steps.*;
import org.kohsuke.stapler.DataBoundConstructor;
Expand All @@ -34,6 +40,7 @@ public class PublishChecksStep extends Step implements Serializable {
private ChecksStatus status = ChecksStatus.COMPLETED;
private ChecksConclusion conclusion = ChecksConclusion.SUCCESS;
private List<StepChecksAction> actions = Collections.emptyList();
private List<StepChecksAnnotation> annotations = Collections.emptyList();

/**
* Constructor used for pipeline by Stapler.
Expand Down Expand Up @@ -94,6 +101,11 @@ public void setActions(final List<StepChecksAction> actions) {
this.actions = actions;
}

@DataBoundSetter
public void setAnnotations(final List<StepChecksAnnotation> annotations) {
this.annotations = annotations;
}

public String getName() {
return name;
}
Expand Down Expand Up @@ -126,6 +138,10 @@ public List<StepChecksAction> getActions() {
return actions;
}

public List<StepChecksAnnotation> getAnnotations() {
return annotations;
}

@Override
public StepExecution start(final StepContext stepContext) {
return new PublishChecksStepExecution(stepContext, this);
Expand All @@ -136,6 +152,8 @@ public StepExecution start(final StepContext stepContext) {
*/
@Extension
public static class PublishChecksStepDescriptor extends StepDescriptor {
private final StepUtils utils = new StepUtils();

@Override
public String getFunctionName() {
return "publishChecks";
Expand All @@ -158,7 +176,7 @@ public String getDisplayName() {
* @return a model with all {@link ChecksStatus}es.
*/
public ListBoxModel doFillStatusItems() {
return asListBoxModel(ChecksStatus.values());
return utils.asListBoxModel(ChecksStatus.values());
}

/**
Expand All @@ -167,18 +185,7 @@ public ListBoxModel doFillStatusItems() {
* @return a model with all {@link ChecksConclusion}s.
*/
public ListBoxModel doFillConclusionItems() {
return asListBoxModel(ChecksConclusion.values());
}

private ListBoxModel asListBoxModel(final Enum<?>... enums) {
return Arrays.stream(enums)
.map(Enum::name)
.map(name -> new ListBoxModel.Option(asDisplayName(name), name))
.collect(Collectors.toCollection(ListBoxModel::new));
}

private String asDisplayName(final String name) {
return StringUtils.capitalize(name.toLowerCase(Locale.ENGLISH).replace("_", " "));
return utils.asListBoxModel(ChecksConclusion.values());
}
}

Expand Down Expand Up @@ -220,6 +227,9 @@ ChecksDetails extractChecksDetails() throws IOException, InterruptedException {
.withTitle(step.getTitle())
.withSummary(step.getSummary())
.withText(step.getText())
.withAnnotations(step.getAnnotations().stream()
.map(StepChecksAnnotation::getAnnotation)
.collect(Collectors.toList()))
.build())
.withActions(step.getActions().stream()
.map(StepChecksAction::getAction)
Expand All @@ -228,6 +238,159 @@ ChecksDetails extractChecksDetails() throws IOException, InterruptedException {
}
}

/**
* A simple wrapper for {@link ChecksAnnotation} to allow users add code annotations by {@link PublishChecksStep}.
*/
public static class StepChecksAnnotation extends AbstractDescribableImpl<StepChecksAnnotation>
implements Serializable {
private static final long serialVersionUID = 1L;

private final String path;
private final int startLine;
private final int endLine;
private final String message;

private Integer startColumn;
private Integer endColumn;
private String title;
private String rawDetails;

private ChecksAnnotation.ChecksAnnotationLevel annotationLevel = ChecksAnnotation.ChecksAnnotationLevel.WARNING;

/**
* Creates an annotation with required parameters.
*
* @param path
* path of the file to annotate
* @param startLine
* start line of the annotation
* @param endLine
* end line of the annotation
* @param message
* annotation message
*/
@DataBoundConstructor
public StepChecksAnnotation(final String path, final int startLine, final int endLine, final String message) {
super();

this.path = path;
this.startLine = startLine;
this.endLine = endLine;
this.message = message;
}

@DataBoundSetter
public void setStartColumn(final Integer startColumn) {
this.startColumn = startColumn;
}

@DataBoundSetter
public void setEndColumn(final Integer endColumn) {
this.endColumn = endColumn;
}

@DataBoundSetter
public void setTitle(final String title) {
this.title = title;
}

@DataBoundSetter
public void setRawDetails(final String rawDetails) {
this.rawDetails = rawDetails;
}

@DataBoundSetter
public void setAnnotationLevel(final ChecksAnnotation.ChecksAnnotationLevel annotationLevel) {
this.annotationLevel = annotationLevel;
}

public String getPath() {
return path;
}

public int getStartLine() {
return startLine;
}

public int getEndLine() {
return endLine;
}

public String getMessage() {
return message;
}

public Integer getStartColumn() {
return startColumn;
}

public Integer getEndColumn() {
return endColumn;
}

public String getTitle() {
return title;
}

public String getRawDetails() {
return rawDetails;
}

public ChecksAnnotation.ChecksAnnotationLevel getAnnotationLevel() {
return annotationLevel;
}

/**
* Get {@link ChecksAnnotation} built with user-provided parameters in {@link PublishChecksStep}.
*
* @return the annotation built with provided parameters
*/
public ChecksAnnotation getAnnotation() {
ChecksAnnotation.ChecksAnnotationBuilder builder = new ChecksAnnotation.ChecksAnnotationBuilder()
.withPath(path)
.withStartLine(startLine)
.withEndLine(endLine)
.withMessage(message)
.withAnnotationLevel(annotationLevel);

if (startColumn != null) {
builder.withStartColumn(startColumn);
}
if (endColumn != null) {
builder.withEndColumn(endColumn);
}
if (title != null) {
builder.withTitle(title);
}
if (rawDetails != null) {
builder.withRawDetails(rawDetails);
}

return builder.build();
}

/**
* Descriptor for {@link StepChecksAnnotation}, required for Pipeline Snippet Generator.
*/
@Extension
public static class StepChecksAnnotationDescriptor extends Descriptor<StepChecksAnnotation> {
private final StepUtils utils = new StepUtils();

/**
* Fill the dropdown list model with all {@link io.jenkins.plugins.checks.api.ChecksAnnotation.ChecksAnnotationLevel}
* values.
*
* @return a model with all {@link io.jenkins.plugins.checks.api.ChecksAnnotation.ChecksAnnotationLevel} values.
*/
public ListBoxModel doFillAnnotationLevelItems() {
return utils.asListBoxModel(
Arrays.stream(ChecksAnnotation.ChecksAnnotationLevel.values())
.filter(v -> v != ChecksAnnotation.ChecksAnnotationLevel.NONE)
.toArray(Enum[]::new));
}
}
}

/**
* A simple wrapper for {@link ChecksAction} to allow users add checks actions by {@link PublishChecksStep}.
*/
Expand Down
31 changes: 31 additions & 0 deletions src/main/java/io/jenkins/plugins/checks/steps/StepUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.jenkins.plugins.checks.steps;

import hudson.util.ListBoxModel;
import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;
import java.util.Locale;
import java.util.stream.Collectors;

/**
* Utilities for pipeline steps.
*/
public class StepUtils {
/**
* Converts an {@link Enum} into a {@link ListBoxModel} with all values of it.
*
* @param enums
* all candidate values of the enum
* @return the list box model with all enum values.
*/
public ListBoxModel asListBoxModel(final Enum<?>... enums) {
return Arrays.stream(enums)
.map(Enum::name)
.map(name -> new ListBoxModel.Option(asDisplayName(name), name))
.collect(Collectors.toCollection(ListBoxModel::new));
}

private String asDisplayName(final String name) {
return StringUtils.capitalize(name.toLowerCase(Locale.ENGLISH).replace("_", " "));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">

<f:entry title="Path" field="path">
<f:textbox />
</f:entry>

<f:entry title="Start Line" field="startLine">
<f:textbox />
</f:entry>

<f:entry title="End Line" field="endLine">
<f:textbox />
</f:entry>

<f:entry title="Message" field="message">
<f:textbox />
</f:entry>

<f:entry title="Start Column" field="startColumn">
<f:textbox />
</f:entry>

<f:entry title="End Column" field="endColumn">
<f:textbox />
</f:entry>

<f:entry title="Title" field="title">
<f:textbox />
</f:entry>

<f:entry title="Raw Details" field="rawDetails">
<f:textbox />
</f:entry>

<f:entry title="Annotation Level" field="annotationLevel">
<f:select default="WARNING"/>
</f:entry>

</j:jelly>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div>
Severity level of the annotation, can be one of can be "NOTICE", "WARNING", or "FAILURE"; by default, "WARNING" will
be used.
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
End column of code to be annotated.
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
End line of code to be annotated.
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
A digest message of the annotation.
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
Path to the file to be annotated, started from the project root directory.
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
Raw details of the annotation.
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
Start column of code to be annotated.
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
Start line of code to be annotated.
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
Title of the annotation.
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,16 @@
</div>
</f:entry>

<f:entry title="${%title.annotations}">
<div id="annotations">
<f:repeatableProperty field="annotations" add="${%Add Annotations}">
<f:entry>
<div align="right">
<f:repeatableDeleteButton/>
</div>
</f:entry>
</f:repeatableProperty>
</div>
</f:entry>

</j:jelly>
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ title.detailsURL=Details URL
title.status=Status
title.conclusion=Conclusion
title.actions=Actions
title.annotations=Annotations
Loading

0 comments on commit 1e1ac7e

Please sign in to comment.