diff --git a/build.gradle b/build.gradle index e600447d..d3c4931a 100644 --- a/build.gradle +++ b/build.gradle @@ -56,18 +56,20 @@ jenkinsPlugin { disabledTestInjection = false } -sourceCompatibility = '1.7' +sourceCompatibility = '1.8' dependencies { compile 'org.jenkins-ci.lib:dry-run-lib:0.1' - jenkinsPlugins 'org.jenkins-ci.plugins:structs:1.3' + jenkinsPlugins 'org.jenkins-ci.plugins:structs:1.5' + jenkinsPlugins 'org.jenkins-ci.plugins.workflow:workflow-api:2.20' - signature 'org.codehaus.mojo.signature:java17:1.0@signature' + signature 'org.codehaus.mojo.signature:java18:1.0@signature' testFixturesImplementation 'org.jenkins-ci.main:jenkins-test-harness:2.44' jenkinsTest 'org.jenkins-ci.main:jenkins-test-harness:2.44' jenkinsTest 'org.jenkins-ci.main:jenkins-test-harness-tools:2.2' + jenkinsPlugins 'org.jenkins-ci.plugins.workflow:workflow-aggregator:2.5' testImplementation 'org.spockframework:spock-core:0.7-groovy-1.8' diff --git a/src/main/java/hudson/plugins/gradle/BuildScanAction.java b/src/main/java/hudson/plugins/gradle/BuildScanAction.java index 58cca9d3..d0b2930a 100644 --- a/src/main/java/hudson/plugins/gradle/BuildScanAction.java +++ b/src/main/java/hudson/plugins/gradle/BuildScanAction.java @@ -32,7 +32,9 @@ public String getUrlName() { } public void addScanUrl(String scanUrl) { - scanUrls.add(scanUrl); + if (!scanUrls.contains(scanUrl)) { + scanUrls.add(scanUrl); + } } @Exported diff --git a/src/main/java/hudson/plugins/gradle/BuildScanLogScanner.java b/src/main/java/hudson/plugins/gradle/BuildScanLogScanner.java new file mode 100644 index 00000000..cec0b64c --- /dev/null +++ b/src/main/java/hudson/plugins/gradle/BuildScanLogScanner.java @@ -0,0 +1,33 @@ +package hudson.plugins.gradle; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class BuildScanLogScanner { + private final BuildScanPublishedListener listener; + private int linesSinceBuildScanPublishingMessage = Integer.MAX_VALUE; + private static final Pattern BUILD_SCAN_PATTERN = Pattern.compile("Publishing (build scan|build information)\\.\\.\\."); + private static final Pattern URL_PATTERN = Pattern.compile("https?://\\S*"); + + public static final int MAX_PUBLISHED_MESSAGE_LENGTH = 70; + + public BuildScanLogScanner(BuildScanPublishedListener listener) { + this.listener = listener; + } + + void scanLine(String line) { + if (linesSinceBuildScanPublishingMessage < 10) { + linesSinceBuildScanPublishingMessage++; + Matcher matcher = URL_PATTERN.matcher(line); + if (matcher.find()) { + linesSinceBuildScanPublishingMessage = Integer.MAX_VALUE; + String buildScanUrl = matcher.group(); + listener.onBuildScanPublished(buildScanUrl); + } + } + if (line.length() < MAX_PUBLISHED_MESSAGE_LENGTH && BUILD_SCAN_PATTERN.matcher(line).find()) { + linesSinceBuildScanPublishingMessage = 0; + } + + } +} diff --git a/src/main/java/hudson/plugins/gradle/BuildScanPublisher.java b/src/main/java/hudson/plugins/gradle/BuildScanPublisher.java new file mode 100644 index 00000000..77631f80 --- /dev/null +++ b/src/main/java/hudson/plugins/gradle/BuildScanPublisher.java @@ -0,0 +1,68 @@ +package hudson.plugins.gradle; + +import com.google.common.collect.ImmutableSet; +import hudson.Extension; +import hudson.model.Run; +import org.jenkinsci.plugins.workflow.steps.Step; +import org.jenkinsci.plugins.workflow.steps.StepContext; +import org.jenkinsci.plugins.workflow.steps.StepDescriptor; +import org.jenkinsci.plugins.workflow.steps.StepExecution; +import org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution; +import org.kohsuke.stapler.DataBoundConstructor; + +import javax.annotation.Nonnull; +import java.io.BufferedReader; +import java.util.Set; +import java.util.stream.Stream; + +public class BuildScanPublisher extends Step { + @DataBoundConstructor + public BuildScanPublisher() { + } + + @Override + public StepExecution start(StepContext context) { + return new Execution(context); + } + + static class Execution extends SynchronousNonBlockingStepExecution { + private static final long serialVersionUID = 1L; + + protected Execution(@Nonnull StepContext context) { + super(context); + } + + @Override + protected Void run() throws Exception { + Run run = getContext().get(Run.class); + BuildScanLogScanner scanner = new BuildScanLogScanner(new DefaultBuildScanPublishedListener(run)); + try ( + BufferedReader logReader = new BufferedReader(run.getLogReader()); + Stream lines = logReader.lines() + ) { + lines.forEach(scanner::scanLine); + } + return null; + } + } + + @Extension + public static final class DescriptorImpl extends StepDescriptor { + + @Override + public Set> getRequiredContext() { + return ImmutableSet.of(Run.class); + } + + @Nonnull + @Override + public String getDisplayName() { + return "Find published build scans"; + } + + @Override + public String getFunctionName() { + return "findBuildScans"; + } + } +} diff --git a/src/main/java/hudson/plugins/gradle/GradleConsoleAnnotator.java b/src/main/java/hudson/plugins/gradle/GradleConsoleAnnotator.java index 163a773e..af140efe 100644 --- a/src/main/java/hudson/plugins/gradle/GradleConsoleAnnotator.java +++ b/src/main/java/hudson/plugins/gradle/GradleConsoleAnnotator.java @@ -6,8 +6,6 @@ import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.charset.Charset; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * @author ikikko @@ -15,24 +13,18 @@ */ public class GradleConsoleAnnotator extends LineTransformationOutputStream { - private static final Pattern BUILD_SCAN_PATTERN = Pattern.compile("Publishing (build scan|build information)\\.\\.\\."); - private static final Pattern URL_PATTERN = Pattern.compile("https?://\\S*"); - private static final int MAX_PUBLISHED_MESSAGE_LENGTH = 70; - private final OutputStream out; private final Charset charset; private final boolean annotateGradleOutput; - private final BuildScanPublishedListener buildScanListener; private final int maxLineLength; - - private int linesSinceBuildScanPublishingMessage = Integer.MAX_VALUE; + private final BuildScanLogScanner buildScanLogScanner; public GradleConsoleAnnotator(OutputStream out, Charset charset, boolean annotateGradleOutput, BuildScanPublishedListener buildScanListener) { this.out = out; this.charset = charset; this.annotateGradleOutput = annotateGradleOutput; - this.buildScanListener = buildScanListener; - this.maxLineLength = annotateGradleOutput ? 500 : MAX_PUBLISHED_MESSAGE_LENGTH; + this.maxLineLength = annotateGradleOutput ? 500 : BuildScanLogScanner.MAX_PUBLISHED_MESSAGE_LENGTH; + this.buildScanLogScanner = new BuildScanLogScanner(buildScanListener); } @Override @@ -55,18 +47,7 @@ protected void eol(byte[] b, int len) throws IOException { } } - if (linesSinceBuildScanPublishingMessage < 10) { - linesSinceBuildScanPublishingMessage++; - Matcher matcher = URL_PATTERN.matcher(line); - if (matcher.find()) { - linesSinceBuildScanPublishingMessage = Integer.MAX_VALUE; - String buildScanUrl = matcher.group(); - buildScanListener.onBuildScanPublished(buildScanUrl); - } - } - if (len < MAX_PUBLISHED_MESSAGE_LENGTH && BUILD_SCAN_PATTERN.matcher(line).find()) { - linesSinceBuildScanPublishingMessage = 0; - } + buildScanLogScanner.scanLine(line); } out.write(b, 0, len); diff --git a/src/main/resources/hudson/plugins/gradle/BuildScanPublisher/help.html b/src/main/resources/hudson/plugins/gradle/BuildScanPublisher/help.html new file mode 100644 index 00000000..ddae0eff --- /dev/null +++ b/src/main/resources/hudson/plugins/gradle/BuildScanPublisher/help.html @@ -0,0 +1,4 @@ +
+ Inspect build log for published Gradle build scans. + The build scans will be shown on the pipeline build page. +