Skip to content

Commit

Permalink
[JENKINS-47823] Add warning for docker-pipeline incompatibility + exp…
Browse files Browse the repository at this point in the history
…ort MAVEN_CONFIG + export MVN_CMD
  • Loading branch information
Cyrille Le Clerc committed Nov 4, 2017
1 parent 0cc6d3f commit bfe173b
Showing 1 changed file with 78 additions and 58 deletions.
Expand Up @@ -75,7 +75,6 @@
import hudson.slaves.WorkspaceList;
import hudson.tasks.Maven;
import hudson.tasks.Maven.MavenInstallation;
import hudson.util.ArgumentListBuilder;
import jenkins.model.Jenkins;
import jenkins.mvn.DefaultGlobalSettingsProvider;
import jenkins.mvn.DefaultSettingsProvider;
Expand Down Expand Up @@ -107,9 +106,10 @@
class WithMavenStepExecution extends StepExecution {

private static final long serialVersionUID = 1L;
private static final String MAVEN_HOME = "MAVEN_HOME";
private static final String M2_HOME = "M2_HOME";
private static final String MAVEN_HOME = "MAVEN_HOME";
private static final String MAVEN_OPTS = "MAVEN_OPTS";
private static final String MVN_CMD = "MVN_CMD";

private static final Logger LOGGER = Logger.getLogger(WithMavenStepExecution.class.getName());

Expand All @@ -130,7 +130,7 @@ class WithMavenStepExecution extends StepExecution {
private transient BodyExecution body;

/**
* Inidicates if running on docker with <tt>docker.image()</tt>
* Indicates if running on docker with <tt>docker.image()</tt>
*/
private boolean withContainer;

Expand Down Expand Up @@ -173,14 +173,22 @@ public boolean start() throws Exception {

withContainer = detectWithContainer();

if (withContainer) {
listener.getLogger().print("WARNING: \"withMaven(){...}\" step running within \"docker.image('image').inside {...}\"." +
" Since the Docker Pipeline Plugin version 1.14, you MUST prepend the 'PATH' environment variable" +
" by the 'MVN_CMD' environment variable in every 'sh' step that invokes 'mvn'. See ");
listener.hyperlink("https://wiki.jenkins.io/display/JENKINS/Pipeline+Maven+Plugin?", "Pipeline Maven Plugin FAQ");
listener.getLogger().println();
}

setupJDK();

// list of credentials injected by withMaven. They will be tracked and masked in the logs
Collection<Credentials> credentials = new ArrayList<>();
setupMaven(credentials);

if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, this.build + " - Track usage and mask password of credentials " + Joiner.on(", ").join(Collections2.transform(credentials, new CredentialsToPrettyString())));
LOGGER.log(Level.FINE, this.build + " - Track usage and mask password of credentials " + Joiner.on(", ").join(Collections2.transform(credentials, new CredentialsToPrettyString())));
}
CredentialsProvider.trackAll(build, new ArrayList<>(credentials));

Expand Down Expand Up @@ -243,8 +251,8 @@ private void setupJDK() throws AbortException, IOException, InterruptedException
// see #detectWithContainer()
LOGGER.log(Level.FINE, "Ignoring JDK installation parameter: {0}", jdkInstallationName);
console.println("WARNING: \"withMaven(){...}\" step running within \"docker.image().inside{...}\"," +
" tool installations are not available see https://issues.jenkins-ci.org/browse/JENKINS-36159. " +
"You have specified a JDK installation \"" + jdkInstallationName + "\", which will be ignored.");
" tool installations are not available see https://issues.jenkins-ci.org/browse/JENKINS-36159. " +
"You have specified a JDK installation \"" + jdkInstallationName + "\", which will be ignored.");
return;
}

Expand All @@ -264,31 +272,32 @@ private void setupJDK() throws AbortException, IOException, InterruptedException
}

/**
*
* @param credentials list of credentials injected by withMaven. They will be tracked and masked in the logs.
* @throws AbortException
* @throws IOException
* @throws InterruptedException
*/
private void setupMaven(@Nonnull Collection<Credentials> credentials) throws AbortException, IOException, InterruptedException {
String mvnExecPath = obtainMavenExec();

// Temp dir with the wrapper that will be prepended to the path
// Temp dir with the wrapper that will be prepended to the path and the temporary files used by withMazven (settings files...)
tempBinDir = tempDir(ws).child("withMaven" + Util.getDigestOf(UUID.randomUUID().toString()).substring(0, 8));
tempBinDir.mkdirs();
// set the path to our script
envOverride.put("PATH+MAVEN", tempBinDir.getRemote());

LOGGER.log(Level.FINE, "Using temp dir: {0}", tempBinDir.getRemote());

if (mvnExecPath == null) {
throw new AbortException("Couldn\u2019t find any maven executable");
}
// SETTINGS FILES
String settingsFilePath = setupSettingFile(credentials);
String globalSettingsFilePath = setupGlobalSettingFile(credentials);

FilePath mvnExec = new FilePath(ws.getChannel(), mvnExecPath);
// LOCAL REPOSITORY
String mavenLocalRepo = setupMavenLocalRepo();

// MAVEN EVENT SPY
FilePath mavenSpyJarPath = setupMavenSpy();

// JAVA_TOOL_OPTIONS: https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/envvars002.html
//
// JAVA_TOOL_OPTIONS
// https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/envvars002.html
String javaToolsOptions = env.get("JAVA_TOOL_OPTIONS", "");
if (StringUtils.isNotEmpty(javaToolsOptions)) {
javaToolsOptions += " ";
Expand All @@ -297,11 +306,25 @@ private void setupMaven(@Nonnull Collection<Credentials> credentials) throws Abo
"-Dorg.jenkinsci.plugins.pipeline.maven.reportsFolder=\"" + this.tempBinDir.getRemote() + "\" ";
envOverride.put("JAVA_TOOL_OPTIONS", javaToolsOptions);

String content = mavenWrapperContent(mvnExec, setupSettingFile(credentials), setupGlobalSettingFile(credentials), setupMavenLocalRepo());
//
// MAVEN_CONFIG
StringBuilder mavenConfig = new StringBuilder();
if (StringUtils.isNotEmpty(settingsFilePath)) {
mavenConfig.append(" --settings " + settingsFilePath);
}
if (StringUtils.isNotEmpty(globalSettingsFilePath)) {
mavenConfig.append(" --global-settings " + globalSettingsFilePath);
}
if (StringUtils.isNotEmpty(mavenLocalRepo)) {
mavenConfig.append(" -Dmaven.repo.local=" + mavenLocalRepo);
}
mavenConfig.append(" --batch-mode");
mavenConfig.append(" --show-version");

createWrapperScript(tempBinDir, mvnExec.getName(), content);
envOverride.put("MAVEN_CONFIG", mavenConfig.toString());

// Maven Ops
//
// MAVEN_OPTS
if (StringUtils.isNotEmpty(step.getMavenOpts())) {
String mavenOpts = envOverride.expand(env.expand(step.getMavenOpts()));

Expand All @@ -311,6 +334,21 @@ private void setupMaven(@Nonnull Collection<Credentials> credentials) throws Abo
}
envOverride.put(MAVEN_OPTS, mavenOpts.replaceAll("[\t\r\n]+", " "));
}

// MAVEN SCRIPT WRAPPER
String mvnExecPath = obtainMavenExec();

LOGGER.log(Level.FINE, "Using temp dir: {0}", tempBinDir.getRemote());

if (mvnExecPath == null) {
throw new AbortException("Couldn\u2019t find any maven executable");
}

FilePath mvnExec = new FilePath(ws.getChannel(), mvnExecPath);
String content = generateMavenWrapperScriptContent(mvnExec);

createWrapperScript(tempBinDir, mvnExec.getName(), content);

}

private FilePath setupMavenSpy() throws IOException, InterruptedException {
Expand Down Expand Up @@ -348,7 +386,7 @@ private FilePath setupMavenSpy() throws IOException, InterruptedException {
return mavenSpyJarFilePath;
}

private String obtainMavenExec() throws AbortException, IOException, InterruptedException {
private String obtainMavenExec() throws IOException, InterruptedException {
String mavenInstallationName = step.getMaven();
LOGGER.log(Level.FINE, "Setting up maven: {0}", mavenInstallationName);

Expand All @@ -371,7 +409,7 @@ private String obtainMavenExec() throws AbortException, IOException, Interrupted
if (mavenInstallationName.equals(i.getName())) {
mavenInstallation = i;
consoleMessage.append(" use Maven installation '" + mavenInstallation.getName() + "'");
LOGGER.log(Level.FINE, "Found maven installation {0} with installation home {1}", new Object[]{mavenInstallation.getName(), mavenInstallation.getHome()});
LOGGER.log(Level.FINE, "Found maven installation {0} with installation home {1}", new Object[]{mavenInstallation.getName(), mavenInstallation.getHome()});
break;
}
}
Expand Down Expand Up @@ -491,58 +529,39 @@ private String readFromProcess(String... args) throws InterruptedException {
}

/**
* Generates the content of the maven wrapper script that works
* Generates the content of the maven wrapper script
*
* @param mvnExec maven executable location
* @param settingsFile settings file
* @param globalSettingsFile global settings file
* @param mavenLocalRepo maven local repo location
* @param mvnExec maven executable location
* @return wrapper script content
* @throws AbortException when problems creating content
*/
private String mavenWrapperContent(FilePath mvnExec, String settingsFile, String globalSettingsFile, String mavenLocalRepo) throws AbortException {

ArgumentListBuilder argList = new ArgumentListBuilder(mvnExec.getRemote());
private String generateMavenWrapperScriptContent(FilePath mvnExec) throws AbortException {

boolean isUnix = Boolean.TRUE.equals(getComputer().isUnix());

String lineSep = isUnix ? "\n" : "\r\n";

if (StringUtils.isNotEmpty(settingsFile)) {
argList.add("--settings", settingsFile);
}

if (StringUtils.isNotEmpty(globalSettingsFile)) {
argList.add("--global-settings", globalSettingsFile);
}

if (StringUtils.isNotEmpty(mavenLocalRepo)) {
argList.addKeyValuePair(null, "maven.repo.local", mavenLocalRepo, false);
}
StringBuilder script = new StringBuilder();

argList.add("--batch-mode");
argList.add("--show-version");
if (isUnix) { // Linux, Unix, MacOSX
String lineSep = "\n";
script.append("#!/bin/sh -e").append(lineSep);
script.append("echo ----- withMaven Wrapper script -----").append(lineSep);
script.append(mvnExec.getRemote() + " $MAVEN_CONFIG \"$@\"").append(lineSep);

StringBuilder c = new StringBuilder();

if (isUnix) {
c.append("#!/bin/sh -e").append(lineSep);
} else { // Windows
c.append("@echo off").append(lineSep);
String lineSep = "\r\n";
script.append("@echo off").append(lineSep);
script.append("echo ----- withMaven Wrapper script -----").append(lineSep);
script.append(mvnExec.getRemote() + " %MAVEN_CONFIG% %*").append(lineSep);
}

c.append("echo ----- withMaven Wrapper script -----").append(lineSep);
c.append(argList.toString()).append(isUnix ? " \"$@\"" : " %*").append(lineSep);

String content = c.toString();
LOGGER.log(Level.FINER, "Generated wrapper: {0}", content);
return content;
LOGGER.log(Level.FINER, "Generated Maven wrapper script: \n{0}", script);
return script.toString();
}

/**
* Creates the actual wrapper script file and sets the permissions.
*
* @param tempBinDir dir to create the script file on
* @param tempBinDir dir to create the script file
* @param name the script file name
* @param content contents of the file
* @return
Expand All @@ -551,6 +570,7 @@ private String mavenWrapperContent(FilePath mvnExec, String settingsFile, String
*/
private FilePath createWrapperScript(FilePath tempBinDir, String name, String content) throws IOException, InterruptedException {
FilePath scriptFile = tempBinDir.child(name);
envOverride.put(MVN_CMD, scriptFile.getRemote());

scriptFile.write(content, getComputer().getDefaultCharset().name());
scriptFile.chmod(0755);
Expand Down Expand Up @@ -729,7 +749,7 @@ private String setupGlobalSettingFile(@Nonnull Collection<Credentials> credentia
* folder to use it with the maven wrapper script
*
* @param mavenSettingsConfigId config file id from Config File Provider
* @param mavenSettingsFile path to write te content to
* @param mavenSettingsFile path to write te content to
* @param credentials
* @return the {@link FilePath} to the settings file
* @throws AbortException in case of error
Expand Down Expand Up @@ -784,7 +804,7 @@ private void settingsFromConfig(String mavenSettingsConfigId, FilePath mavenSett
* folder to use it with the maven wrapper script
*
* @param mavenGlobalSettingsConfigId global config file id from Config File Provider
* @param mavenGlobalSettingsFile path to write te content to
* @param mavenGlobalSettingsFile path to write te content to
* @param credentials
* @return the {@link FilePath} to the settings file
* @throws AbortException in case of error
Expand Down

0 comments on commit bfe173b

Please sign in to comment.