diff --git a/src/main/java/com/cloudbees/jenkins/plugins/customtools/CustomTool.java b/src/main/java/com/cloudbees/jenkins/plugins/customtools/CustomTool.java index f37b0b6..04636f7 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/customtools/CustomTool.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/customtools/CustomTool.java @@ -44,6 +44,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import javax.annotation.CheckForNull; import org.kohsuke.stapler.DataBoundConstructor; @@ -62,7 +63,7 @@ public class CustomTool extends ToolInstallation implements private final String exportedPaths; private final LabelSpecifics[] labelSpecifics; private static final LabelSpecifics[] EMPTY_LABELS = new LabelSpecifics[0]; - private transient String correctedHome; + private transient String correctedHome = null; private final ToolVersionConfig toolVersion; private final String additionalVariables; @@ -101,7 +102,10 @@ public LabelSpecifics[] getLabelSpecifics() { return (labelSpecifics!=null) ? labelSpecifics : EMPTY_LABELS; } - /**Check if the tool has additional variables set*/ + /** + * Check if the tool has additional environment variables set. + * @return true when the tool injects additional environment variables. + */ public boolean hasAdditionalVariables() { return additionalVariables != null; } @@ -180,6 +184,12 @@ public void setInstallations(CustomTool... installations) { save(); } + /** + * Gets a {@link CustomTool} by its name. + * @param name A name of the tool to be retrieved. + * @return A {@link CustomTool} or null if it has no found + */ + @CheckForNull public CustomTool byName(String name) { for (CustomTool tool : getInstallations()) { if (tool.getName().equals(name)) { diff --git a/src/main/java/com/cloudbees/jenkins/plugins/customtools/CustomToolInstallWrapper.java b/src/main/java/com/cloudbees/jenkins/plugins/customtools/CustomToolInstallWrapper.java index 4031351..f93d5e9 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/customtools/CustomToolInstallWrapper.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/customtools/CustomToolInstallWrapper.java @@ -28,7 +28,6 @@ import hudson.Extension; import hudson.Launcher; import hudson.Proc; -import hudson.Util; import hudson.matrix.MatrixBuild; import hudson.model.BuildListener; import hudson.model.AbstractBuild; @@ -42,10 +41,11 @@ import hudson.tasks.BuildWrapperDescriptor; import java.io.IOException; -import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Map; +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; import net.sf.json.JSONObject; @@ -68,24 +68,41 @@ public class CustomToolInstallWrapper extends BuildWrapper { * */ public static class SelectedTool { - private String name; + private final String name; @DataBoundConstructor public SelectedTool(String name) { this.name = name; } + public String getName() { return name; } + + @Override + public String toString() { + return name; + } + @CheckForNull public CustomTool toCustomTool() { return ((CustomTool.DescriptorImpl)Hudson.getInstance().getDescriptor(CustomTool.class)).byName(name); } + + @Nonnull + public CustomTool toCustomToolValidated() throws CustomToolException { + CustomTool tool = toCustomTool(); + if (tool == null) { + throw new CustomToolException( + Messages.CustomTool_GetToolByName_ErrorMessage(name)); + } + return tool; + } } private SelectedTool[] selectedTools = new SelectedTool[0]; - private MulticonfigWrapperOptions multiconfigOptions; - private boolean convertHomesToUppercase; + private final MulticonfigWrapperOptions multiconfigOptions; + private final boolean convertHomesToUppercase; @DataBoundConstructor public CustomToolInstallWrapper(SelectedTool[] selectedTools, MulticonfigWrapperOptions multiconfigOptions, boolean convertHomesToUppercase) { @@ -93,7 +110,7 @@ public CustomToolInstallWrapper(SelectedTool[] selectedTools, MulticonfigWrapper this.multiconfigOptions = (multiconfigOptions != null) ? multiconfigOptions : MulticonfigWrapperOptions.DEFAULT; this.convertHomesToUppercase = convertHomesToUppercase; } - + public boolean isConvertHomesToUppercase() { return convertHomesToUppercase; } @@ -104,13 +121,15 @@ public Environment setUp(AbstractBuild build, Launcher launcher, final EnvVars buildEnv = build.getEnvironment(listener); final Node node = build.getBuiltOn(); - - return new Environment(){ + + return new Environment() { @Override - public void buildEnvVars(Map env) { + public void buildEnvVars(Map env) { + // TODO: Inject Home dirs as well - for (CustomTool tool : customTools()) { - if (tool.hasVersions()) { + for (SelectedTool selectedTool : selectedTools) { + CustomTool tool = selectedTool.toCustomTool(); + if (tool != null && tool.hasVersions()) { ToolVersion version = ToolVersion.getEffectiveToolVersion(tool, buildEnv, node); if (version != null && !env.containsKey(version.getVariableName())) { env.put(version.getVariableName(), version.getDefaultVersion()); @@ -125,22 +144,16 @@ public SelectedTool[] getSelectedTools() { return selectedTools.clone(); } - private List customTools() { - List tools = new ArrayList(); - for (SelectedTool selected : selectedTools) { - tools.add(selected.toCustomTool()); - } - return tools; - } - /** * The heart of the beast. Installs selected tools and exports their paths to the * PATH and their HOMEs as environment variables. + * @return A decorated launcher */ @Override public Launcher decorateLauncher(AbstractBuild build, final Launcher launcher, BuildListener listener) throws IOException, InterruptedException, - RunnerAbortedException { + RunnerAbortedException { + EnvVars buildEnv = build.getEnvironment(listener); final EnvVars homes = new EnvVars(); final EnvVars versions = new EnvVars(); @@ -149,8 +162,8 @@ public Launcher decorateLauncher(AbstractBuild build, final Launcher launcher, final List additionalVarInjectors = new LinkedList(); // Handle multi-configuration build - if (MatrixBuild.class.isAssignableFrom(build.getClass())) { - CustomToolsLogger.LogMessage(listener, "Skipping installation of tools at the master job"); + if (build instanceof MatrixBuild) { + CustomToolsLogger.logMessage(listener, "Skipping installation of tools at the master job"); if (multiconfigOptions.isSkipMasterInstallation()) { return launcher; } @@ -158,11 +171,12 @@ public Launcher decorateLauncher(AbstractBuild build, final Launcher launcher, // Each tool can export zero or many directories to the PATH Node node = Computer.currentComputer().getNode(); - for (CustomTool tool : customTools()) { - CustomToolsLogger.LogMessage(listener, tool.getName(), "Starting installation"); + for (SelectedTool selectedToolName : selectedTools) { + CustomTool tool = selectedToolName.toCustomToolValidated(); + CustomToolsLogger.logMessage(listener, tool.getName(), "Starting installation"); // Check versioning - CheckVersions(tool, listener, buildEnv, node, versions); + checkVersions(tool, listener, buildEnv, node, versions); // This installs the tool if necessary CustomTool installed = tool @@ -191,16 +205,16 @@ public Launcher decorateLauncher(AbstractBuild build, final Launcher launcher, if (!spec.appliesTo(node)) { continue; } - CustomToolsLogger.LogMessage(listener, installed.getName(), "Label specifics from '"+spec.getLabel()+"' will be applied"); + CustomToolsLogger.logMessage(listener, installed.getName(), "Label specifics from '"+spec.getLabel()+"' will be applied"); if (spec.hasAdditionalVars()) { additionalVarInjectors.add(EnvVariablesInjector.Create(spec.getAdditionalVars())); } } - CustomToolsLogger.LogMessage(listener, installed.getName(), "Tool is installed at "+ installed.getHome()); + CustomToolsLogger.logMessage(listener, installed.getName(), "Tool is installed at "+ installed.getHome()); String homeDirVarName = (convertHomesToUppercase ? installed.getName().toUpperCase() : installed.getName()) +"_HOME"; - CustomToolsLogger.LogMessage(listener, installed.getName(), "Setting "+ homeDirVarName+"="+installed.getHome()); + CustomToolsLogger.logMessage(listener, installed.getName(), "Setting "+ homeDirVarName+"="+installed.getHome()); homes.put(homeDirVarName, installed.getHome()); } @@ -248,7 +262,15 @@ private EnvVars toEnvVars(String[] envs) { } /** - * Check versions and modify build environment if required. + * @deprecated The method is deprecated. It will be removed in future versions. + */ + public void CheckVersions (CustomTool tool, BuildListener listener, EnvVars buildEnv, Node node, EnvVars target) + throws CustomToolException { + checkVersions(tool, listener, buildEnv, node, target); + } + + /** + * Checks versions and modify build environment if required. * @param tool Custom Tool * @param listener Build Listener * @param buildEnv Build Environment (can be modified) @@ -257,16 +279,16 @@ private EnvVars toEnvVars(String[] envs) { * @throws CustomToolException * @since 0.4 */ - public void CheckVersions (CustomTool tool, BuildListener listener, EnvVars buildEnv, Node node, EnvVars target) throws CustomToolException { + public void checkVersions (CustomTool tool, BuildListener listener, EnvVars buildEnv, Node node, EnvVars target) throws CustomToolException { // Check version if (tool.hasVersions()) { ToolVersion version = ToolVersion.getEffectiveToolVersion(tool, buildEnv, node); if (version == null) { - CustomToolsLogger.LogMessage(listener, tool.getName(), "Error: No version has been specified, no default version. Failing the build..."); + CustomToolsLogger.logMessage(listener, tool.getName(), "Error: No version has been specified, no default version. Failing the build..."); throw new CustomToolException("Version has not been specified for the "+tool.getName()); } - CustomToolsLogger.LogMessage(listener, tool.getName(), "Version "+version.getActualVersion()+" has been specified by "+version.getVersionSource()); + CustomToolsLogger.logMessage(listener, tool.getName(), "Version "+version.getActualVersion()+" has been specified by "+version.getVersionSource()); // Override default versions if (version.getVersionSource().equals(ToolVersion.DEFAULTS_SOURCE)) { diff --git a/src/main/java/com/synopsys/arc/jenkinsci/plugins/customtools/CustomToolsLogger.java b/src/main/java/com/synopsys/arc/jenkinsci/plugins/customtools/CustomToolsLogger.java index 2ccac67..e382c1e 100644 --- a/src/main/java/com/synopsys/arc/jenkinsci/plugins/customtools/CustomToolsLogger.java +++ b/src/main/java/com/synopsys/arc/jenkinsci/plugins/customtools/CustomToolsLogger.java @@ -18,18 +18,34 @@ import hudson.model.BuildListener; /** - * + * Provides logging routines for the plugin. * @author Oleg Nenashev , Synopsys Inc. * @since 0.3 */ public class CustomToolsLogger { public static final String LOG_PREFIX = "[CustomTools] - "; + /** + * @deprecated Use {@link #logMessage(hudson.model.BuildListener, java.lang.String)} + * instead. + */ public static void LogMessage(BuildListener listener, String message) { - listener.getLogger().println(CustomToolsLogger.LOG_PREFIX+message); + logMessage(listener, message); } + /** + * @deprecated Use {@link #logMessage(hudson.model.BuildListener, java.lang.String, java.lang.String)} + * instead. + */ public static void LogMessage(BuildListener listener, String toolName, String message) { + logMessage(listener, toolName, message); + } + + public static void logMessage(BuildListener listener, String message) { + listener.getLogger().println(CustomToolsLogger.LOG_PREFIX+message); + } + + public static void logMessage(BuildListener listener, String toolName, String message) { listener.getLogger().println(CustomToolsLogger.LOG_PREFIX+toolName+": "+message); } } diff --git a/src/main/java/com/synopsys/arc/jenkinsci/plugins/customtools/EnvVariablesInjector.java b/src/main/java/com/synopsys/arc/jenkinsci/plugins/customtools/EnvVariablesInjector.java index d5608ea..7fed038 100644 --- a/src/main/java/com/synopsys/arc/jenkinsci/plugins/customtools/EnvVariablesInjector.java +++ b/src/main/java/com/synopsys/arc/jenkinsci/plugins/customtools/EnvVariablesInjector.java @@ -33,7 +33,21 @@ public class EnvVariablesInjector extends TreeMap entry: entrySet()) { entry.getValue().Inject(target); } @@ -94,17 +116,25 @@ public Entity(String envName, String envValue, String listDelimiter, { this.envName = envName; this.envValue = envValue; - this.listDelimiter = listDelimiter; - this.isList = isList; - this.isOverrides = isOverrides; + // this.listDelimiter = listDelimiter; + // this.isList = isList; + // this.isOverrides = isOverrides; } + /** + * @deprecated Use {@link #injectVariables(hudson.EnvVars)} instead. + * This method will be removed in future versions. + */ + public void Inject(EnvVars target) throws IOException { + injectVariables(target); + } + /** * Inject variables into EnvVars * @param target Target environment * @throws IOException Exception during modification of EnvVars */ - public void Inject(EnvVars target) throws IOException { + public void injectVariables(EnvVars target) throws IOException { //TODO: check overrides //TODO: check lists //TODO: substitute, check, etc. @@ -115,7 +145,5 @@ public void Inject(EnvVars target) throws IOException { target.put(envName, newEnvValue); } - } - - + } } diff --git a/src/main/java/com/synopsys/arc/jenkinsci/plugins/customtools/LabelSpecifics.java b/src/main/java/com/synopsys/arc/jenkinsci/plugins/customtools/LabelSpecifics.java index b18790c..81b12ae 100644 --- a/src/main/java/com/synopsys/arc/jenkinsci/plugins/customtools/LabelSpecifics.java +++ b/src/main/java/com/synopsys/arc/jenkinsci/plugins/customtools/LabelSpecifics.java @@ -19,7 +19,6 @@ import hudson.Extension; import hudson.Util; import hudson.model.AbstractDescribableImpl; -import hudson.model.Describable; import hudson.model.Descriptor; import hudson.model.Label; import hudson.model.Node; @@ -33,9 +32,10 @@ * @since 0.3 */ public class LabelSpecifics extends AbstractDescribableImpl implements Serializable { - private String label; - private String additionalVars; - private String exportedPaths; + + private final String label; + private final String additionalVars; + private final String exportedPaths; @DataBoundConstructor public LabelSpecifics(String label, String additionalVars, String exportedPaths) { diff --git a/src/main/java/com/synopsys/arc/jenkinsci/plugins/customtools/PathsList.java b/src/main/java/com/synopsys/arc/jenkinsci/plugins/customtools/PathsList.java index 937345f..027ce24 100644 --- a/src/main/java/com/synopsys/arc/jenkinsci/plugins/customtools/PathsList.java +++ b/src/main/java/com/synopsys/arc/jenkinsci/plugins/customtools/PathsList.java @@ -38,6 +38,7 @@ public class PathsList implements Serializable { /** * Constructor. Sets system's default separator and pathSeparator * @param paths List of paths to be returned + * @param homeDir Home directory of the tool */ public PathsList(Collection paths, String homeDir) { this(paths, File.pathSeparator, File.separator, homeDir); @@ -87,7 +88,7 @@ public boolean add(PathsList pathsList) { } /** - * Gets the list of installed tools + * Gets the list of installed tools. * @return A list with valid delimiters or null if paths is empty */ public String toListString() { diff --git a/src/main/java/com/synopsys/arc/jenkinsci/plugins/customtools/versions/ToolVersionConfig.java b/src/main/java/com/synopsys/arc/jenkinsci/plugins/customtools/versions/ToolVersionConfig.java index d8c3687..b58b1da 100644 --- a/src/main/java/com/synopsys/arc/jenkinsci/plugins/customtools/versions/ToolVersionConfig.java +++ b/src/main/java/com/synopsys/arc/jenkinsci/plugins/customtools/versions/ToolVersionConfig.java @@ -32,7 +32,7 @@ public class ToolVersionConfig extends AbstractDescribableImpl, Synopsys Inc. */ public class CustomToolInstallWrapperTest extends HudsonTestCase { + + private static final String NON_EXISTENT_TOOL = "non-existent"; + /** * Inserts {@link CustomToolInstallWrapper} after {@link StubWrapper}. * @throws Exception @@ -73,7 +78,7 @@ public void testNestedLauncherCalls() throws Exception { nestedWrapperTestImpl(wrappers, false); } - //@Bug(20560) + @Bug(20560) public void testEmptyToolsList() throws Exception { List wrappers = new ArrayList(0); wrappers.add(new CommandCallerInstaller()); @@ -81,6 +86,24 @@ public void testEmptyToolsList() throws Exception { nestedWrapperTestImpl(wrappers, false); } + @Bug(0) + public void testDeletedTool() throws Exception { + FreeStyleProject project = createFreeStyleProject(); + + CustomToolInstallWrapper.SelectedTool[] tools = + new CustomToolInstallWrapper.SelectedTool[] { + new CustomToolInstallWrapper.SelectedTool(NON_EXISTENT_TOOL) + }; + + project.getBuildWrappersList().add( + new CustomToolInstallWrapper(tools, MulticonfigWrapperOptions.DEFAULT, false)); + + Future build = project.scheduleBuild2(0); + assertBuildStatus(Result.FAILURE, build.get()); + assertLogContains( + Messages.CustomTool_GetToolByName_ErrorMessage(NON_EXISTENT_TOOL), build.get()); + } + /** * Implements tests for nested wrappers. * The test checks that environment variables have been set correctly. diff --git a/src/test/java/com/synopsys/arc/jenkins/plugins/customtools/util/StubWrapper.java b/src/test/java/com/synopsys/arc/jenkins/plugins/customtools/util/StubWrapper.java index 8b7ca8b..0c0523d 100644 --- a/src/test/java/com/synopsys/arc/jenkins/plugins/customtools/util/StubWrapper.java +++ b/src/test/java/com/synopsys/arc/jenkins/plugins/customtools/util/StubWrapper.java @@ -28,7 +28,6 @@ import hudson.tasks.BuildWrapperDescriptor; import java.io.IOException; import java.util.Map; -import java.util.TreeMap; /** * A stub wrapper, which injects a test variable into the build environment. @@ -45,7 +44,6 @@ public class StubWrapper extends BuildWrapper { @Override public Launcher decorateLauncher(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException, Run.RunnerAbortedException { - final Map envs = new TreeMap(); return new Launcher.LocalLauncher(listener) { @Override