diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml new file mode 100644 index 0000000..94863e6 --- /dev/null +++ b/.mvn/extensions.xml @@ -0,0 +1,7 @@ + + + io.jenkins.tools.incrementals + git-changelist-maven-extension + 1.0-beta-7 + + diff --git a/.mvn/maven.config b/.mvn/maven.config new file mode 100644 index 0000000..2a0299c --- /dev/null +++ b/.mvn/maven.config @@ -0,0 +1,2 @@ +-Pconsume-incrementals +-Pmight-produce-incrementals diff --git a/pom.xml b/pom.xml index 0754490..bd3f945 100644 --- a/pom.xml +++ b/pom.xml @@ -3,12 +3,12 @@ org.jenkins-ci.plugins plugin - 2.31 + 3.25 ant - 1.9-SNAPSHOT + ${revision}${changelist} hpi Ant Plugin Adds Apache Ant support to Jenkins @@ -24,18 +24,21 @@ scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git - HEAD + ${scmTag} - 1.651.3 + 1.9 + -SNAPSHOT + 2.121.2 + 8 org.jenkins-ci.plugins structs - 1.6 + 1.17 org.jenkins-ci.main @@ -52,13 +55,13 @@ org.jenkins-ci.plugins.workflow workflow-cps - 2.32 + 2.58 test org.jenkins-ci.plugins.workflow workflow-job - 2.9 + 2.26 test @@ -70,7 +73,13 @@ org.jenkins-ci.plugins.workflow workflow-durable-task-step - 2.5 + 2.26-rc791.37915aaf7f4d + test + + + org.jenkins-ci.plugins + durable-task + 1.27-rc374.ea1d4ad27dd9 test diff --git a/src/main/java/hudson/tasks/Ant.java b/src/main/java/hudson/tasks/Ant.java index 3ab7d3b..375d481 100644 --- a/src/main/java/hudson/tasks/Ant.java +++ b/src/main/java/hudson/tasks/Ant.java @@ -58,6 +58,7 @@ import org.kohsuke.stapler.QueryParameter; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import hudson.remoting.VirtualChannel; import java.io.File; import java.io.IOException; @@ -395,22 +396,27 @@ public void buildEnvVars(EnvVars env) { * Gets the executable path of this Ant on the given target system. */ public String getExecutable(Launcher launcher) throws IOException, InterruptedException { - return launcher.getChannel().call(new MasterToSlaveCallable() { - private static final long serialVersionUID = 906341330603832653L; - public String call() throws IOException { - File exe = getExeFile(); - if(exe.exists()) - return exe.getPath(); - return null; - } - }); + VirtualChannel channel = launcher.getChannel(); + if (channel == null) { + throw new IOException("offline?"); + } + return channel.call(new GetExecutable(getHome())); } - - private File getExeFile() { - String execName = Functions.isWindows() ? "ant.bat" : "ant"; - String home = Util.replaceMacro(getHome(), EnvVars.masterEnvVars); - - return new File(home,"bin/"+execName); + private static class GetExecutable extends MasterToSlaveCallable { + private static final long serialVersionUID = 906341330603832653L; + private final String rawHome; + GetExecutable(String rawHome) { + this.rawHome = rawHome; + } + @Override public String call() throws IOException { + String execName = Functions.isWindows() ? "ant.bat" : "ant"; + String home = Util.replaceMacro(rawHome, EnvVars.masterEnvVars); + File exe = new File(home, "bin/" + execName); + if (exe.exists()) { + return exe.getPath(); + } + return null; + } } /** diff --git a/src/main/java/hudson/tasks/_ant/AntConsoleAnnotator.java b/src/main/java/hudson/tasks/_ant/AntConsoleAnnotator.java index 996ca4a..a0383dc 100644 --- a/src/main/java/hudson/tasks/_ant/AntConsoleAnnotator.java +++ b/src/main/java/hudson/tasks/_ant/AntConsoleAnnotator.java @@ -27,12 +27,14 @@ import hudson.console.ConsoleLogFilter; import hudson.console.LineTransformationOutputStream; import hudson.model.Run; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.charset.Charset; +import jenkins.util.JenkinsJVM; /** * Filter {@link OutputStream} that places an annotation that marks Ant target execution. @@ -43,12 +45,32 @@ public class AntConsoleAnnotator extends LineTransformationOutputStream { private final OutputStream out; private final Charset charset; + /** Serialized, signed, and Base64-encoded forms of {@link AntTargetNote} and {@link AntOutcomeNote} respectively. */ + private final byte[][] antNotes; private boolean seenEmptyLine; public AntConsoleAnnotator(OutputStream out, Charset charset) { + this(out, charset, createAntNotes()); + } + + private AntConsoleAnnotator(OutputStream out, Charset charset, byte[][] antNotes) { this.out = out; this.charset = charset; + this.antNotes = antNotes; + } + + private static byte[][] createAntNotes() { + JenkinsJVM.checkJenkinsJVM(); + try { + ByteArrayOutputStream targetNote = new ByteArrayOutputStream(); + new AntTargetNote().encodeTo(targetNote); + ByteArrayOutputStream outcomeNote = new ByteArrayOutputStream(); + new AntOutcomeNote().encodeTo(outcomeNote); + return new byte[][] {targetNote.toByteArray(), outcomeNote.toByteArray()}; + } catch (IOException x) { // should be impossible + throw new RuntimeException(x); + } } @Override @@ -60,10 +82,10 @@ protected void eol(byte[] b, int len) throws IOException { if (seenEmptyLine && endsWith(line,':') && line.indexOf(' ')<0) // put the annotation - new AntTargetNote().encodeTo(out); + out.write(antNotes[0]); if (line.equals("BUILD SUCCESSFUL") || line.equals("BUILD FAILED")) - new AntOutcomeNote().encodeTo(out); + out.write(antNotes[1]); seenEmptyLine = line.length()==0; out.write(b,0,len); @@ -74,6 +96,11 @@ private boolean endsWith(String line, char c) { return len>0 && line.charAt(len-1)==c; } + @Override + public void flush() throws IOException { + out.flush(); + } + @Override public void close() throws IOException { super.close(); @@ -85,8 +112,15 @@ public static ConsoleLogFilter asConsoleLogFilter() { } private static class ConsoleLogFilterImpl extends ConsoleLogFilter implements Serializable { private static final long serialVersionUID = 1; + private byte[][] antNotes = createAntNotes(); + private Object readResolve() { + if (antNotes == null) { // old program.dat + antNotes = createAntNotes(); + } + return this; + } @Override public OutputStream decorateLogger(Run build, OutputStream logger) throws IOException, InterruptedException { - return new AntConsoleAnnotator(logger, Charsets.UTF_8); + return new AntConsoleAnnotator(logger, Charsets.UTF_8, antNotes); } } diff --git a/src/test/java/hudson/tasks/AntWrapperTest.java b/src/test/java/hudson/tasks/AntWrapperTest.java index 234c621..684121f 100644 --- a/src/test/java/hudson/tasks/AntWrapperTest.java +++ b/src/test/java/hudson/tasks/AntWrapperTest.java @@ -26,7 +26,10 @@ import com.gargoylesoftware.htmlunit.html.DomElement; import com.gargoylesoftware.htmlunit.html.HtmlPage; +import hudson.console.ConsoleNote; import hudson.model.FreeStyleProject; +import hudson.slaves.DumbSlave; +import java.util.logging.Level; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; @@ -38,6 +41,7 @@ import org.junit.runners.model.Statement; import org.jvnet.hudson.test.BuildWatcher; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.LoggerRule; import org.jvnet.hudson.test.RestartableJenkinsRule; import org.jvnet.hudson.test.ToolInstallations; @@ -46,6 +50,7 @@ public class AntWrapperTest { @ClassRule public static BuildWatcher buildWatcher = new BuildWatcher(); @Rule public RestartableJenkinsRule r = new RestartableJenkinsRule(); @Rule public TemporaryFolder tmp = new TemporaryFolder(); + @Rule public LoggerRule logging = new LoggerRule(); @Test public void configRoundTrip() throws Exception { r.addStep(new Statement() { @@ -70,12 +75,13 @@ public class AntWrapperTest { r.addStep(new Statement() { @Override public void evaluate() throws Throwable { ToolInstallations.configureDefaultAnt(tmp); // TODO could instead use DockerRule to run against a specified JDK location + DumbSlave s = r.j.createOnlineSlave(); + logging.recordPackage(ConsoleNote.class, Level.FINE); WorkflowJob p = r.j.createProject(WorkflowJob.class, "p"); - r.j.jenkins.getWorkspaceFor(p).child("build.xml").copyFrom(AntWrapperTest.class.getResource("_ant/simple-build.xml")); - p.setDefinition(new CpsFlowDefinition("node {withAnt(installation: 'default') {if (isUnix()) {sh 'ant foo'} else {bat 'ant foo'}}}", true)); + s.getWorkspaceFor(p).child("build.xml").copyFrom(AntWrapperTest.class.getResource("_ant/simple-build.xml")); + p.setDefinition(new CpsFlowDefinition("node('!master') {withAnt(installation: 'default') {if (isUnix()) {sh 'ant foo'} else {bat 'ant foo'}}}", true)); WorkflowRun b = r.j.buildAndAssertSuccess(p); - // TODO passes locally, fails in jenkins.ci: AntConsoleAnnotator processes AntOutcomeNote but not AntTargetNote - // (perhaps because it seems to have set ANT_HOME=/opt/ant/latest? yet the output looks right) + b.getLogText().writeRawLogTo(0, System.err); AntTest.assertHtmlLogContains(b, "foo"); AntTest.assertHtmlLogContains(b, "bar"); JenkinsRule.WebClient wc = r.j.createWebClient();