-
Notifications
You must be signed in to change notification settings - Fork 111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JENKINS-25223: Allow executing scripts in JobProperty.prebuild phase #36
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,390 @@ | ||
package org.jenkinsci.plugins.envinject; | ||
|
||
import hudson.DescriptorExtensionList; | ||
import hudson.Extension; | ||
import hudson.FilePath; | ||
import hudson.model.BuildListener; | ||
import hudson.model.Environment; | ||
import hudson.model.JobProperty; | ||
import hudson.model.JobPropertyDescriptor; | ||
import hudson.model.AbstractBuild; | ||
import hudson.model.Computer; | ||
import hudson.model.Descriptor; | ||
import hudson.model.Job; | ||
import hudson.model.Node; | ||
import hudson.model.Result; | ||
import hudson.model.Run; | ||
|
||
import java.io.PrintWriter; | ||
import java.io.StringWriter; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.HashMap; | ||
import java.util.LinkedHashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
import javax.annotation.CheckForNull; | ||
|
||
import jenkins.model.Jenkins; | ||
import net.sf.json.JSON; | ||
import net.sf.json.JSONException; | ||
import net.sf.json.JSONObject; | ||
|
||
import org.jenkinsci.lib.envinject.EnvInjectException; | ||
import org.jenkinsci.lib.envinject.EnvInjectLogger; | ||
import org.jenkinsci.plugins.envinject.model.EnvInjectJobPropertyContributor; | ||
import org.jenkinsci.plugins.envinject.model.EnvInjectJobPropertyContributorDescriptor; | ||
import org.jenkinsci.plugins.envinject.service.EnvInjectActionSetter; | ||
import org.jenkinsci.plugins.envinject.service.EnvInjectContributorManagement; | ||
import org.jenkinsci.plugins.envinject.service.EnvInjectEnvVars; | ||
import org.jenkinsci.plugins.envinject.service.EnvInjectVariableGetter; | ||
import org.kohsuke.stapler.StaplerRequest; | ||
|
||
/** | ||
* @author Arcadiy Ivanov (arcivanov) | ||
* @author Gregory Boissinot | ||
*/ | ||
public class EnvInjectPrebuildJobProperty<T extends Job<?, ?>> extends JobProperty<T> { | ||
|
||
private EnvInjectJobPropertyInfo info = new EnvInjectJobPropertyInfo(); | ||
private boolean on; | ||
private boolean keepJenkinsSystemVariables; | ||
private boolean keepBuildVariables; | ||
private boolean overrideBuildParameters; | ||
private EnvInjectJobPropertyContributor[] contributors; | ||
|
||
private transient EnvInjectJobPropertyContributor[] contributorsComputed; | ||
|
||
@SuppressWarnings("unused") | ||
public EnvInjectJobPropertyInfo getInfo() { | ||
return info; | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public boolean isOn() { | ||
return on; | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public boolean isKeepJenkinsSystemVariables() { | ||
return keepJenkinsSystemVariables; | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public boolean isKeepBuildVariables() { | ||
return keepBuildVariables; | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public boolean isOverrideBuildParameters() { | ||
return overrideBuildParameters; | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public EnvInjectJobPropertyContributor[] getContributors() { | ||
if (contributorsComputed == null) { | ||
try { | ||
contributorsComputed = computeEnvInjectContributors(); | ||
} catch (org.jenkinsci.lib.envinject.EnvInjectException e) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
e.printStackTrace(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
} | ||
contributors = contributorsComputed; | ||
} | ||
|
||
return Arrays.copyOf(contributors, contributors.length); | ||
} | ||
|
||
private EnvInjectJobPropertyContributor[] computeEnvInjectContributors() throws org.jenkinsci.lib.envinject.EnvInjectException { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
DescriptorExtensionList<EnvInjectJobPropertyContributor, EnvInjectJobPropertyContributorDescriptor> | ||
descriptors = EnvInjectJobPropertyContributor.all(); | ||
|
||
// If the config are loaded with success (this step) and the descriptors size doesn't have change | ||
// we considerate, they are the same, therefore we retrieve instances | ||
if (contributors != null && contributors.length == descriptors.size()) { | ||
return contributors; | ||
} | ||
|
||
EnvInjectContributorManagement envInjectContributorManagement = new EnvInjectContributorManagement(); | ||
EnvInjectJobPropertyContributor[] contributorsInstance = envInjectContributorManagement.getNewContributorsInstance(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
//No jobProperty Contributors ==> new configuration | ||
if (contributors == null || contributors.length == 0) { | ||
return contributorsInstance; | ||
} | ||
|
||
List<EnvInjectJobPropertyContributor> result = new ArrayList<EnvInjectJobPropertyContributor>(); | ||
for (EnvInjectJobPropertyContributor contributor1 : contributorsInstance) { | ||
for (EnvInjectJobPropertyContributor contributor2 : contributors) { | ||
if (contributor1.getDescriptor().getClass() == contributor2.getDescriptor().getClass()) { | ||
result.add(contributor2); | ||
} else { | ||
result.add(contributor1); | ||
} | ||
} | ||
} | ||
return result.toArray(new EnvInjectJobPropertyContributor[result.size()]); | ||
} | ||
|
||
public void setInfo(EnvInjectJobPropertyInfo info) { | ||
this.info = info; | ||
} | ||
|
||
public void setOn(boolean on) { | ||
this.on = on; | ||
} | ||
|
||
public void setKeepJenkinsSystemVariables(boolean keepJenkinsSystemVariables) { | ||
this.keepJenkinsSystemVariables = keepJenkinsSystemVariables; | ||
} | ||
|
||
public void setKeepBuildVariables(boolean keepBuildVariables) { | ||
this.keepBuildVariables = keepBuildVariables; | ||
} | ||
|
||
public void setOverrideBuildParameters(boolean overrideBuildParameters) { | ||
this.overrideBuildParameters = overrideBuildParameters; | ||
} | ||
|
||
public void setContributors(EnvInjectJobPropertyContributor[] jobPropertyContributors) { | ||
this.contributors = jobPropertyContributors; | ||
} | ||
|
||
@Override | ||
public JobProperty<?> reconfigure(StaplerRequest req, JSONObject form) throws Descriptor.FormException { | ||
EnvInjectPrebuildJobProperty property = (EnvInjectPrebuildJobProperty) super.reconfigure(req, form); | ||
if (property != null && property.info != null && !Jenkins.getInstance().hasPermission(Jenkins.RUN_SCRIPTS)) { | ||
// Don't let non RUN_SCRIPT users set arbitrary groovy script | ||
property.info = new EnvInjectJobPropertyInfo(property.info.propertiesFilePath, property.info.propertiesContent, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
property.info.getScriptFilePath(), property.info.getScriptContent(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
this.info != null ? this.info.getGroovyScriptContent() : "", | ||
property.info.isLoadFilesFromMaster()); | ||
} | ||
return property; | ||
} | ||
|
||
@Extension | ||
@SuppressWarnings("unused") | ||
public static final class DescriptorImpl extends JobPropertyDescriptor { | ||
|
||
@Override | ||
public String getDisplayName() { | ||
return "[Environment Inject (Prebuild)] -" + Messages.envinject_set_displayName(); | ||
} | ||
|
||
@Override | ||
public boolean isApplicable(Class<? extends Job> jobType) { | ||
return true; | ||
} | ||
|
||
@Override | ||
public String getHelpFile() { | ||
return "/plugin/envinject/help.html"; | ||
} | ||
|
||
@Override | ||
public EnvInjectPrebuildJobProperty newInstance(StaplerRequest req, JSONObject formData) throws FormException { | ||
Object onObject = formData.get("on"); | ||
|
||
if (onObject != null) { | ||
EnvInjectPrebuildJobProperty envInjectJobProperty = new EnvInjectPrebuildJobProperty(); | ||
EnvInjectJobPropertyInfo info = req.bindParameters(EnvInjectJobPropertyInfo.class, "envInjectInfoPrebuildJobProperty."); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
envInjectJobProperty.setInfo(info); | ||
envInjectJobProperty.setOn(true); | ||
if (onObject instanceof JSONObject) { | ||
JSONObject onJSONObject = (JSONObject) onObject; | ||
envInjectJobProperty.setKeepJenkinsSystemVariables(onJSONObject.getBoolean("keepJenkinsSystemVariables")); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
envInjectJobProperty.setKeepBuildVariables(onJSONObject.getBoolean("keepBuildVariables")); | ||
envInjectJobProperty.setOverrideBuildParameters(onJSONObject.getBoolean("overrideBuildParameters")); | ||
|
||
//Process contributions | ||
setContributors(req, envInjectJobProperty, onJSONObject); | ||
|
||
return envInjectJobProperty; | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
|
||
private void setContributors(StaplerRequest req, EnvInjectPrebuildJobProperty envInjectJobProperty, JSONObject onJSONObject) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
if (!onJSONObject.containsKey("contributors")) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
envInjectJobProperty.setContributors(new EnvInjectJobPropertyContributor[0]); | ||
} else { | ||
JSON contribJSON; | ||
try { | ||
contribJSON = onJSONObject.getJSONArray("contributors"); | ||
} catch (JSONException jsone) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
contribJSON = onJSONObject.getJSONObject("contributors"); | ||
} | ||
List<EnvInjectJobPropertyContributor> contributions = req.bindJSONToList(EnvInjectJobPropertyContributor.class, contribJSON); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
EnvInjectJobPropertyContributor[] contributionsArray = contributions.toArray(new EnvInjectJobPropertyContributor[contributions.size()]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
envInjectJobProperty.setContributors(contributionsArray); | ||
} | ||
} | ||
|
||
public DescriptorExtensionList<EnvInjectJobPropertyContributor, EnvInjectJobPropertyContributorDescriptor> getEnvInjectContributors() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
return EnvInjectJobPropertyContributor.all(); | ||
} | ||
|
||
public @CheckForNull EnvInjectJobPropertyContributor[] getContributorsInstance() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
EnvInjectContributorManagement envInjectContributorManagement = new EnvInjectContributorManagement(); | ||
try { | ||
return envInjectContributorManagement.getNewContributorsInstance(); | ||
} catch (org.jenkinsci.lib.envinject.EnvInjectException e) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
e.printStackTrace(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
} | ||
return null; | ||
} | ||
|
||
public boolean isEnvInjectContributionActivated() { | ||
EnvInjectContributorManagement envInjectContributorManagement = new EnvInjectContributorManagement(); | ||
return envInjectContributorManagement.isEnvInjectContributionActivated(); | ||
} | ||
|
||
} | ||
|
||
/* | ||
* (non-Javadoc) | ||
* | ||
* @see hudson.model.JobProperty#prebuild(hudson.model.AbstractBuild, | ||
* hudson.model.BuildListener) | ||
*/ | ||
@Override | ||
public boolean prebuild(AbstractBuild<?, ?> build, BuildListener listener) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
if(!isOn()) { | ||
return true; | ||
} | ||
EnvInjectLogger logger = new EnvInjectLogger(listener); | ||
FilePath ws = build.getWorkspace(); | ||
|
||
try { | ||
logger.info("Preparing an environment for the build (prebuild phase)."); | ||
|
||
EnvInjectVariableGetter variableGetter = new EnvInjectVariableGetter(); | ||
EnvInjectJobPropertyInfo info = getInfo(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
assert isOn(); | ||
|
||
// Init infra env vars | ||
Map<String, String> previousEnvVars = variableGetter.getEnvVarsPreviousSteps(build, logger); | ||
Map<String, String> infraEnvVarsNode = new LinkedHashMap<String, String>(previousEnvVars); | ||
Map<String, String> infraEnvVarsMaster = new LinkedHashMap<String, String>(previousEnvVars); | ||
|
||
// Add workspace if not set | ||
if (ws != null) { | ||
if (infraEnvVarsNode.get("WORKSPACE") == null) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
infraEnvVarsNode.put("WORKSPACE", ws.getRemote()); | ||
} | ||
} | ||
|
||
//Add Jenkins System variables | ||
if (isKeepJenkinsSystemVariables()) { | ||
logger.info("Keeping Jenkins system variables."); | ||
infraEnvVarsMaster.putAll(variableGetter.getJenkinsSystemVariables(true)); | ||
infraEnvVarsNode.putAll(variableGetter.getJenkinsSystemVariables(false)); | ||
} | ||
|
||
//Add build variables | ||
if (isKeepBuildVariables()) { | ||
logger.info("Keeping Jenkins build variables."); | ||
Map<String, String> buildVariables = variableGetter.getBuildVariables(build, logger); | ||
infraEnvVarsMaster.putAll(buildVariables); | ||
infraEnvVarsNode.putAll(buildVariables); | ||
} | ||
|
||
final FilePath rootPath = getNodeRootPath(); | ||
if (rootPath != null) { | ||
|
||
final EnvInjectEnvVars envInjectEnvVarsService = new EnvInjectEnvVars(logger); | ||
|
||
//Execute script | ||
int resultCode = envInjectEnvVarsService.executeScript(info.isLoadFilesFromMaster(), | ||
info.getScriptContent(), | ||
rootPath, info.getScriptFilePath(), infraEnvVarsMaster, infraEnvVarsNode, rootPath.createLauncher(listener), listener); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
if (resultCode != 0) { | ||
build.setResult(Result.FAILURE); | ||
throw new Run.RunnerAbortedException(); | ||
} | ||
|
||
//Evaluate Groovy script | ||
Map<String, String> groovyMapEnvVars = envInjectEnvVarsService.executeAndGetMapGroovyScript(logger, info.getGroovyScriptContent(), infraEnvVarsNode); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
final Map<String, String> propertiesVariables = envInjectEnvVarsService.getEnvVarsPropertiesJobProperty(rootPath, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
logger, info.isLoadFilesFromMaster(), | ||
info.getPropertiesFilePath(), info.getPropertiesContentMap(previousEnvVars), | ||
infraEnvVarsMaster, infraEnvVarsNode); | ||
|
||
//Get variables get by contribution | ||
Map<String, String> contributionVariables = getEnvVarsByContribution(build, this, logger, listener); | ||
|
||
final Map<String, String> mergedVariables = envInjectEnvVarsService.getMergedVariables( | ||
infraEnvVarsNode, | ||
propertiesVariables, | ||
groovyMapEnvVars, | ||
contributionVariables); | ||
|
||
//Add an action to share injected environment variables | ||
new EnvInjectActionSetter(rootPath).addEnvVarsToEnvInjectBuildAction(build, mergedVariables); | ||
} | ||
} catch (Throwable t) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
StringWriter sw = new StringWriter(); | ||
PrintWriter pw = new PrintWriter(sw); | ||
t.printStackTrace(pw); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
logger.error("Failure while executing scripts in a prebuild phase: " + sw.toString()); | ||
pw.close(); | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
private Node getNode() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
Computer computer = Computer.currentComputer(); | ||
if (computer == null) { | ||
return null; | ||
} | ||
return computer.getNode(); | ||
} | ||
|
||
private FilePath getNodeRootPath() { | ||
Node node = getNode(); | ||
if (node != null) { | ||
return node.getRootPath(); | ||
} | ||
return null; | ||
} | ||
|
||
private Map<String, String> getEnvVarsByContribution(AbstractBuild build, EnvInjectPrebuildJobProperty envInjectJobProperty, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
EnvInjectLogger logger, BuildListener listener) throws EnvInjectException { | ||
|
||
assert envInjectJobProperty != null; | ||
Map<String, String> contributionVariables = new HashMap<String, String>(); | ||
|
||
EnvInjectJobPropertyContributor[] contributors = envInjectJobProperty.getContributors(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
if (contributors != null) { | ||
logger.info("Injecting contributions."); | ||
for (EnvInjectJobPropertyContributor contributor : contributors) { | ||
contributionVariables.putAll(contributor.getEnvVars(build, listener)); | ||
} | ||
} | ||
return contributionVariables; | ||
} | ||
|
||
|
||
@Deprecated | ||
private transient boolean injectGlobalPasswords; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add the missing @deprecated Javadoc tag. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @dummy-lanwen-bot (and @lanwen ) This should There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @daniel-beck I've turned on this like an experiment, sorry for spam. (Already turned off). I'll create very light profile for jenkins plugins to avoid spam in future, as of it too many violations of code style in any place :( |
||
@Deprecated | ||
private transient EnvInjectPasswordEntry[] passwordEntries; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add the missing @deprecated Javadoc tag. |
||
@Deprecated | ||
private transient boolean keepSystemVariables; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove this unused "keepSystemVariables" private field. |
||
|
||
@Deprecated | ||
public boolean isInjectGlobalPasswords() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add the missing @deprecated Javadoc tag. |
||
return injectGlobalPasswords; | ||
} | ||
|
||
@Deprecated | ||
public EnvInjectPasswordEntry[] getPasswordEntries() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add the missing @deprecated Javadoc tag. |
||
return passwordEntries; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this unused import 'hudson.model.Environment'.