Skip to content

Commit

Permalink
Implemented a 'Global Tool Configuration' for Surround. Removed 'Path…
Browse files Browse the repository at this point in the history
… to Surround Executable' from Pipeline and Freestyle configurations.
  • Loading branch information
pvince committed Nov 14, 2016
1 parent e21f190 commit 0ee8461
Show file tree
Hide file tree
Showing 10 changed files with 260 additions and 36 deletions.
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,5 +86,11 @@
<artifactId>mailer</artifactId>
<version>1.16</version>
</dependency>

<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>structs</artifactId>
<version>1.5</version>
</dependency>
</dependencies>
</project>
23 changes: 23 additions & 0 deletions src/main/java/hudson/scm/SSCMUtils.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package hudson.scm;

import hudson.FilePath;
import hudson.model.Computer;
import hudson.model.Node;
import jenkins.model.Jenkins;

/**
* Class of basic utils for working with 'sscm://' urls.
*/
Expand Down Expand Up @@ -131,6 +136,24 @@ public static boolean validateSSCMURL(String URL)

// Check section 3 & 4
return !(splitURL[2].isEmpty() || splitURL[3].isEmpty());
}

public static Node workspaceToNode(FilePath workspace)
{
Jenkins j = Jenkins.getActiveInstance();
if(workspace != null && workspace.isRemote())
{
for(Computer c : j.getComputers())
{
if(c.getChannel() == workspace.getChannel())
{
Node n = c.getNode();
if(n != null)
return n;
}
}
}
return j;
}

}
110 changes: 89 additions & 21 deletions src/main/java/hudson/scm/SurroundSCM.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package hudson.scm;

import hudson.*;
import hudson.model.AbstractBuild;
import hudson.model.Job;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.model.*;
import hudson.util.ArgumentListBuilder;
import jenkins.model.Jenkins;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;
Expand Down Expand Up @@ -69,7 +67,12 @@ public SCM newInstance(StaplerRequest req, JSONObject formData)
private String password ;
private String branch ;
private String repository;

@Deprecated
private String surroundSCMExecutable;

private String sscm_tool_name;

private boolean bIncludeOutput;


Expand Down Expand Up @@ -138,18 +141,6 @@ public void setIncludeOutput(boolean includeOutput) {
this.bIncludeOutput = includeOutput;
}

public String getSurroundSCMExecutable() {
if (surroundSCMExecutable == null)
return "sscm";
else
return surroundSCMExecutable;
}

public void setSurroundSCMExecutable(String surroundSCMExecutable) {
this.surroundSCMExecutable = surroundSCMExecutable;
}


/**
* Singleton descriptor.
*/
Expand All @@ -160,6 +151,22 @@ public void setSurroundSCMExecutable(String surroundSCMExecutable) {
private static final String SURROUND_DATETIME_FORMAT_STR_2 = "yyyyMMddHH:mm:ss";

@DataBoundConstructor
public SurroundSCM(String rsaKeyPath, String server, String serverPort, String userName,
String password, String branch, String repository)
{
this.rsaKeyPath = rsaKeyPath;
this.server = server;
this.serverPort = serverPort;
this.userName = userName;
this.password = password;
this.branch = branch;
this.repository = repository;
this.bIncludeOutput = true; // Leaving this here for future functionality.

this.surroundSCMExecutable = null;
}

@Deprecated
public SurroundSCM(String rsaKeyPath, String server, String serverPort, String userName,
String password, String branch, String repository, String surroundSCMExecutable,
boolean includeOutput) {
Expand Down Expand Up @@ -248,7 +255,8 @@ public PollingResult compareRemoteRevisionWith(

listener.getLogger().println("Calculating changes since build #" + lastBuildNum + " which happened at " + scm_datetime_formatter.format(lastBuild) + " pluginVer: " + pluginVersion);

double countChanges = determineChangeCount(launcher, listener, lastBuild, now, temporaryFile);

double countChanges = determineChangeCount(launcher, listener, lastBuild, now, temporaryFile, workspace);

if(!temporaryFile.delete())
{
Expand Down Expand Up @@ -276,6 +284,7 @@ public void checkout(
@Nonnull Run<?, ?> build, @Nonnull Launcher launcher, @Nonnull FilePath workspace, @Nonnull TaskListener listener,
@CheckForNull File changelogFile, @CheckForNull SCMRevisionState baseline) throws IOException, InterruptedException
{

SimpleDateFormat scm_datetime_formatter = new SimpleDateFormat(SURROUND_DATETIME_FORMAT_STR_2);

Date currentDate = new Date(); //defaults to current
Expand All @@ -286,7 +295,7 @@ public void checkout(
}

ArgumentListBuilder cmd = new ArgumentListBuilder();
cmd.add(getSurroundSCMExecutable());//will default to sscm user can put in path
cmd.add(getSscmExe(workspace, listener, environment));//will default to sscm user can put in path
cmd.add("get");
cmd.add("/" );
cmd.add("-wreplace");
Expand Down Expand Up @@ -359,7 +368,7 @@ private boolean captureChangeLog(Launcher launcher, FilePath workspace,
dateRange = dateRange.concat(scm_datetime_formatter.format(currentDate));

ArgumentListBuilder cmd = new ArgumentListBuilder();
cmd.add(getSurroundSCMExecutable());//will default to sscm user can put in path
cmd.add(getSscmExe(workspace, listener, env));//will default to sscm user can put in path
cmd.add("cc");
cmd.add("/");
cmd.add("-d".concat(dateRange));
Expand Down Expand Up @@ -405,7 +414,7 @@ private boolean captureChangeLog(Launcher launcher, FilePath workspace,
}

private double determineChangeCount(Launcher launcher, TaskListener listener, Date lastBuildDate,
Date currentDate, File changelogFile) throws IOException, InterruptedException
Date currentDate, File changelogFile, FilePath workspace) throws IOException, InterruptedException
{
SimpleDateFormat scm_datetime_formatter = new SimpleDateFormat(SURROUND_DATETIME_FORMAT_STR);

Expand All @@ -418,7 +427,7 @@ private double determineChangeCount(Launcher launcher, TaskListener listener, Da
dateRange = dateRange.concat(scm_datetime_formatter.format(currentDate));

ArgumentListBuilder cmd = new ArgumentListBuilder();
cmd.add(getSurroundSCMExecutable());
cmd.add(getSscmExe(workspace, listener, null));
cmd.add("cc");
cmd.add("/");
cmd.add("-d".concat(dateRange));
Expand Down Expand Up @@ -483,4 +492,63 @@ private double determineChangeCount(Launcher launcher, TaskListener listener, Da
return changesCount;
}

/**
* Attempt to find a pre-configured 'SurroundTool' with a saved 'sscm_tool_name'
* Currently this will always fall back to the 'default' tool for the current node and requires some further
* testing of edge conditions
*
* @param listener
* @return
*/
public SurroundTool resolveSscmTool(TaskListener listener)
{
// TODO_PTV: Review this function, should we allow users to override the sscm_tool_name in the project level?
// TODO_PTV: Review this function, does this work when a node is configured to use a 2nd Surround SCM tool?
SurroundTool sscm = null;
if(sscm_tool_name == null || sscm_tool_name.isEmpty()) {
sscm = SurroundTool.getDefaultInstallation();
} else {
sscm = Jenkins.getInstance().getDescriptorByType(SurroundTool.DescriptorImpl.class).getInstallation(sscm_tool_name);
if (sscm == null) {
listener.getLogger().println(String.format("Selected sscm installation [%s] does not exist. Using Default", sscm_tool_name));
sscm = SurroundTool.getDefaultInstallation();
}
}
// TODO_PTV: Is it safe to save off the tool name so we don't need to perform a lookup again?
//if(sscm != null)
// sscm_tool_name = sscm.getName();

return sscm;
}

public String getSscmExe( FilePath workspace, TaskListener listener, EnvVars env) throws IOException, InterruptedException {
if(workspace != null) {
workspace.mkdirs(); // ensure it exists.
}
return getSscmExe(SSCMUtils.workspaceToNode(workspace), env, listener);
}

/**
* See "public String getGitExe(Node builtOn, EnvVars env, TaskListener listener)" Line 848 @ GitSCM.java
* @param builtOn
* @param env
* @param listener
* @return
*/
public String getSscmExe(Node builtOn, EnvVars env, TaskListener listener)
{
SurroundTool tool = resolveSscmTool(listener);
if(builtOn != null) {
try {
tool = tool.forNode(builtOn, listener);
} catch(IOException | InterruptedException e) {
listener.getLogger().println("Failed to get sscm executable");
}
}
if(env != null) {
tool = tool.forEnvironment(env);
}

return tool.getSscmExe();
}
}
126 changes: 126 additions & 0 deletions src/main/java/hudson/scm/SurroundTool.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package hudson.scm;

import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.EnvVars;
import hudson.Extension;
import hudson.init.InitMilestone;
import hudson.init.Initializer;
import hudson.model.EnvironmentSpecific;
import hudson.model.Node;
import hudson.model.TaskListener;
import hudson.slaves.NodeSpecific;
import hudson.tools.ToolDescriptor;
import hudson.tools.ToolInstallation;
import hudson.tools.ToolProperty;
import hudson.util.FormValidation;
import jenkins.model.Jenkins;
import org.jenkinsci.Symbol;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;

import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;

public final class SurroundTool extends ToolInstallation implements NodeSpecific<SurroundTool>, EnvironmentSpecific<SurroundTool>
{
public static transient final String DEFAULT_NAME = "Default";

@DataBoundConstructor
public SurroundTool(String name, String home, List<? extends ToolProperty<?>> properties) {
super(name, home, properties);
}

public String getSscmExe() { return getHome(); }

private static SurroundTool[] getInstallations(DescriptorImpl descriptor) {
SurroundTool[] installations = null;
try {
installations = descriptor.getInstallations();
} catch (NullPointerException e) {
installations = new SurroundTool[0];
}
return installations;
}

public static SurroundTool getDefaultInstallation() {
Jenkins jenkinsInstance = Jenkins.getInstance();
if(jenkinsInstance == null)
return null;

DescriptorImpl surroundTools = jenkinsInstance.getDescriptorByType(SurroundTool.DescriptorImpl.class);
SurroundTool tool = surroundTools.getInstallation(SurroundTool.DEFAULT_NAME);
if(tool != null) {
return tool;
} else {
SurroundTool[] installations = surroundTools.getInstallations();
if(installations.length > 0) {
return installations[0];
} else {
onLoaded();
return surroundTools.getInstallations()[0];
}
}
}

@Override
public SurroundTool forNode(@NonNull Node node, TaskListener log) throws IOException, InterruptedException {
return new SurroundTool(getName(), translateFor(node, log), Collections.<ToolProperty<?>>emptyList());
}

@Override
public SurroundTool forEnvironment(EnvVars environment) {
return new SurroundTool(getName(), environment.expand(getHome()), Collections.<ToolProperty<?>>emptyList());
}

@Initializer(after = InitMilestone.EXTENSIONS_AUGMENTED)
public static void onLoaded() {
// creates default tool installation if needed. Uses "sscm" or migrates data from previous versions.

Jenkins jenkinsInstance = Jenkins.getInstance();
if(jenkinsInstance == null)
return;

DescriptorImpl descriptor = (DescriptorImpl)jenkinsInstance.getDescriptor(SurroundTool.class);
SurroundTool[] installations = getInstallations(descriptor);

if(installations != null && installations.length > 0) {
// No need to initialize if there's already something
return;
}

String defaultSscmExe = isWindows() ? "sscm.exe" : "sscm";
SurroundTool tool = new SurroundTool(DEFAULT_NAME, defaultSscmExe, Collections.<ToolProperty<?>>emptyList());
descriptor.setInstallations(new SurroundTool[]{ tool });
descriptor.save();
}

@Extension @Symbol("sscm")
public static class DescriptorImpl extends ToolDescriptor<SurroundTool>
{
@Override
public String getDisplayName() {
return "Surround SCM";
}

@Override
public FormValidation doCheckHome(@QueryParameter File value) {
Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);
String path = value.getPath();
return FormValidation.validateExecutable(path);
}

public SurroundTool getInstallation(String name) {
for(SurroundTool s : getInstallations()) {
if(s.getName().equals(name))
return s;
}
return null;
}
}

private static boolean isWindows() {
return File.pathSeparatorChar==';';
}
}
9 changes: 3 additions & 6 deletions src/main/resources/hudson/scm/SurroundSCM/config.jelly
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,6 @@
Creates a text field that shows the value of the "name" property.
When submitted, it will be passed to the corresponding constructor parameter.
-->
<f:entry title="CLI (sscm)" field="surroundSCMExecutable" >
<f:textbox />
</f:entry>
<f:entry title="RSA key path" field="rsaKeyPath">
<f:textbox />
</f:entry>
<f:entry title="Server name" field="server">
<f:textbox />
</f:entry>
Expand All @@ -34,4 +28,7 @@
<f:entry title="Repository" field="repository">
<f:textbox />
</f:entry>
<f:entry title="RSA key path" field="rsaKeyPath">
<f:textbox />
</f:entry>
</j:jelly>

This file was deleted.

3 changes: 0 additions & 3 deletions src/main/resources/hudson/scm/SurroundStep/config.jelly
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@
<f:entry field="password" title="Password">
<f:password />
</f:entry>
<f:entry field="sscmPath" title="CLI (sscm) ">
<f:textbox />
</f:entry>
<f:entry field="RSAKeyFile" title="RSA key path">
<f:textbox />
</f:entry>
Expand Down

0 comments on commit 0ee8461

Please sign in to comment.