From 52573f170b00a4fcd40543539ebdce0003388d16 Mon Sep 17 00:00:00 2001 From: Ryan Styrczula Date: Mon, 18 Jul 2016 09:58:22 -0400 Subject: [PATCH 1/4] Add SimpleBuildStep extension to Unity3dBuilder (as a consequence, upped Jenkins core version dependency and refactored where required) --- pom.xml | 4 +- .../org/jenkinsci/plugins/unity3d/Helper.java | 41 ++++++++ .../plugins/unity3d/Unity3dBuilder.java | 97 +++++++++++-------- .../plugins/unity3d/Unity3dInstallation.java | 8 +- src/main/resources/index.jelly | 1 + .../unity3d/Unity3dBuilder/config.jelly | 1 + .../plugins/unity3d/Unity3dBuilderTest.java | 16 +++ .../plugins/unity3d/io/PipeTest.java | 4 +- 8 files changed, 122 insertions(+), 50 deletions(-) create mode 100644 src/main/java/org/jenkinsci/plugins/unity3d/Helper.java diff --git a/pom.xml b/pom.xml index 2b9afe19..e5de9e0a 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.jenkins-ci.plugins plugin - 1.436 + 1.642.3 unity3d-plugin @@ -82,7 +82,7 @@ com.google.guava guava - r06 + 19.0 provided diff --git a/src/main/java/org/jenkinsci/plugins/unity3d/Helper.java b/src/main/java/org/jenkinsci/plugins/unity3d/Helper.java new file mode 100644 index 00000000..a69541b8 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/unity3d/Helper.java @@ -0,0 +1,41 @@ +package org.jenkinsci.plugins.unity3d; + +import com.google.common.base.Function; +import com.google.common.collect.Collections2; +import hudson.util.ArgumentListBuilder; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * + * @author rstyrczula + */ +public class Helper { + public static Set toIntegerSet(String csvIntegers) { + Set result = new HashSet(); + if (! csvIntegers.trim().equals("")) { + result.addAll(Collections2.transform(Arrays.asList(csvIntegers.split(",")), new Function() { + public Integer apply(String s) { + return Integer.parseInt(s.trim()); + } + })); + } + return result; + } + + public static String findCommandlineArgument(ArgumentListBuilder args, String arg) { + return findArgFromList(args.toList(), arg); + } + + public static String findArgFromList(List a, String arg) { + String customArg = null; + for (int i = 0; i < a.size() - 1; i++) { + if (a.get(i).equals(arg)) { + customArg = a.get(i+1); + } + } + return customArg; + } +} diff --git a/src/main/java/org/jenkinsci/plugins/unity3d/Unity3dBuilder.java b/src/main/java/org/jenkinsci/plugins/unity3d/Unity3dBuilder.java index 56096089..28ed4e55 100644 --- a/src/main/java/org/jenkinsci/plugins/unity3d/Unity3dBuilder.java +++ b/src/main/java/org/jenkinsci/plugins/unity3d/Unity3dBuilder.java @@ -9,7 +9,6 @@ import hudson.model.BuildListener; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; -import hudson.model.Computer; import hudson.model.Result; import hudson.tasks.BuildStepDescriptor; import hudson.tasks.Builder; @@ -23,7 +22,6 @@ import java.io.PrintStream; import java.util.Arrays; import java.util.List; -import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.Future; @@ -32,10 +30,15 @@ import com.google.common.base.Function; import com.google.common.collect.Collections2; +import hudson.model.Run; +import hudson.model.TaskListener; +import jenkins.tasks.SimpleBuildStep; + import net.sf.json.JSONObject; import org.jenkinsci.plugins.unity3d.io.Pipe; import org.jenkinsci.plugins.unity3d.io.StreamCopyThread; import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; @@ -49,7 +52,7 @@ * * @author Jerome Lacoste */ -public class Unity3dBuilder extends Builder { +public class Unity3dBuilder extends Builder implements SimpleBuildStep { private static final Logger log = Logger.getLogger(Unity3dBuilder.class.getName()); /** @@ -66,7 +69,7 @@ public class Unity3dBuilder extends Builder { public Unity3dBuilder(String unity3dName, String argLine, String unstableReturnCodes) { this.unity3dName = unity3dName; this.argLine = argLine; - this.unstableReturnCodes = unstableReturnCodes; + this.unstableReturnCodes = Util.fixNull(unstableReturnCodes); } @SuppressWarnings("unused") @@ -90,8 +93,16 @@ public String getUnstableReturnCodes() { return unstableReturnCodes; } + /** + * @since 1.4 + */ + @DataBoundSetter + public void setUnstableReturnCodes(String unstableReturnCodes) { + this.unstableReturnCodes = Util.fixNull(unstableReturnCodes); + } + Set toUnstableReturnCodesSet() { - return toIntegerSet(unstableReturnCodes); + return Helper.toIntegerSet(unstableReturnCodes); } private String getArgLineOrGlobalArgLine() { @@ -115,10 +126,25 @@ private PerformException(String s) { } } + @Override // SimpleBuildStep.perform + public void perform(Run run, FilePath fp, Launcher lnchr, TaskListener tl) throws InterruptedException { + try + { + _perform(run, fp, lnchr, tl); + } + catch (PerformException e) { + tl.fatalError(e.getMessage()); + } catch (IOException e) { + Util.displayIOException(e, tl); + String errorMessage = Messages.Unity3d_ExecUnexpectedlyFailed(); + e.printStackTrace(tl.fatalError(errorMessage)); + } + } + @Override public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException { try { - _perform(build, launcher, listener); + _perform(build, build.getWorkspace(), launcher, listener); return true; } catch (PerformException e) { listener.fatalError(e.getMessage()); @@ -131,12 +157,12 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListene } } - private void _perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException, PerformException { + private void _perform(Run build, FilePath workspace, Launcher launcher, TaskListener listener) throws IOException, InterruptedException, PerformException { EnvVars env = build.getEnvironment(listener); - - Unity3dInstallation ui = getAndConfigureUnity3dInstallation(listener, env); - ArgumentListBuilder args = prepareCommandlineArguments(build, launcher, ui, env); + Unity3dInstallation ui = getAndConfigureUnity3dInstallation(listener, env, workspace); + + ArgumentListBuilder args = prepareCommandlineArguments(build, workspace, launcher, ui, env); String customLogFile = findLogFileArgument(args); @@ -150,7 +176,7 @@ private void _perform(AbstractBuild build, Launcher launcher, BuildListener StreamCopyThread copierThread = new StreamCopyThread("Pipe editor.log to output thread.", pipe.getIn(), ca); try { copierThread.start(); - int r = launcher.launch().cmds(args).envs(env).stdout(ca).pwd(build.getWorkspace()).join(); + int r = launcher.launch().cmds(args).envs(env).stdout(ca).pwd(workspace).join(); // r == 11 means executeMethod could not be found ? checkProcResult(build, r); } finally { @@ -178,7 +204,7 @@ private void _perform(AbstractBuild build, Launcher launcher, BuildListener } } - private void checkProcResult(AbstractBuild build, int result) throws PerformException { + private void checkProcResult(Run build, int result) throws PerformException { log.info("Unity command line exited with error code: " + result); if (isBuildUnstable(result)) { log.info(Messages.Unity3d_BuildMarkedAsUnstableBecauseOfStatus(result)); @@ -200,39 +226,38 @@ private boolean isBuildSuccess(int result) { /** Find the -logFile argument from the built arg line **/ private String findLogFileArgument(ArgumentListBuilder args) { - String customLogFile = null; - List a = args.toList(); - for (int i = 0; i < a.size() - 1; i++) { - if (a.get(i).equals("-logFile")) { - customLogFile = a.get(i+1); - } - } - return customLogFile; + return Helper.findCommandlineArgument(args, "-logFile"); } - private ArgumentListBuilder prepareCommandlineArguments(AbstractBuild build, Launcher launcher, Unity3dInstallation ui, EnvVars vars) throws IOException, InterruptedException, PerformException { + private ArgumentListBuilder prepareCommandlineArguments(Run build, FilePath workspace, Launcher launcher, Unity3dInstallation ui, EnvVars vars) throws IOException, InterruptedException, PerformException { String exe; try { exe = ui.getExecutable(launcher); } catch (RuntimeException re) { throw new PerformException(re.getMessage()); } + + if(build instanceof AbstractBuild) { + AbstractBuild abstractBuild = (AbstractBuild)build; + FilePath moduleRoot = abstractBuild.getModuleRoot(); + String moduleRootRemote = moduleRoot.getRemote(); + Map buildParameters = abstractBuild.getBuildVariables(); - FilePath moduleRoot = build.getModuleRoot(); - String moduleRootRemote = moduleRoot.getRemote(); - Map buildParameters = build.getBuildVariables(); - - return createCommandlineArgs(exe, moduleRootRemote, vars, buildParameters); + return createCommandlineArgs(exe, moduleRootRemote, vars, buildParameters); + } else { + // build variables should be parsed by groovy script + return createCommandlineArgs(exe, workspace.getRemote(), vars, null); + } } - - private Unity3dInstallation getAndConfigureUnity3dInstallation(BuildListener listener, EnvVars env) throws PerformException, IOException, InterruptedException { + + private Unity3dInstallation getAndConfigureUnity3dInstallation(TaskListener listener, EnvVars env, FilePath workspace) throws PerformException, IOException, InterruptedException { Unity3dInstallation ui = getUnity3dInstallation(); if(ui==null) { throw new PerformException(Messages.Unity3d_NoUnity3dInstallation()); } - ui = ui.forNode(Computer.currentComputer().getNode(), listener); + ui = ui.forNode(workspace.toComputer().getNode(), listener); ui = ui.forEnvironment(env); return ui; } @@ -267,18 +292,6 @@ private Unity3dInstallation getUnity3dInstallation() { return null; } - static Set toIntegerSet(String csvIntegers) { - Set result = new HashSet(); - if (! csvIntegers.trim().equals("")) { - result.addAll(Collections2.transform(Arrays.asList(csvIntegers.split(",")), new Function() { - public Integer apply(String s) { - return Integer.parseInt(s.trim()); - } - })); - } - return result; - } - @Override public DescriptorImpl getDescriptor() { return (DescriptorImpl) super.getDescriptor(); @@ -310,7 +323,7 @@ public void setInstallations(Unity3dInstallation... antInstallations) { public FormValidation doCheckUnstableReturnCodes(@QueryParameter String value) { try { - toIntegerSet(value); + Helper.toIntegerSet(value); return FormValidation.ok(); } catch (RuntimeException re) { return FormValidation.error(Messages.Unity3d_InvalidParamUnstableReturnCodes(value)); diff --git a/src/main/java/org/jenkinsci/plugins/unity3d/Unity3dInstallation.java b/src/main/java/org/jenkinsci/plugins/unity3d/Unity3dInstallation.java index 5c082832..946ba51f 100644 --- a/src/main/java/org/jenkinsci/plugins/unity3d/Unity3dInstallation.java +++ b/src/main/java/org/jenkinsci/plugins/unity3d/Unity3dInstallation.java @@ -9,7 +9,7 @@ import hudson.model.Hudson; import hudson.model.Node; import hudson.model.TaskListener; -import hudson.remoting.Callable; +import jenkins.security.MasterToSlaveCallable; import hudson.slaves.NodeSpecific; import hudson.tools.ToolDescriptor; import hudson.tools.ToolInstallation; @@ -60,7 +60,7 @@ public Unity3dInstallation forNode(Node node, TaskListener log) throws IOExcepti * Gets the executable path of this Unity3dBuilder on the given target system. */ public String getExecutable(Launcher launcher) throws IOException, InterruptedException { - return launcher.getChannel().call(new Callable() { + return launcher.getChannel().call(new MasterToSlaveCallable() { public String call() throws IOException { return checkUnity3dExecutablePath(getHome()); } @@ -129,7 +129,7 @@ private static String checkUnity3dExecutablePath(String home) { * @throws IOException */ public Future pipeEditorLog(final Launcher launcher, final String customLogFile, final OutputStream ros) throws IOException { - return launcher.getChannel().callAsync(new Callable() { + return launcher.getChannel().callAsync(new MasterToSlaveCallable() { public Long call() throws IOException { return new PipeFileAfterModificationAction(getEditorLogFile(customLogFile).getAbsolutePath(), ros, true).call(); } @@ -144,7 +144,7 @@ public Long call() throws IOException { * @throws InterruptedException */ public String getEditorLogPath(final Launcher launcher, final String customLogFile) throws IOException, InterruptedException { - return launcher.getChannel().call(new Callable() { + return launcher.getChannel().call(new MasterToSlaveCallable() { public String call() throws IOException { return getEditorLogFile(customLogFile).getAbsolutePath(); } diff --git a/src/main/resources/index.jelly b/src/main/resources/index.jelly index 6975729b..2fe0e1b2 100644 --- a/src/main/resources/index.jelly +++ b/src/main/resources/index.jelly @@ -1,3 +1,4 @@ + diff --git a/src/main/resources/org/jenkinsci/plugins/unity3d/Unity3dBuilder/config.jelly b/src/main/resources/org/jenkinsci/plugins/unity3d/Unity3dBuilder/config.jelly index 802dd5af..428107e3 100644 --- a/src/main/resources/org/jenkinsci/plugins/unity3d/Unity3dBuilder/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/unity3d/Unity3dBuilder/config.jelly @@ -1,3 +1,4 @@ + ${inst.name} - + diff --git a/src/main/resources/org/jenkinsci/plugins/unity3d/workflow/Unity3dBuilderStep/config.jelly b/src/main/resources/org/jenkinsci/plugins/unity3d/workflow/Unity3dBuilderStep/config.jelly new file mode 100644 index 00000000..d31b089c --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/unity3d/workflow/Unity3dBuilderStep/config.jelly @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/unity3d/workflow/Unity3dBuilderStep/help.html b/src/main/resources/org/jenkinsci/plugins/unity3d/workflow/Unity3dBuilderStep/help.html new file mode 100644 index 00000000..f900ad2e --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/unity3d/workflow/Unity3dBuilderStep/help.html @@ -0,0 +1,4 @@ +

For projects that use Unity3d as the build system.
+ This causes Jenkins to invoke the Unity3d Editor with the given command line arguments.
+ A non-zero exit code from Unity3d makes Jenkins mark the build as a failure. +

\ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/unity3d/Unity3dBuilder/help-argLine.html b/src/main/webapp/help-argLine.html similarity index 100% rename from src/main/resources/org/jenkinsci/plugins/unity3d/Unity3dBuilder/help-argLine.html rename to src/main/webapp/help-argLine.html diff --git a/src/main/resources/org/jenkinsci/plugins/unity3d/Unity3dBuilder/help-name.html b/src/main/webapp/help-name.html similarity index 100% rename from src/main/resources/org/jenkinsci/plugins/unity3d/Unity3dBuilder/help-name.html rename to src/main/webapp/help-name.html From 3f8fa263a3eafe1d7c768a68b47f2da9201a9885 Mon Sep 17 00:00:00 2001 From: Ryan Styrczula Date: Wed, 31 Aug 2016 10:22:04 -0400 Subject: [PATCH 4/4] implement getRequiredMonitorService for concurrency throw AbortException in SimpleBuildStep perform to notify failed builds --- .../plugins/unity3d/Unity3dBuilder.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/unity3d/Unity3dBuilder.java b/src/main/java/org/jenkinsci/plugins/unity3d/Unity3dBuilder.java index 28ed4e55..096bc6a4 100644 --- a/src/main/java/org/jenkinsci/plugins/unity3d/Unity3dBuilder.java +++ b/src/main/java/org/jenkinsci/plugins/unity3d/Unity3dBuilder.java @@ -1,5 +1,6 @@ package org.jenkinsci.plugins.unity3d; +import hudson.AbortException; import hudson.CopyOnWrite; import hudson.EnvVars; import hudson.Extension; @@ -20,18 +21,14 @@ import java.io.IOException; import java.io.ObjectStreamException; import java.io.PrintStream; -import java.util.Arrays; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Future; import java.util.logging.Logger; -import com.google.common.base.Function; -import com.google.common.collect.Collections2; - import hudson.model.Run; import hudson.model.TaskListener; +import hudson.tasks.BuildStepMonitor; import jenkins.tasks.SimpleBuildStep; import net.sf.json.JSONObject; @@ -125,15 +122,21 @@ private PerformException(String s) { super(s); } } - + + @Override + public BuildStepMonitor getRequiredMonitorService() { + return BuildStepMonitor.NONE; + } + @Override // SimpleBuildStep.perform - public void perform(Run run, FilePath fp, Launcher lnchr, TaskListener tl) throws InterruptedException { + public void perform(Run run, FilePath fp, Launcher lnchr, TaskListener tl) throws InterruptedException, AbortException { try { _perform(run, fp, lnchr, tl); } catch (PerformException e) { tl.fatalError(e.getMessage()); + throw new AbortException(e.getMessage()); } catch (IOException e) { Util.displayIOException(e, tl); String errorMessage = Messages.Unity3d_ExecUnexpectedlyFailed();