Skip to content
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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public class AliasInitializer {
@Initializer(before = InitMilestone.PLUGINS_STARTED)
@SuppressWarnings("unused")
public static void addAliases() {
Items.XSTREAM.alias("EnvInjectPrebuildJobProperty", EnvInjectPrebuildJobProperty.class);
Items.XSTREAM.alias("EnvInjectJobProperty", EnvInjectJobProperty.class);
Items.XSTREAM.alias("EnvInjectBuildWrapper", EnvInjectBuildWrapper.class);
Items.XSTREAM.alias("EnvInjectPasswordWrapper", EnvInjectPasswordWrapper.class);
Expand Down
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;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Remove this unused import 'hudson.model.Environment'. rule

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) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL Either log or rethrow this exception. rule

e.printStackTrace();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL Use a logger to log this exception. rule

}
contributors = contributorsComputed;
}

return Arrays.copyOf(contributors, contributors.length);
}

private EnvInjectJobPropertyContributor[] computeEnvInjectContributors() throws org.jenkinsci.lib.envinject.EnvInjectException {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Split this 132 characters long line (which is greater than 120 authorized). rule


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();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Split this 125 characters long line (which is greater than 120 authorized). rule


//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,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Split this 123 characters long line (which is greater than 120 authorized). rule

property.info.getScriptFilePath(), property.info.getScriptContent(),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Split this 125 characters long line (which is greater than 120 authorized). rule

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.");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Method 'StaplerRequest.bindParameters(...)' is deprecated. rule
MAJOR Rename "info" which hides the field declared at line 50. rule
MINOR Split this 136 characters long line (which is greater than 120 authorized). rule

envInjectJobProperty.setInfo(info);
envInjectJobProperty.setOn(true);
if (onObject instanceof JSONObject) {
JSONObject onJSONObject = (JSONObject) onObject;
envInjectJobProperty.setKeepJenkinsSystemVariables(onJSONObject.getBoolean("keepJenkinsSystemVariables"));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Split this 126 characters long line (which is greater than 120 authorized). rule

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) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Split this 134 characters long line (which is greater than 120 authorized). rule

if (!onJSONObject.containsKey("contributors")) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Define a constant instead of duplicating this literal "contributors" 3 times. rule

envInjectJobProperty.setContributors(new EnvInjectJobPropertyContributor[0]);
} else {
JSON contribJSON;
try {
contribJSON = onJSONObject.getJSONArray("contributors");
} catch (JSONException jsone) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL Either log or rethrow this exception. rule

contribJSON = onJSONObject.getJSONObject("contributors");
}
List<EnvInjectJobPropertyContributor> contributions = req.bindJSONToList(EnvInjectJobPropertyContributor.class, contribJSON);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Split this 141 characters long line (which is greater than 120 authorized). rule

EnvInjectJobPropertyContributor[] contributionsArray = contributions.toArray(new EnvInjectJobPropertyContributor[contributions.size()]);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Split this 152 characters long line (which is greater than 120 authorized). rule

envInjectJobProperty.setContributors(contributionsArray);
}
}

public DescriptorExtensionList<EnvInjectJobPropertyContributor, EnvInjectJobPropertyContributorDescriptor> getEnvInjectContributors() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Split this 143 characters long line (which is greater than 120 authorized). rule

return EnvInjectJobPropertyContributor.all();
}

public @CheckForNull EnvInjectJobPropertyContributor[] getContributorsInstance() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Reorder the modifiers to comply with the Java Language Specification. rule

EnvInjectContributorManagement envInjectContributorManagement = new EnvInjectContributorManagement();
try {
return envInjectContributorManagement.getNewContributorsInstance();
} catch (org.jenkinsci.lib.envinject.EnvInjectException e) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL Either log or rethrow this exception. rule

e.printStackTrace();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL Use a logger to log this exception. rule

}
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) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR The Cyclomatic Complexity of this method "prebuild" is 12 which is greater than 10 authorized. rule

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();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR Rename "info" which hides the field declared at line 50. rule

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) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR Merge this if statement with the enclosing one. rule

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);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Split this 143 characters long line (which is greater than 120 authorized). rule

if (resultCode != 0) {
build.setResult(Result.FAILURE);
throw new Run.RunnerAbortedException();
}

//Evaluate Groovy script
Map<String, String> groovyMapEnvVars = envInjectEnvVarsService.executeAndGetMapGroovyScript(logger, info.getGroovyScriptContent(), infraEnvVarsNode);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Split this 165 characters long line (which is greater than 120 authorized). rule


final Map<String, String> propertiesVariables = envInjectEnvVarsService.getEnvVarsPropertiesJobProperty(rootPath,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Split this 129 characters long line (which is greater than 120 authorized). rule

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) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BLOCKER Catch Exception instead of Throwable. rule
CRITICAL Either log or rethrow this exception. rule

StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
t.printStackTrace(pw);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL Use a logger to log this exception. rule

logger.error("Failure while executing scripts in a prebuild phase: " + sw.toString());
pw.close();
return false;
}
return true;
}

private Node getNode() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Make "getNode" a "static" method. rule

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,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Split this 128 characters long line (which is greater than 120 authorized). rule

EnvInjectLogger logger, BuildListener listener) throws EnvInjectException {

assert envInjectJobProperty != null;
Map<String, String> contributionVariables = new HashMap<String, String>();

EnvInjectJobPropertyContributor[] contributors = envInjectJobProperty.getContributors();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR Rename "contributors" which hides the field declared at line 55. rule

if (contributors != null) {
logger.info("Injecting contributions.");
for (EnvInjectJobPropertyContributor contributor : contributors) {
contributionVariables.putAll(contributor.getEnvVars(build, listener));
}
}
return contributionVariables;
}


@Deprecated
private transient boolean injectGlobalPasswords;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR Add the missing @deprecated Javadoc tag. rule
MINOR Move this variable to comply with Java Code Conventions. rule

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dummy-lanwen-bot (and @lanwen ) This should code format the @deprecated otherwise the person behind that stupid user name will hate you.

Copy link
Member

Choose a reason for hiding this comment

The 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;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR Add the missing @deprecated Javadoc tag. rule
MINOR Move this variable to comply with Java Code Conventions. rule

@Deprecated
private transient boolean keepSystemVariables;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR Remove this unused "keepSystemVariables" private field. rule
MAJOR Add the missing @deprecated Javadoc tag. rule
MINOR Move this variable to comply with Java Code Conventions. rule


@Deprecated
public boolean isInjectGlobalPasswords() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR Add the missing @deprecated Javadoc tag. rule

return injectGlobalPasswords;
}

@Deprecated
public EnvInjectPasswordEntry[] getPasswordEntries() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR Add the missing @deprecated Javadoc tag. rule

return passwordEntries;
}
}
Loading