Skip to content

Commit

Permalink
[FIX JENKINS-40364]
Browse files Browse the repository at this point in the history
  • Loading branch information
nfalco79 committed Jan 22, 2017
2 parents 148305e + e1be967 commit c1d918a
Show file tree
Hide file tree
Showing 40 changed files with 1,883 additions and 18 deletions.
11 changes: 11 additions & 0 deletions pom.xml
Expand Up @@ -45,6 +45,17 @@
</properties>

<dependencies>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>config-file-provider</artifactId>
<version>2.15.5</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.6.4</version>
<scope>test</scope>
</dependency>
</dependencies>

<repositories>
Expand Down
43 changes: 41 additions & 2 deletions src/main/java/jenkins/plugins/nodejs/NodeJSBuildWrapper.java
@@ -1,22 +1,33 @@
package jenkins.plugins.nodejs;

import java.io.IOException;
import java.util.Collection;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;

import org.jenkinsci.lib.configprovider.model.Config;
import org.jenkinsci.plugins.configfiles.GlobalConfigFiles;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;

import hudson.AbortException;
import hudson.EnvVars;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.Util;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Computer;
import hudson.model.Node;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.tasks.BuildWrapperDescriptor;
import hudson.util.FormValidation;
import jenkins.plugins.nodejs.configfiles.NPMConfig;
import jenkins.plugins.nodejs.configfiles.NPMConfig.NPMConfigProvider;
import jenkins.plugins.nodejs.configfiles.VerifyConfigProviderException;
import jenkins.plugins.nodejs.tools.NodeJSInstallation;
import jenkins.tasks.SimpleBuildWrapper;

Expand Down Expand Up @@ -46,10 +57,12 @@ public String put(String key, String value) {
}

private final String nodeJSInstallationName;
private final String configId;

@DataBoundConstructor
public NodeJSBuildWrapper(String nodeJSInstallationName){
public NodeJSBuildWrapper(String nodeJSInstallationName, String configId) {
this.nodeJSInstallationName = Util.fixEmpty(nodeJSInstallationName);
this.configId = Util.fixEmpty(configId);
}

/**
Expand All @@ -65,6 +78,10 @@ public String getNodeJSInstallationName() {
return nodeJSInstallationName;
}

public String getConfigId() {
return configId;
}

/*
* (non-Javadoc)
* @see jenkins.tasks.SimpleBuildWrapper#setUp(jenkins.tasks.SimpleBuildWrapper.Context, hudson.model.Run, hudson.FilePath, hudson.Launcher, hudson.model.TaskListener, hudson.EnvVars)
Expand All @@ -76,13 +93,19 @@ public void setUp(final Context context, Run<?, ?> build, FilePath workspace, La
if (ni == null) {
throw new IOException(Messages.NodeJSCommandInterpreter_noInstallationFound(nodeJSInstallationName));
}
Node node = workspace.toComputer().getNode();
Computer computer = workspace.toComputer();
if (computer == null) {
throw new AbortException(Messages.NodeJSCommandInterpreter_nodeOffline());
}
Node node = computer.getNode();
if (node == null) {
throw new AbortException(Messages.NodeJSCommandInterpreter_nodeOffline());
}
ni = ni.forNode(node, listener);
ni = ni.forEnvironment(initialEnvironment);
ni.buildEnvVars(new EnvVarsAdapter(context));

NodeJSUtils.supplyConfig(configId, (AbstractBuild<?, ?>) build, listener);
}


Expand All @@ -103,6 +126,22 @@ public NodeJSInstallation[] getInstallations() {
return NodeJSUtils.getInstallations();
}

public Collection<Config> getConfigs() {
return GlobalConfigFiles.get().getConfigs(NPMConfigProvider.class);
}

public FormValidation doCheckConfigId(@CheckForNull @QueryParameter final String configId) {
NPMConfig config = (NPMConfig) GlobalConfigFiles.get().getById(configId);
if (config != null) {
try {
config.doVerify();
} catch (VerifyConfigProviderException e) {
return FormValidation.error(e.getMessage());
}
}
return FormValidation.ok();
}

}

}
49 changes: 45 additions & 4 deletions src/main/java/jenkins/plugins/nodejs/NodeJSCommandInterpreter.java
@@ -1,8 +1,14 @@
package jenkins.plugins.nodejs;

import java.io.IOException;
import java.util.Collection;

import javax.annotation.CheckForNull;

import org.jenkinsci.lib.configprovider.model.Config;
import org.jenkinsci.plugins.configfiles.GlobalConfigFiles;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;

import hudson.AbortException;
import hudson.EnvVars;
Expand All @@ -17,6 +23,10 @@
import hudson.tasks.Builder;
import hudson.tasks.CommandInterpreter;
import hudson.util.ArgumentListBuilder;
import hudson.util.FormValidation;
import jenkins.plugins.nodejs.configfiles.NPMConfig;
import jenkins.plugins.nodejs.configfiles.VerifyConfigProviderException;
import jenkins.plugins.nodejs.configfiles.NPMConfig.NPMConfigProvider;
import jenkins.plugins.nodejs.tools.NodeJSInstallation;
import jenkins.plugins.nodejs.tools.Platform;

Expand All @@ -28,9 +38,8 @@
* @author Nikolas Falco
*/
public class NodeJSCommandInterpreter extends CommandInterpreter {
private static final String JAVASCRIPT_EXT = ".js";

private final String nodeJSInstallationName;
private final String configId;
private transient String nodeExec; // NOSONAR

/**
Expand All @@ -40,11 +49,14 @@ public class NodeJSCommandInterpreter extends CommandInterpreter {
* the NodeJS script
* @param nodeJSInstallationName
* the NodeJS label configured in Jenkins
* @param configId
* the provided Config id
*/
@DataBoundConstructor
public NodeJSCommandInterpreter(final String command, final String nodeJSInstallationName) {
public NodeJSCommandInterpreter(final String command, final String nodeJSInstallationName, final String configId) {
super(command);
this.nodeJSInstallationName = Util.fixEmpty(nodeJSInstallationName);
this.configId = Util.fixEmpty(configId);
}

/**
Expand Down Expand Up @@ -82,6 +94,9 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListen
throw new AbortException(Messages.NodeJSCommandInterpreter_noExecutableFound(ni.getHome()));
}
}

// add npmrc config
NodeJSUtils.supplyConfig(configId, build, listener);
} catch (AbortException e) {
listener.fatalError(e.getMessage()); // NOSONAR
return false;
Expand Down Expand Up @@ -110,13 +125,17 @@ protected String getContents() {

@Override
protected String getFileExtension() {
return JAVASCRIPT_EXT;
return NodeJSConstants.JAVASCRIPT_EXT;
}

public String getNodeJSInstallationName() {
return nodeJSInstallationName;
}

public String getConfigId() {
return configId;
}

/**
* Provides builder details for the job configuration page.
*
Expand Down Expand Up @@ -149,6 +168,28 @@ public NodeJSInstallation[] getInstallations() {
return NodeJSUtils.getInstallations();
}

/**
* Gather all defined npmrc config files.
*
* @return a collection of user npmrc files or {@code empty} if no one
* defined.
*/
public Collection<Config> getConfigs() {
return GlobalConfigFiles.get().getConfigs(NPMConfigProvider.class);
}

public FormValidation doCheckConfigId(@CheckForNull @QueryParameter final String configId) {
NPMConfig config = (NPMConfig) GlobalConfigFiles.get().getById(configId);
if (config != null) {
try {
config.doVerify();
} catch (VerifyConfigProviderException e) {
return FormValidation.error(e.getMessage());
}
}
return FormValidation.ok();
}

}

}
42 changes: 42 additions & 0 deletions src/main/java/jenkins/plugins/nodejs/NodeJSConstants.java
@@ -0,0 +1,42 @@
package jenkins.plugins.nodejs;

public final class NodeJSConstants {

private NodeJSConstants() {
// constructor
}

/**
* Default extension for javascript file.
*/
public static final String JAVASCRIPT_EXT = ".js";

/**
* The location of user-level configuration settings.
*/
public static final String NPM_USERCONFIG = "npm_config_userconfig";

/**
* Force npm to always require authentication when accessing the registry,
* even for GET requests.
* <p>
* Default: false<br>
* Type: Boolean
* </p>
*/
public static final String NPM_SETTINGS_ALWAYS_AUTH = "always-auth";
/**
* The base URL of the npm package registry.
* <p>
* Default: https://registry.npmjs.org/<br>
* Type: url
* </p>
*/
public static final String NPM_SETTINGS_REGISTRY = "registry";
/**
* The authentication base64 string &gt;USER&lt;:&gt;PASSWORD&lt; used to
* login to the global registry.
*/
public static final String NPM_SETTINGS_AUTH = "_auth";

}
91 changes: 90 additions & 1 deletion src/main/java/jenkins/plugins/nodejs/NodeJSUtils.java
@@ -1,12 +1,34 @@
package jenkins.plugins.nodejs;

import hudson.AbortException;
import hudson.FilePath;
import hudson.Util;
import hudson.model.Environment;
import hudson.model.TaskListener;
import hudson.model.AbstractBuild;

import java.util.List;
import java.util.Map;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import jenkins.model.Jenkins;
import jenkins.plugins.nodejs.configfiles.NPMConfig;
import jenkins.plugins.nodejs.configfiles.NPMRegistry;
import jenkins.plugins.nodejs.configfiles.RegistryHelper;
import jenkins.plugins.nodejs.configfiles.VerifyConfigProviderException;
import jenkins.plugins.nodejs.tools.NodeJSInstallation;
import jenkins.plugins.nodejs.tools.NodeJSInstallation.DescriptorImpl;

import org.apache.commons.lang.StringUtils;
import org.jenkinsci.lib.configprovider.model.Config;
import org.jenkinsci.plugins.configfiles.ConfigFiles;
import org.jenkinsci.plugins.configfiles.buildwrapper.ManagedFileUtil;
import org.jenkinsci.plugins.configfiles.common.CleanTempFilesAction;

import com.cloudbees.plugins.credentials.common.StandardUsernameCredentials;

/*package*/final class NodeJSUtils {

private NodeJSUtils() {
Expand All @@ -25,7 +47,7 @@ private NodeJSUtils() {
public static NodeJSInstallation getNodeJS(@Nullable String name) {
if (name != null) {
for (NodeJSInstallation installation : getInstallations()) {
if (name != null && name.equals(installation.getName()))
if (name.equals(installation.getName()))
return installation;
}
}
Expand All @@ -46,4 +68,71 @@ public static NodeJSInstallation[] getInstallations() {
return descriptor.getInstallations();
}

/**
* Create a copy of the given configuration in a no accessible folder for
* the user.
* <p>
* This file will be deleted at the end of job also in case of user
* interruption.
* </p>
*
* @param configId the configuration identification
* @param build a build being run
* @param listener a way to report progress
* @throws AbortException in case the provided configId is not valid
*/
public static FilePath supplyConfig(String configId, AbstractBuild<?, ?> build, TaskListener listener) throws AbortException {
if (StringUtils.isNotBlank(configId)) {
Config c = ConfigFiles.getByIdOrNull(build, configId);

if (c == null) {
throw new AbortException("this NodeJS build is setup to use a config with id " + configId + " but can not be find");
} else {
NPMConfig config;
if (c instanceof NPMConfig) {
config = (NPMConfig) c;
} else {
config = new NPMConfig(c.id, c.name, c.comment, c.content, c.getProviderId(), null);
}

listener.getLogger().println("using user config with name " + config.name);
String fileContent = config.content;

List<NPMRegistry> registries = config.getRegistries();
RegistryHelper helper = new RegistryHelper(registries);
if (!registries.isEmpty()) {
listener.getLogger().println("Adding all registry entries");
Map<String, StandardUsernameCredentials> registry2Credentials = helper.resolveCredentials(build);
fileContent = helper.fillRegistry(fileContent, registry2Credentials);
}

try {
if (StringUtils.isNotBlank(fileContent)) { // NOSONAR
config.doVerify();

FilePath workDir = ManagedFileUtil.tempDir(build.getWorkspace());
final FilePath f = workDir.createTextTempFile(".npmrc", "", Util.replaceMacro(fileContent, build.getEnvironment(listener)), true);
listener.getLogger().printf("Created %s", f);

build.getEnvironments().add(new Environment() {
@Override
public void buildEnvVars(Map<String, String> env) {
env.put(NodeJSConstants.NPM_USERCONFIG, f.getRemote());
}
});

build.addAction(new CleanTempFilesAction(f.getRemote()));
return f;
}
} catch (VerifyConfigProviderException e) {
throw new AbortException("Invalid user config: " + e.getMessage());
} catch (Exception e) {
throw new IllegalStateException("the npmrc user config could not be supplied for the current build", e);
}
}
}

return null;
}

}

0 comments on commit c1d918a

Please sign in to comment.