diff --git a/CHANGELOG.md b/CHANGELOG.md index 01cbe00..14cc672 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ * Your contribution here. * [#107](https://github.com/jenkinsci/ansicolor-plugin/pull/107): Removing startup banner - [@jglick](https://github.com/jglick). +* [#128](https://github.com/jenkinsci/ansicolor-plugin/pull/128): Restoring limited compatibility for coloration generated remotely by Pipeline builds on agents - [@jglick](https://github.com/jglick). 0.5.2 (08/17/2017) ============ diff --git a/pom.xml b/pom.xml index a3682a8..0a18745 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,8 @@ org.jenkins-ci.plugins plugin - 2.25 + 3.25 + ansicolor @@ -45,23 +46,51 @@ - 1.642.3 + 2.121.2 + 8 org.jenkins-ci.plugins.workflow workflow-step-api - 2.12 + 2.15 true org.jenkins-ci.plugins.workflow - workflow-aggregator - 2.5 + workflow-cps + 2.59 + test + + + org.jenkins-ci.plugins.workflow + workflow-job + 2.26 + test + + + org.jenkins-ci.plugins.workflow + workflow-durable-task-step + 2.25 + test + + + org.jenkins-ci.plugins.workflow + workflow-basic-steps + 2.12 test + + + + org.jenkins-ci.plugins + structs + 1.17 + + + diff --git a/src/main/java/hudson/plugins/ansicolor/AnsiColorConsoleLogFilter.java b/src/main/java/hudson/plugins/ansicolor/AnsiColorConsoleLogFilter.java index 4c1b912..e318629 100644 --- a/src/main/java/hudson/plugins/ansicolor/AnsiColorConsoleLogFilter.java +++ b/src/main/java/hudson/plugins/ansicolor/AnsiColorConsoleLogFilter.java @@ -3,12 +3,16 @@ import hudson.console.ConsoleLogFilter; import hudson.console.LineTransformationOutputStream; import hudson.model.AbstractBuild; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; +import jenkins.util.JenkinsJVM; /** * {@link ConsoleLogFilter} that adds a {@link SimpleHtmlNote} to each line. @@ -20,10 +24,40 @@ public final class AnsiColorConsoleLogFilter extends ConsoleLogFilter implements private static final Logger LOG = Logger.getLogger(AnsiColorConsoleLogFilter.class.getName()); private AnsiColorMap colorMap; + private final Map notes; public AnsiColorConsoleLogFilter(AnsiColorMap colorMap) { super(); this.colorMap = colorMap; + this.notes = new HashMap<>(); + // some cases of AnsiHtmlOutputStream.setForegroundColor: + for (AnsiColorMap.Color color : AnsiColorMap.Color.values()) { + pregenerateNote(new AnsiAttributeElement(AnsiAttributeElement.AnsiAttrType.FG, "span", "style=\"color: " + colorMap.getNormal(color.ordinal()) + ";\"")); + } + // TODO other cases, and other methods + LOG.log(Level.FINE, "Notes pregenerated for {0}", notes.keySet()); + } + + private void pregenerateNote(AnsiAttributeElement element) { + element.emitOpen(html -> pregenerateNote(html)); + element.emitClose(html -> pregenerateNote(html)); + } + + private void pregenerateNote(String html) { + if (!notes.containsKey(html)) { + JenkinsJVM.checkJenkinsJVM(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + new SimpleHtmlNote(html).encodeTo(baos); + } catch (IOException x) { // should be impossible + throw new RuntimeException(x); + } + notes.put(html, baos.toByteArray()); + } + } + + private Object readResolve() { // handle old program.dat + return notes == null ? new AnsiColorConsoleLogFilter(colorMap) : this; } @SuppressWarnings("rawtypes") @@ -39,7 +73,12 @@ public OutputStream decorateLogger(AbstractBuild build, final OutputStream logge @Override public void emitHtml(String html) { try { - new SimpleHtmlNote(html).encodeTo(logger); + byte[] pregenerated = notes.get(html); + if (pregenerated != null) { + logger.write(pregenerated); + } else { + new SimpleHtmlNote(html).encodeTo(logger); + } } catch (IOException e) { LOG.log(Level.WARNING, "Failed to add HTML markup '" + html + "'", e); } diff --git a/src/test/java/hudson/plugins/ansicolor/AnsiColorBuildWrapperTest.java b/src/test/java/hudson/plugins/ansicolor/AnsiColorBuildWrapperTest.java index 13851ae..06fabf7 100644 --- a/src/test/java/hudson/plugins/ansicolor/AnsiColorBuildWrapperTest.java +++ b/src/test/java/hudson/plugins/ansicolor/AnsiColorBuildWrapperTest.java @@ -1,11 +1,12 @@ package hudson.plugins.ansicolor; import hudson.Functions; +import hudson.console.ConsoleNote; import java.io.StringWriter; +import java.util.logging.Level; import static org.hamcrest.CoreMatchers.instanceOf; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; -import org.jenkinsci.plugins.workflow.job.WorkflowRun; import org.junit.Test; import static org.junit.Assert.*; import org.junit.Assume; @@ -13,6 +14,8 @@ import org.junit.Rule; import org.junit.runners.model.Statement; import org.jvnet.hudson.test.BuildWatcher; +import org.jvnet.hudson.test.Issue; +import org.jvnet.hudson.test.LoggerRule; import org.jvnet.hudson.test.RestartableJenkinsRule; public class AnsiColorBuildWrapperTest { @@ -42,7 +45,10 @@ public void testDecorateLogger() { public static BuildWatcher buildWatcher = new BuildWatcher(); @Rule public RestartableJenkinsRule story = new RestartableJenkinsRule(); + @Rule + public LoggerRule logging = new LoggerRule().recordPackage(ConsoleNote.class, Level.FINE); + @Issue("JENKINS-54133") @Test public void testWorkflowWrap() throws Exception { story.addStep(new Statement() { @@ -50,9 +56,10 @@ public void testWorkflowWrap() throws Exception { @Override public void evaluate() throws Throwable { Assume.assumeTrue(!Functions.isWindows()); + story.j.createSlave(); WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition( - "node {\n" + "node('!master') {\n" + " wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm', 'defaultFg': 1, 'defaultBg': 2]) {\n" + " sh(\"\"\"#!/bin/bash\n" + " printf 'The following word is supposed to be \\\\e[31mred\\\\e[0m\\\\n'\"\"\"\n"