diff --git a/Jenkinsfile b/Jenkinsfile index 7963aaf..4777150 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,6 +1,10 @@ -def jenkinsLts = '2.235.5' +final jenkinsLast = '2.235.5' +final jenkinsLts = '2.263.2' buildPlugin(configurations: [ [ platform: 'linux', jdk: '8', jenkins: null ], + [ platform: 'linux', jdk: '8', jenkins: jenkinsLast, javaLevel: '8' ], + [ platform: 'windows', jdk: '8', jenkins: jenkinsLast, javaLevel: '8' ], + [ platform: 'linux', jdk: '11', jenkins: jenkinsLast, javaLevel: '8' ], [ platform: 'linux', jdk: '8', jenkins: jenkinsLts, javaLevel: '8' ], [ platform: 'windows', jdk: '8', jenkins: jenkinsLts, javaLevel: '8' ], [ platform: 'linux', jdk: '11', jenkins: jenkinsLts, javaLevel: '8' ], diff --git a/src/main/java/hudson/plugins/ansicolor/action/ShortlogActionCreator.java b/src/main/java/hudson/plugins/ansicolor/action/ShortlogActionCreator.java index 49da97f..01b8499 100644 --- a/src/main/java/hudson/plugins/ansicolor/action/ShortlogActionCreator.java +++ b/src/main/java/hudson/plugins/ansicolor/action/ShortlogActionCreator.java @@ -22,6 +22,8 @@ public class ShortlogActionCreator { private static final Logger LOGGER = Logger.getLogger(ShortlogActionCreator.class.getName()); private static final int CONSOLE_TAIL_DEFAULT = 150; private static final int BUFFER_SIZE = 16 * 1024; + public static final VersionNumber LINES_WHOLE_SINCE_VERSION = new VersionNumber("2.260"); + static final String PROP_LINES_WHOLE = "jenkins.ansicolor.keepLinesWhole"; private final LineIdentifier lineIdentifier; private final byte[] eol; @@ -100,7 +102,7 @@ private int indexOfEol(byte[] buf, int after) { private int[] calculateBeginLength(byte[] buf, int startInBuff, int eolPos, boolean keepLinesWhole) { if (keepLinesWhole) { - final int begin = eolPos != -1? eolPos + eol.length: startInBuff; + final int begin = eolPos != -1 ? eolPos + eol.length : startInBuff; return new int[]{begin, eolPos != -1 ? indexOfEol(buf, eolPos) - begin + eol.length : -1}; } return new int[]{startInBuff, eolPos != -1 ? eolPos - startInBuff + eol.length : -1}; @@ -112,7 +114,7 @@ public static class Listener extends RunListener> { public void onFinalized(Run run) { super.onFinalized(run); final List commands = Arrays.asList(ColorizedAction.Command.START, ColorizedAction.Command.STOP); - Map actions = run.getActions(ColorizedAction.class).stream() + final Map actions = run.getActions(ColorizedAction.class).stream() .filter(a -> commands.contains(a.getCommand())) .collect(Collectors.toMap(a -> { try { @@ -126,13 +128,15 @@ public void onFinalized(Run run) { final File logFile = new File(run.getRootDir(), "log"); if (logFile.isFile()) { final ShortlogActionCreator shortlogActionCreator = new ShortlogActionCreator(new LineIdentifier(), System.lineSeparator()); - final VersionNumber keepLinesWholeVersion = new VersionNumber("2.260"); final String consoleTail = System.getProperty("hudson.consoleTailKB"); + final boolean keepLinesWhole = Optional.ofNullable(System.getProperty(PROP_LINES_WHOLE)) + .map(Boolean::parseBoolean) + .orElseGet(() -> Optional.ofNullable(Jenkins.getVersion()).orElse(LINES_WHOLE_SINCE_VERSION).isNewerThan(LINES_WHOLE_SINCE_VERSION)); final ColorizedAction action = shortlogActionCreator.createActionForShortlog( logFile, actions, consoleTail != null ? Integer.parseInt(consoleTail) : CONSOLE_TAIL_DEFAULT, - Optional.ofNullable(Jenkins.getVersion()).orElse(keepLinesWholeVersion).isNewerThan(keepLinesWholeVersion) + keepLinesWhole ); if (action != null) { run.addAction(action); diff --git a/src/test/java/hudson/plugins/ansicolor/JenkinsTestSupport.java b/src/test/java/hudson/plugins/ansicolor/JenkinsTestSupport.java index 1532bb8..5412240 100644 --- a/src/test/java/hudson/plugins/ansicolor/JenkinsTestSupport.java +++ b/src/test/java/hudson/plugins/ansicolor/JenkinsTestSupport.java @@ -3,6 +3,7 @@ import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; +import org.junit.Assume; import org.junit.Rule; import org.junit.runners.model.Statement; import org.jvnet.hudson.test.RestartableJenkinsRule; @@ -11,6 +12,8 @@ import java.io.StringWriter; import java.util.Collection; import java.util.Collections; +import java.util.Map; +import java.util.function.BooleanSupplier; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -22,15 +25,32 @@ public class JenkinsTestSupport { public RestartableJenkinsRule jenkinsRule = new RestartableJenkinsRule(); private static final int CONSOLE_TAIL_DEFAULT = 150; - protected void assertOutputOnRunningPipeline(String expectedOutput, String notExpectedOutput, String pipelineScript, boolean useShortLog) { - assertOutputOnRunningPipeline(Collections.singletonList(expectedOutput), Collections.singletonList(notExpectedOutput), pipelineScript, useShortLog); + protected void assertOutputOnRunningPipeline(BooleanSupplier assumption, String expectedOutput, String notExpectedOutput, String pipelineScript, boolean useShortLog, Map properties) { + assertOutputOnRunningPipeline(assumption, Collections.singletonList(expectedOutput), Collections.singletonList(notExpectedOutput), pipelineScript, useShortLog, properties); } protected void assertOutputOnRunningPipeline(Collection expectedOutput, Collection notExpectedOutput, String pipelineScript, boolean useShortLog) { + assertOutputOnRunningPipeline(() -> true, expectedOutput, notExpectedOutput, pipelineScript, useShortLog, Collections.emptyMap()); + } + + protected void assertOutputOnRunningPipeline(Collection expectedOutput, Collection notExpectedOutput, String pipelineScript, boolean useShortLog, Map properties) { + assertOutputOnRunningPipeline(() -> true, expectedOutput, notExpectedOutput, pipelineScript, useShortLog, properties); + } + + protected void assertOutputOnRunningPipeline( + BooleanSupplier assumption, + Collection expectedOutput, + Collection notExpectedOutput, + String pipelineScript, + boolean useShortLog, + Map properties + ) { jenkinsRule.addStep(new Statement() { @Override public void evaluate() throws Throwable { + Assume.assumeTrue(assumption.getAsBoolean()); + properties.forEach(System::setProperty); final WorkflowJob project = jenkinsRule.j.jenkins.createProject(WorkflowJob.class, "test-project-" + JenkinsTestSupport.this.getClass().getSimpleName()); project.setDefinition(new CpsFlowDefinition(pipelineScript, true)); jenkinsRule.j.assertBuildStatusSuccess(project.scheduleBuild2(0)); @@ -38,6 +58,7 @@ public void evaluate() throws Throwable { final WorkflowRun lastBuild = project.getLastBuild(); final long start = useShortLog ? new File(lastBuild.getRootDir(), "log").length() - CONSOLE_TAIL_DEFAULT * 1024 : 0; assertTrue(lastBuild.getLogText().writeHtmlTo(start, writer) > 0); + properties.keySet().forEach(System::clearProperty); final String html = writer.toString().replaceAll("", ""); assertThat(html).contains(expectedOutput); assertThat(html).doesNotContain(notExpectedOutput); diff --git a/src/test/java/hudson/plugins/ansicolor/action/ShortlogActionCreatorIntegrationTest.java b/src/test/java/hudson/plugins/ansicolor/action/ShortlogActionCreatorIntegrationTest.java index 0eb419f..143fc43 100644 --- a/src/test/java/hudson/plugins/ansicolor/action/ShortlogActionCreatorIntegrationTest.java +++ b/src/test/java/hudson/plugins/ansicolor/action/ShortlogActionCreatorIntegrationTest.java @@ -1,9 +1,15 @@ package hudson.plugins.ansicolor.action; import hudson.plugins.ansicolor.JenkinsTestSupport; +import jenkins.model.Jenkins; +import org.junit.Ignore; import org.junit.Test; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.BooleanSupplier; public class ShortlogActionCreatorIntegrationTest extends JenkinsTestSupport { private static final String AS_1K = repeat("a", 1024); @@ -12,15 +18,35 @@ public class ShortlogActionCreatorIntegrationTest extends JenkinsTestSupport { private static final String DS_1K = repeat("d", 1024); @Test - public void canAnotateLongLogOutputInShortlog() { + public void canAnnotateLongLogOutputInShortlogLinesWholeFalse() { final String script = "ansiColor('xterm') {\n" + repeat("echo '\033[32m" + AS_1K + "\033[0m'\n", 150) + "}"; - assertOutputOnRunningPipeline("" + AS_1K + "", "\033", script, true); + final Map properties = new HashMap<>(); + properties.put(ShortlogActionCreator.PROP_LINES_WHOLE, "false"); + BooleanSupplier brokenLinesJenkins = () -> Optional.ofNullable(Jenkins.getVersion()) + .orElse(ShortlogActionCreator.LINES_WHOLE_SINCE_VERSION) + .isOlderThan(ShortlogActionCreator.LINES_WHOLE_SINCE_VERSION); + assertOutputOnRunningPipeline(brokenLinesJenkins, "" + AS_1K + "", "\033", script, true, properties); } @Test - public void canAnotateLongLogOutputInShortlogMultipleSteps() { + @Ignore("Needs adjustments for Jenkins > 2.260") + public void canAnnotateLongLogOutputInShortlogLinesWholeTrue() { + final String script = "ansiColor('xterm') {\n" + + repeat("echo '\033[32m" + AS_1K + "\033[0m'\n", 150) + + "echo 'Abc'\n" + + "}"; + final Map properties = new HashMap<>(); + properties.put(ShortlogActionCreator.PROP_LINES_WHOLE, "true"); + BooleanSupplier wholeLinesJenkins = () -> Optional.ofNullable(Jenkins.getVersion()) + .orElse(ShortlogActionCreator.LINES_WHOLE_SINCE_VERSION) + .isNewerThan(ShortlogActionCreator.LINES_WHOLE_SINCE_VERSION); + assertOutputOnRunningPipeline(wholeLinesJenkins, "" + AS_1K + "", "\033", script, true, properties); + } + + @Test + public void canAnnotateLongLogOutputInShortlogMultipleStepsLinesWholeFalse() { final String script = "echo '\033[32mBeginning\033[0m'\n" + "ansiColor('vga') {\n" + repeat(" echo '\033[32m" + AS_1K + "\033[0m'\n", 10) + @@ -34,6 +60,8 @@ public void canAnotateLongLogOutputInShortlogMultipleSteps() { "}\n" + "echo 'End'"; + final Map properties = new HashMap<>(); + properties.put(ShortlogActionCreator.PROP_LINES_WHOLE, "false"); assertOutputOnRunningPipeline( Arrays.asList( "" + BS_1K + "", @@ -50,7 +78,46 @@ public void canAnotateLongLogOutputInShortlogMultipleSteps() { "\033[32m" + DS_1K + "\033[0m" ), script, - true + true, + properties + ); + } + + @Test + public void canAnnotateLongLogOutputInShortlogMultipleStepsLinesWholeTrue() { + final String script = "echo '\033[32mBeginning\033[0m'\n" + + "ansiColor('vga') {\n" + + repeat(" echo '\033[32m" + AS_1K + "\033[0m'\n", 10) + + "}\n" + + "ansiColor('xterm') {\n" + + repeat(" echo '\033[32m" + BS_1K + "\033[0m'\n", 30) + + "}\n" + + "ansiColor('css') {\n" + + repeat(" echo '\033[32m" + CS_1K + "\033[0m'\n", 50) + + repeat(" echo '\033[32m" + DS_1K + "\033[0m'\n", 50) + + "}\n" + + "echo 'End'"; + + final Map properties = new HashMap<>(); + properties.put(ShortlogActionCreator.PROP_LINES_WHOLE, "true"); + assertOutputOnRunningPipeline( + Arrays.asList( + "\033[32m" + BS_1K + "\033[0m", + "" + CS_1K + "", + "" + DS_1K + "", + "End" + ), + Arrays.asList( + "Beginning", + "a", + "\033[32m" + AS_1K + "\033[0m", + "" + BS_1K + "", + "\033[32m" + CS_1K + "\033[0m", + "\033[32m" + DS_1K + "\033[0m" + ), + script, + true, + properties ); } }