diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fe96cf..99b6a5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ -0.5.4 (Next) +0.6 (Next) ============ +* [#132](https://github.com/jenkinsci/ansicolor-plugin/pull/132): Reworked implementation to add markup on display, not to the actual build log - [@jglick](https://github.com/jglick). * Your contribution here. 0.5.3 (11/06/2018) diff --git a/pom.xml b/pom.xml index 6890c3b..1e52962 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ ansicolor - 0.5.4-SNAPSHOT + 0.6-SNAPSHOT hpi AnsiColor @@ -46,7 +46,7 @@ - 2.121.2 + 2.145 8 @@ -57,6 +57,12 @@ 2.15 true + + org.jenkins-ci.plugins.workflow + workflow-api + 2.30 + true + org.jenkins-ci.plugins.workflow workflow-cps @@ -89,6 +95,11 @@ structs 1.17 + + org.jenkins-ci.plugins + scm-api + 2.2.6 + diff --git a/src/main/java/hudson/plugins/ansicolor/AnsiColorBuildWrapper.java b/src/main/java/hudson/plugins/ansicolor/AnsiColorBuildWrapper.java index 1b67a4c..f37beef 100644 --- a/src/main/java/hudson/plugins/ansicolor/AnsiColorBuildWrapper.java +++ b/src/main/java/hudson/plugins/ansicolor/AnsiColorBuildWrapper.java @@ -27,7 +27,6 @@ import hudson.Extension; import hudson.FilePath; import hudson.Launcher; -import hudson.console.ConsoleLogFilter; import hudson.model.TaskListener; import hudson.model.AbstractProject; import hudson.model.Run; @@ -80,6 +79,7 @@ public DescriptorImpl getDescriptor() { @Override public void setUp(Context context, Run build, FilePath workspace, Launcher launcher, TaskListener listener, EnvVars initialEnvironment) throws IOException, InterruptedException { + build.replaceAction(new ColorizedAction(colorMapName)); } /** @@ -188,8 +188,4 @@ public boolean isApplicable(AbstractProject item) { } } - @Override - public ConsoleLogFilter createLoggerDecorator(Run build) { - return new AnsiColorConsoleLogFilter(getDescriptor().getColorMap(colorMapName)); - } } diff --git a/src/main/java/hudson/plugins/ansicolor/AnsiColorConsoleLogFilter.java b/src/main/java/hudson/plugins/ansicolor/AnsiColorConsoleLogFilter.java index 646f5f8..570f7ea 100644 --- a/src/main/java/hudson/plugins/ansicolor/AnsiColorConsoleLogFilter.java +++ b/src/main/java/hudson/plugins/ansicolor/AnsiColorConsoleLogFilter.java @@ -15,7 +15,9 @@ /** * {@link ConsoleLogFilter} that adds a {@link SimpleHtmlNote} to each line. + * @deprecated Only here for serial form compatibility. */ +@Deprecated public final class AnsiColorConsoleLogFilter extends ConsoleLogFilter implements Serializable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/hudson/plugins/ansicolor/AnsiColorStep.java b/src/main/java/hudson/plugins/ansicolor/AnsiColorStep.java index 0a7411f..bdc88aa 100644 --- a/src/main/java/hudson/plugins/ansicolor/AnsiColorStep.java +++ b/src/main/java/hudson/plugins/ansicolor/AnsiColorStep.java @@ -1,32 +1,30 @@ package hudson.plugins.ansicolor; import hudson.Extension; -import hudson.console.ConsoleLogFilter; import hudson.plugins.ansicolor.AnsiColorBuildWrapper.DescriptorImpl; import hudson.util.ListBoxModel; -import java.io.IOException; import java.util.Collections; -import javax.annotation.Nonnull; import jenkins.model.Jenkins; -import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; import org.jenkinsci.plugins.workflow.steps.AbstractStepExecutionImpl; -import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl; import org.jenkinsci.plugins.workflow.steps.BodyExecutionCallback; -import org.jenkinsci.plugins.workflow.steps.BodyInvoker; import org.jenkinsci.plugins.workflow.steps.EnvironmentExpander; import org.jenkinsci.plugins.workflow.steps.StepContext; import org.kohsuke.stapler.DataBoundConstructor; -import com.google.inject.Inject; +import hudson.model.Run; +import java.util.Set; +import org.jenkinsci.plugins.workflow.steps.Step; +import org.jenkinsci.plugins.workflow.steps.StepDescriptor; +import org.jenkinsci.plugins.workflow.steps.StepExecution; /** * Custom pipeline step that can be used without a node and build wrapper. */ -public class AnsiColorStep extends AbstractStepImpl { +public class AnsiColorStep extends Step { private final String colorMapName; @@ -50,15 +48,24 @@ private static DescriptorImpl getWrapperDescriptor() { return Jenkins.getActiveInstance().getDescriptorByType(DescriptorImpl.class); } + @Override + public StepExecution start(StepContext context) throws Exception { + return new ExecutionImpl(context, colorMapName); + } + /** * Execution for {@link AnsiColorStep}. */ - public static class ExecutionImpl extends AbstractStepExecutionImpl { + private static class ExecutionImpl extends AbstractStepExecutionImpl { private static final long serialVersionUID = 1L; - @Inject(optional = true) - private transient AnsiColorStep step; + private final String colorMapName; + + ExecutionImpl(StepContext context, String colorMapName) { + super(context); + this.colorMapName = colorMapName; + } /** * {@inheritDoc} @@ -66,39 +73,22 @@ public static class ExecutionImpl extends AbstractStepExecutionImpl { @Override public boolean start() throws Exception { StepContext context = getContext(); + context.get(Run.class).replaceAction(new ColorizedAction(colorMapName)); EnvironmentExpander currentEnvironment = context.get(EnvironmentExpander.class); - EnvironmentExpander terminalEnvironment = EnvironmentExpander.constant(Collections.singletonMap("TERM", step.getColorMapName())); - context.newBodyInvoker().withContext(createConsoleLogFilter(context)) + EnvironmentExpander terminalEnvironment = EnvironmentExpander.constant(Collections.singletonMap("TERM", colorMapName)); + context.newBodyInvoker() .withContext(EnvironmentExpander.merge(currentEnvironment, terminalEnvironment)) .withCallback(BodyExecutionCallback.wrap(context)).start(); return false; } - private ConsoleLogFilter createConsoleLogFilter(StepContext context) - throws IOException, InterruptedException { - ConsoleLogFilter original = context.get(ConsoleLogFilter.class); - ConsoleLogFilter subsequent = new AnsiColorConsoleLogFilter(step.getColorMap()); - return BodyInvoker.mergeConsoleLogFilters(original, subsequent); - } - - /** - * {@inheritDoc} - */ - @Override - public void stop(@Nonnull Throwable cause) throws Exception { - getContext().onFailure(cause); - } } /** * Descriptor for {@link AnsiColorStep}. */ @Extension(optional = true) - public static class StepDescriptorImpl extends AbstractStepDescriptorImpl { - - public StepDescriptorImpl() { - super(ExecutionImpl.class); - } + public static class StepDescriptorImpl extends StepDescriptor { @Override public String getDisplayName() { @@ -124,5 +114,11 @@ public boolean takesImplicitBlockArgument() { public ListBoxModel doFillColorMapNameItems() { return getWrapperDescriptor().doFillColorMapNameItems(); } + + @Override + public Set> getRequiredContext() { + return Collections.singleton(Run.class); + } + } } diff --git a/src/main/java/hudson/plugins/ansicolor/ColorConsoleAnnotator.java b/src/main/java/hudson/plugins/ansicolor/ColorConsoleAnnotator.java new file mode 100644 index 0000000..fc54977 --- /dev/null +++ b/src/main/java/hudson/plugins/ansicolor/ColorConsoleAnnotator.java @@ -0,0 +1,135 @@ +/* + * The MIT License + * + * Copyright 2018 CloudBees, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package hudson.plugins.ansicolor; + +import hudson.Extension; +import hudson.MarkupText; +import hudson.console.ConsoleAnnotator; +import hudson.console.ConsoleAnnotatorFactory; +import hudson.model.Queue; +import hudson.model.Run; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; +import jenkins.model.Jenkins; +import org.apache.commons.io.output.CountingOutputStream; +import org.apache.commons.io.output.NullOutputStream; +import org.apache.commons.lang.StringEscapeUtils; +import org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner; +import org.jenkinsci.plugins.workflow.graph.FlowNode; + +/** + * Applies ANSI coloration to log files where requested. + */ +final class ColorConsoleAnnotator extends ConsoleAnnotator { + + private static final Logger LOGGER = Logger.getLogger(ColorConsoleAnnotator.class.getName()); + + private static final long serialVersionUID = 1; + + private final String colorMapName; + private final String charset; + + ColorConsoleAnnotator(String colorMapName, String charset) { + this.colorMapName = colorMapName; + this.charset = charset; + LOGGER.fine("creating annotator with colorMapName=" + colorMapName + " charset=" + charset); + } + + @Override + public ConsoleAnnotator annotate(Object context, MarkupText text) { + String s = text.getText(); + if (s.indexOf('\u001B') != -1) { + AnsiColorMap colorMap = Jenkins.get().getDescriptorByType(AnsiColorBuildWrapper.DescriptorImpl.class).getColorMap(colorMapName); + CountingOutputStream outgoing = new CountingOutputStream(new NullOutputStream()); + class EmitterImpl implements AnsiAttributeElement.Emitter { + CountingOutputStream incoming; + int adjustment; + int lastPoint = -1; // multiple HTML tags may be emitted for one control sequence + @Override + public void emitHtml(String html) { + LOGGER.finest("emitting " + html + " @" + incoming.getCount()); + text.addMarkup(incoming.getCount(), html); + if (incoming.getCount() != lastPoint) { + lastPoint = incoming.getCount(); + int hide = incoming.getCount() - outgoing.getCount() - adjustment; + LOGGER.finest("hiding " + hide + " @" + (outgoing.getCount() + adjustment)); + text.addMarkup(outgoing.getCount() + adjustment, outgoing.getCount() + adjustment + hide, "", ""); + adjustment += hide; + } + } + } + EmitterImpl emitter = new EmitterImpl(); + CountingOutputStream incoming = new CountingOutputStream(new AnsiHtmlOutputStream(outgoing, colorMap, emitter)); + emitter.incoming = incoming; + try { + byte[] data = s.getBytes(charset); + for (int i = 0; i < data.length; i++) { + // Do not use write(byte[]) as offsets in incoming would not be accurate. + incoming.write(data[i]); + } + } catch (IOException x) { + LOGGER.log(Level.WARNING, null, x); + } + LOGGER.finer(() -> "\"" + StringEscapeUtils.escapeJava(s) + "\" → \"" + StringEscapeUtils.escapeJava(text.toString(true)) + "\""); + } + return this; + } + + @Extension + public static final class Factory extends ConsoleAnnotatorFactory { + + @Override + public ConsoleAnnotator newInstance(Object context) { + LOGGER.fine("context=" + context); + if (context instanceof Run) { + ColorizedAction action = ((Run) context).getAction(ColorizedAction.class); + if (action != null) { + return new ColorConsoleAnnotator(action.colorMapName, ((Run) context).getCharset().name()); + } + } else if (Jenkins.get().getPlugin("workflow-api") != null && context instanceof FlowNode) { + FlowNode node = (FlowNode) context; + FlowExecutionOwner owner = node.getExecution().getOwner(); + if (owner != null) { + Queue.Executable exec = null; + try { + exec = owner.getExecutable(); + } catch (IOException x) { + LOGGER.log(Level.WARNING, null, x); + } + if (exec instanceof Run) { + ColorizedAction action = ((Run) exec).getAction(ColorizedAction.class); + if (action != null) { + return new ColorConsoleAnnotator(action.colorMapName, /* JEp-206 */ "UTF-8"); + } + } + } + } + return null; + } + + } + +} diff --git a/src/main/java/hudson/plugins/ansicolor/ColorizedAction.java b/src/main/java/hudson/plugins/ansicolor/ColorizedAction.java new file mode 100644 index 0000000..9c38005 --- /dev/null +++ b/src/main/java/hudson/plugins/ansicolor/ColorizedAction.java @@ -0,0 +1,41 @@ +/* + * The MIT License + * + * Copyright 2018 CloudBees, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package hudson.plugins.ansicolor; + +import hudson.model.InvisibleAction; + +/** + * Marker for the fact that a build used colorization. + * Note that the specific log span(s) are ignored. + */ +final class ColorizedAction extends InvisibleAction { + + final String colorMapName; + + ColorizedAction(String colorMapName) { + this.colorMapName = colorMapName; + } + +} diff --git a/src/main/java/hudson/plugins/ansicolor/SimpleHtmlNote.java b/src/main/java/hudson/plugins/ansicolor/SimpleHtmlNote.java index 49c9dd1..4d7a2e0 100644 --- a/src/main/java/hudson/plugins/ansicolor/SimpleHtmlNote.java +++ b/src/main/java/hudson/plugins/ansicolor/SimpleHtmlNote.java @@ -6,7 +6,9 @@ /** * A simple ConsoleNote which represents just a simple tag. + * @deprecated Only here for serial form compatibility. */ +@Deprecated public class SimpleHtmlNote extends ConsoleNote { private String tagHtml; diff --git a/src/test/java/hudson/plugins/ansicolor/AnsiColorBuildWrapperTest.java b/src/test/java/hudson/plugins/ansicolor/AnsiColorBuildWrapperTest.java index 06fabf7..211a21a 100644 --- a/src/test/java/hudson/plugins/ansicolor/AnsiColorBuildWrapperTest.java +++ b/src/test/java/hudson/plugins/ansicolor/AnsiColorBuildWrapperTest.java @@ -1,10 +1,16 @@ package hudson.plugins.ansicolor; import hudson.Functions; +import hudson.Launcher; import hudson.console.ConsoleNote; +import hudson.model.AbstractBuild; +import hudson.model.BuildListener; +import hudson.model.FreeStyleBuild; +import hudson.model.FreeStyleProject; +import java.io.IOException; import java.io.StringWriter; import java.util.logging.Level; -import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.Matchers.*; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.junit.Test; @@ -17,6 +23,7 @@ import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.LoggerRule; import org.jvnet.hudson.test.RestartableJenkinsRule; +import org.jvnet.hudson.test.TestBuilder; public class AnsiColorBuildWrapperTest { @@ -46,7 +53,40 @@ public void testDecorateLogger() { @Rule public RestartableJenkinsRule story = new RestartableJenkinsRule(); @Rule - public LoggerRule logging = new LoggerRule().recordPackage(ConsoleNote.class, Level.FINE); + public LoggerRule logging = new LoggerRule().recordPackage(ConsoleNote.class, Level.FINE).record(ColorConsoleAnnotator.class, Level.FINER); + + @Test + public void maven() throws Exception { + story.then(r -> { + FreeStyleProject p = r.createFreeStyleProject(); + p.getBuildWrappersList().add(new AnsiColorBuildWrapper(null)); + p.getBuildersList().add(new TestBuilder() { + @Override + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + // Like Maven 3.6.0 when using (MNG-6380) MAVEN_OPTS=-Djansi.force=true + listener.getLogger().println("[\u001B[1;34mINFO\u001B[m] Scanning for projects..."); + listener.getLogger().println("[\u001B[1;34mINFO\u001B[m] "); + listener.getLogger().println("[\u001B[1;34mINFO\u001B[m] \u001B[1m--------------< \u001B[0;36morg.jenkins-ci.plugins:build-token-root\u001B[0;1m >---------------\u001B[m"); + listener.getLogger().println("[\u001B[1;34mINFO\u001B[m] \u001B[1mBuilding Build Authorization Token Root Plugin 1.5-SNAPSHOT\u001B[m"); + listener.getLogger().println("[\u001B[1;34mINFO\u001B[m] \u001B[1m--------------------------------[ hpi ]---------------------------------\u001B[m"); + listener.getLogger().println("[\u001B[1;34mINFO\u001B[m] "); + listener.getLogger().println("[\u001B[1;34mINFO\u001B[m] \u001B[1m--- \u001B[0;32mmaven-clean-plugin:3.0.0:clean\u001B[m \u001B[1m(default-clean)\u001B[m @ \u001B[36mbuild-token-root\u001B[0;1m ---\u001B[m"); + listener.getLogger().println("[\u001B[1;34mINFO\u001B[m] \u001B[1m------------------------------------------------------------------------\u001B[m"); + listener.getLogger().println("[\u001B[1;34mINFO\u001B[m] \u001B[1;32mBUILD SUCCESS\u001B[m"); + return true; + } + }); + FreeStyleBuild b = r.buildAndAssertSuccess(p); + StringWriter writer = new StringWriter(); + b.getLogText().writeHtmlTo(0L, writer); + String html = writer.toString(); + System.out.print(html); + assertThat(html.replaceAll(".+?", ""), + allOf( + containsString("[INFO]"), + containsString("--------------< org.jenkins-ci.plugins:build-token-root >---------------"))); + }); + } @Issue("JENKINS-54133") @Test @@ -71,7 +111,8 @@ public void evaluate() throws Throwable { StringWriter writer = new StringWriter(); p.getLastBuild().getLogText().writeHtmlTo(0L, writer); String html = writer.toString(); - assertTrue("Failed to match color attribute in following HTML log output:\n" + html, html.matches("(?s).*red.*")); + assertTrue("Failed to match color attribute in following HTML log output:\n" + html, + html.replaceAll(".+?", "").matches("(?s).*red.*")); } }); } diff --git a/src/test/java/hudson/plugins/ansicolor/AnsiColorConsoleLogFilterTest.java b/src/test/java/hudson/plugins/ansicolor/AnsiColorConsoleLogFilterTest.java deleted file mode 100644 index b116048..0000000 --- a/src/test/java/hudson/plugins/ansicolor/AnsiColorConsoleLogFilterTest.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * The MIT License - * - * Copyright 2018 CloudBees, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package hudson.plugins.ansicolor; - -import hudson.console.ConsoleAnnotationOutputStream; -import hudson.model.AbstractBuild; -import hudson.model.TaskListener; -import hudson.slaves.DumbSlave; -import hudson.util.StreamTaskListener; -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintStream; -import java.io.StringWriter; -import java.nio.charset.StandardCharsets; -import java.util.logging.Level; -import jenkins.security.MasterToSlaveCallable; -import org.jenkinsci.plugins.workflow.log.ConsoleAnnotators; -import org.junit.AssumptionViolatedException; // Ignore seems to be ignored in this context -import org.junit.ClassRule; -import org.junit.BeforeClass; -import org.jvnet.hudson.test.Issue; -import org.jvnet.hudson.test.JenkinsRule; -import org.jvnet.hudson.test.LoggerRule; - -/** - * Checks which kinds of console notes are successfully pregenerated for use in a remoted filter. - */ -@Issue("JENKINS-54133") -public class AnsiColorConsoleLogFilterTest extends AnsiHtmlOutputStreamTest { - - @ClassRule - public static LoggerRule logging = new LoggerRule().record(AnsiColorConsoleLogFilter.class, Level.FINE); - - @ClassRule - public static JenkinsRule r = new JenkinsRule(); - - private static DumbSlave s; - - @BeforeClass - public static void createSlave() throws Exception { - s = r.createOnlineSlave(); - } - - @Override - protected String annotate(String text, AnsiColorMap colorMap) throws IOException { - StringWriter sw = new StringWriter(); - try (OutputStream caos = new ConsoleAnnotationOutputStream(sw, ConsoleAnnotators.createAnnotator(null), null, StandardCharsets.UTF_8); - StreamTaskListener listener = new StreamTaskListener(caos)) { - s.getChannel().call(new AnnotateCallable(text, listener, new AnsiColorConsoleLogFilter(colorMap))); - } catch (IOException x) { - throw x; - } catch (Exception x) { - throw new IOException(x); - } - return sw.toString(); - } - - private static final class AnnotateCallable extends MasterToSlaveCallable { - - private final String text; - private final TaskListener listener; - private final AnsiColorConsoleLogFilter filter; - - AnnotateCallable(String text, TaskListener listener, AnsiColorConsoleLogFilter filter) { - this.text = text; - this.listener = listener; - this.filter = filter; - } - - @Override - public Void call() throws Exception { - try (OutputStream decorated = filter.decorateLogger((AbstractBuild) null, listener.getLogger()); - PrintStream ps = new PrintStream(decorated)) { - ps.print(text); - } - return null; - } - - } - - @Override - public void testEmbeddedConsoleNote() throws IOException { - throw new AssumptionViolatedException("seems irrelevant"); - } - - @Override - public void testNegative() throws IOException { - throw new AssumptionViolatedException("TODO not implemented"); - } - - @Override - public void testGreenOnWhite() throws IOException { - throw new AssumptionViolatedException("TODO missing background-color"); - } - - @Override - public void testGreenOnWhiteCSS() throws IOException { - throw new AssumptionViolatedException("TODO missing background-color"); - } - - @Override - public void testGreenOnWhiteXTerm() throws IOException { - throw new AssumptionViolatedException("TODO missing background-color"); - } - - @Override - public void testResetForegroundColor() throws IOException { - throw new AssumptionViolatedException("TODO missing bold"); - } - - @Override - public void testForegroundColor256() throws IOException { - throw new AssumptionViolatedException("other than the standard colors, which could be split into a separate test, seems unimplementable"); - } - - @Override - public void testForegroundColorRgb() throws IOException { - throw new AssumptionViolatedException("probably unimplementable"); - } - - @Override - public void testResetBackgroundColor() throws IOException { - throw new AssumptionViolatedException("TODO not implemented"); - } - - @Override - public void testBackgroundColorHighIntensity() throws IOException { - throw new AssumptionViolatedException("TODO not implemented"); - } - - @Override - public void testBackgroundColor256() throws IOException { - throw new AssumptionViolatedException("other than the standard colors, which could be split into a separate test, seems unimplementable"); - } - - @Override - public void testBackgroundColorRgb() throws IOException { - throw new AssumptionViolatedException("probably unimplementable"); - } - - @Override - public void testDefaultColors() throws IOException { - throw new AssumptionViolatedException("TODO missing background-color"); - } - - @Override - public void testConsoleNote() throws IOException { - throw new AssumptionViolatedException("seems irrelevant"); - } - - @Override - public void testOverlapping() throws IOException { - throw new AssumptionViolatedException("TODO missing some things"); - } - -} diff --git a/src/test/java/hudson/plugins/ansicolor/AnsiColorStepTest.java b/src/test/java/hudson/plugins/ansicolor/AnsiColorStepTest.java index a70c3b4..14ed73a 100644 --- a/src/test/java/hudson/plugins/ansicolor/AnsiColorStepTest.java +++ b/src/test/java/hudson/plugins/ansicolor/AnsiColorStepTest.java @@ -4,6 +4,7 @@ import static org.junit.Assert.assertTrue; import java.io.StringWriter; +import java.util.logging.Level; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; @@ -13,6 +14,7 @@ import org.junit.Test; import org.junit.runners.model.Statement; import org.jvnet.hudson.test.BuildWatcher; +import org.jvnet.hudson.test.LoggerRule; import org.jvnet.hudson.test.RestartableJenkinsRule; public class AnsiColorStepTest { @@ -36,6 +38,8 @@ public void testGetColorMapNameVga() { public static BuildWatcher buildWatcher = new BuildWatcher(); @Rule public RestartableJenkinsRule story = new RestartableJenkinsRule(); + @Rule + public LoggerRule logging = new LoggerRule().record(ColorConsoleAnnotator.class, Level.FINER); @Test public void testPipelineStep() throws Exception { @@ -56,7 +60,7 @@ public void evaluate() throws Throwable { String html = writer.toString(); story.j.assertLogContains("TERM=xterm", run); assertTrue("Failed to match color attribute in following HTML log output:\n" + html, - html.matches("(?s).*red.*")); + html.replaceAll(".+?", "").matches("(?s).*red.*")); } }); } diff --git a/src/test/java/hudson/plugins/ansicolor/AnsiHtmlOutputStreamTest.java b/src/test/java/hudson/plugins/ansicolor/AnsiHtmlOutputStreamTest.java index b544e74..cae6af7 100644 --- a/src/test/java/hudson/plugins/ansicolor/AnsiHtmlOutputStreamTest.java +++ b/src/test/java/hudson/plugins/ansicolor/AnsiHtmlOutputStreamTest.java @@ -610,7 +610,7 @@ private void assertThatAnnotateIs(AnsiColorMap colorMap, String ansi, String htm assertThat(annotate(ansi, colorMap), is(html)); } - protected String annotate(String text, AnsiColorMap colorMap) throws IOException { + private String annotate(String text, AnsiColorMap colorMap) throws IOException { final ByteArrayOutputStream bos = new ByteArrayOutputStream(); AnsiHtmlOutputStream ansi = new AnsiHtmlOutputStream(bos, colorMap, new AnsiAttributeElement.Emitter() { public void emitHtml(String html) {