Skip to content

Commit

Permalink
JENKINS-15793 Add support for specifying https protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
rossrowe committed Nov 12, 2012
1 parent e6adb4c commit c3047f5
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 59 deletions.
29 changes: 22 additions & 7 deletions pom.xml
@@ -1,4 +1,5 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
Expand Down Expand Up @@ -61,6 +62,20 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.zeroturnaround</groupId>
<artifactId>jrebel-maven-plugin</artifactId>
<version>1.1.1</version>
<executions>
<execution>
<id>generate-rebel-xml</id>
<phase>process-resources</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<extensions>
<extension>
Expand Down Expand Up @@ -125,11 +140,11 @@
<artifactId>commons-io</artifactId>
<version>1.4</version>
</dependency>
<!--<dependency>-->
<!--<groupId>com.saucelabs</groupId>-->
<!--<artifactId>sebuilder-interpreter</artifactId>-->
<!--<version>1.0.0-SNAPSHOT</version>-->
<!--</dependency>-->
<dependency>
<groupId>com.saucelabs</groupId>
<artifactId>sebuilder-interpreter</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.saucelabs</groupId>
<artifactId>saucerest</artifactId>
Expand All @@ -151,7 +166,7 @@
<dependency>
<groupId>com.saucelabs</groupId>
<artifactId>ci-sauce</artifactId>
<version>1.19</version>
<version>1.20</version>
<scope>compile</scope>
</dependency>
<dependency>
Expand Down
Expand Up @@ -26,7 +26,6 @@
import java.util.logging.Logger;

/**
*
* Presents the links to the Sauce OnDemand jobs on the build summary page.
*
* @author Ross Rowe
Expand All @@ -37,7 +36,8 @@ public class SauceOnDemandBuildAction extends AbstractAction {

private static final String DATE_FORMAT = "yyyy-MM-dd-HH";

public static final String JOB_DETAILS_URL = "http://saucelabs.com/rest/v1/%1$s/jobs?full=true";
public static final String JOB_DETAILS_URL = "http://saucelabs.com/rest/v1/%1$s/build/%2$s/jobs?full=true";
// public static final String JOB_DETAILS_URL = "http://saucelabs.com/rest/v1/%1$s/build/SC-SC-7/jobs?full=true";

private static final String HMAC_KEY = "HMACMD5";

Expand Down Expand Up @@ -97,25 +97,21 @@ public List<JobInformation> retrieveJobIdsFromSauce() throws IOException, JSONEx
List<JobInformation> jobInformation = new ArrayList<JobInformation>();

SauceFactory sauceAPIFactory = new SauceFactory();
String jsonResponse = sauceAPIFactory.doREST(String.format(JOB_DETAILS_URL, username), username, accessKey);
JSONArray jobResults = new JSONArray(jsonResponse);
String jsonResponse = sauceAPIFactory.doREST(String.format(JOB_DETAILS_URL, username, SauceOnDemandBuildWrapper.sanitiseBuildNumber(build.toString())), username, accessKey);
JSONObject job = new JSONObject(jsonResponse);
JSONArray jobResults = job.getJSONArray("jobs");
for (int i = 0; i < jobResults.length(); i++) {
//check custom data to find job that was for build
JSONObject jobData = jobResults.getJSONObject(i);
if (!jobData.isNull("build")) {
String buildResultKey = jobData.getString("build");
if (buildResultKey.equals(build.toString())) {
String jobId = jobData.getString("id");
JobInformation information = new JobInformation(jobId, calcHMAC(username, accessKey, jobId));
String status = jobData.getString("passed");
if (status.equals("null")) {
status = "not set";
}
information.setStatus(status);
information.setName(jobData.getString("name"));
jobInformation.add(information);
}
String jobId = jobData.getString("id");
JobInformation information = new JobInformation(jobId, calcHMAC(username, accessKey, jobId));
String status = jobData.getString("passed");
if (status.equals("null")) {
status = "not set";
}
information.setStatus(status);
information.setName(jobData.getString("name"));
jobInformation.add(information);
}
return jobInformation;
}
Expand All @@ -125,7 +121,7 @@ public void doJobReport(StaplerRequest req, StaplerResponse rsp)

ById byId = new ById(req.getParameter("jobId"));
try {
req.getView(byId,"index.jelly").forward(req,rsp);
req.getView(byId, "index.jelly").forward(req, rsp);
} catch (ServletException e) {
throw new IOException(e);
}
Expand Down
Expand Up @@ -101,6 +101,7 @@ public class SauceOnDemandBuildWrapper extends BuildWrapper implements Serializa
public static final String SELENIUM_VERSION = "SELENIUM_VERSION";
private SauceOnDemandLogParser logParser;
private static final String JENKINS_BUILD_NUMBER = "JENKINS_BUILD_NUMBER";
private String httpsProtocol;


@DataBoundConstructor
Expand All @@ -109,13 +110,15 @@ public SauceOnDemandBuildWrapper(Credentials
SeleniumInformation seleniumInformation,
String seleniumHost,
String seleniumPort,
String httpsProtocol,
boolean enableSauceConnect,
boolean launchSauceConnectOnSlave) {
this.credentials = credentials;
this.seleniumInformation = seleniumInformation;
this.enableSauceConnect = enableSauceConnect;
this.seleniumHost = seleniumHost;
this.seleniumPort = seleniumPort;
this.httpsProtocol = httpsProtocol;
if (seleniumInformation != null) {
this.seleniumBrowsers = seleniumInformation.getSeleniumBrowsers();
this.webDriverBrowsers = seleniumInformation.getWebDriverBrowsers();
Expand Down Expand Up @@ -150,7 +153,7 @@ public void buildEnvVars(Map<String, String> env) {

outputSeleniumVariables(env);
outputWebDriverVariables(env);
env.put(JENKINS_BUILD_NUMBER, build.toString());
env.put(JENKINS_BUILD_NUMBER, sanitiseBuildNumber(build.toString()));
env.put(SAUCE_USERNAME, getUserName());
env.put(SAUCE_API_KEY, getApiKey());
env.put(SELENIUM_HOST, getHostName());
Expand All @@ -166,58 +169,55 @@ private void outputSeleniumVariables(Map<String, String> env) {
if (seleniumBrowsers != null && !seleniumBrowsers.isEmpty()) {
if (seleniumBrowsers.size() == 1) {
Browser browserInstance = BrowserFactory.getInstance().seleniumBrowserForKey(seleniumBrowsers.get(0));
env.put(SELENIUM_PLATFORM, browserInstance.getPlatform().toString());
env.put(SELENIUM_BROWSER, browserInstance.getBrowserName());
env.put(SELENIUM_VERSION, browserInstance.getVersion());
env.put(SELENIUM_DRIVER, browserInstance.getUri());
outputEnvironmentVariablesForBrowser(env, browserInstance);
}

JSONArray browsersJSON = new JSONArray();
for (String browser : seleniumBrowsers) {
Browser browserInstance = BrowserFactory.getInstance().seleniumBrowserForKey(browser);
JSONObject config = new JSONObject();
try {
config.put("os", browserInstance.getPlatform().toString());
config.put("browser", browserInstance.getBrowserName());
config.put("browser-version", browserInstance.getVersion());
config.put("url", browserInstance.getUri());
} catch (JSONException e) {
logger.log(Level.SEVERE, "Unable to create JSON Object", e);
}
browsersJSON.put(config);
browserAsJSON(browsersJSON, browserInstance);
}
env.put(SAUCE_ONDEMAND_BROWSERS, StringEscapeUtils.escapeJava(browsersJSON.toString()));
env.put(SAUCE_ONDEMAND_BROWSERS, browsersJSON.toString());
}
}

private void outputEnvironmentVariablesForBrowser(Map<String, String> env, Browser browserInstance) {
env.put(SELENIUM_PLATFORM, browserInstance.getPlatform().toString());
env.put(SELENIUM_BROWSER, browserInstance.getBrowserName());
env.put(SELENIUM_VERSION, browserInstance.getVersion());
env.put(SELENIUM_DRIVER, browserInstance.getUri());
}

private void outputWebDriverVariables(Map<String, String> env) {
if (webDriverBrowsers != null && !webDriverBrowsers.isEmpty()) {
if (webDriverBrowsers.size() == 1) {
Browser browserInstance = BrowserFactory.getInstance().webDriverBrowserForKey(webDriverBrowsers.get(0));
env.put(SELENIUM_PLATFORM, browserInstance.getPlatform().toString());
env.put(SELENIUM_BROWSER, browserInstance.getBrowserName());
env.put(SELENIUM_VERSION, browserInstance.getVersion());
env.put(SELENIUM_DRIVER, browserInstance.getUri());
outputEnvironmentVariablesForBrowser(env, browserInstance);
}

JSONArray browsersJSON = new JSONArray();
for (String browser : webDriverBrowsers) {
Browser browserInstance = BrowserFactory.getInstance().webDriverBrowserForKey(browser);
JSONObject config = new JSONObject();
try {
config.put("os", browserInstance.getPlatform().toString());
config.put("browser", browserInstance.getBrowserName());
config.put("browser-version", browserInstance.getVersion());
config.put("url", browserInstance.getUri());
} catch (JSONException e) {
logger.log(Level.SEVERE, "Unable to create JSON Object", e);
}
browsersJSON.put(config);
browserAsJSON(browsersJSON, browserInstance);
}
env.put(SAUCE_ONDEMAND_BROWSERS, StringEscapeUtils.escapeJava(browsersJSON.toString()));
env.put(SAUCE_ONDEMAND_BROWSERS, browsersJSON.toString());
}
}

private void browserAsJSON(JSONArray browsersJSON, Browser browserInstance) {
JSONObject config = new JSONObject();
try {
config.put("os", browserInstance.getOs());
config.put("platform", browserInstance.getPlatform().toString());
config.put("browser", browserInstance.getBrowserName());
config.put("browser-version", browserInstance.getVersion());
config.put("url", browserInstance.getUri());
} catch (JSONException e) {
logger.log(Level.SEVERE, "Unable to create JSON Object", e);
}
browsersJSON.put(config);
}

private String getHostName() {
if (StringUtils.isNotBlank(seleniumHost)) {
Matcher matcher = ENVIRONMENT_VARIABLE_PATTERN.matcher(seleniumHost);
Expand Down Expand Up @@ -283,7 +283,7 @@ private void processBuildOutput(AbstractBuild build) {
updates.put("name", jobName);
}
updates.put("public", false);
updates.put("build", build.toString());
updates.put("build", sanitiseBuildNumber(build.toString()));
sauceREST.updateJobInfo(id, updates);
} catch (IOException e) {
logger.log(Level.WARNING, "Error while updating job " + id, e);
Expand All @@ -293,6 +293,15 @@ private void processBuildOutput(AbstractBuild build) {
}
}

/**
* Replace all spaces and hashes with underscores.
* @param buildNumber
* @return
*/
public static String sanitiseBuildNumber(String buildNumber) {
return buildNumber.replaceAll(" ", "_").replaceAll("#", "_");
}

private String getCurrentHostName() {
try {
String hostName = Computer.currentComputer().getHostName();
Expand Down Expand Up @@ -455,6 +464,14 @@ public void setLaunchSauceConnectOnSlave(boolean launchSauceConnectOnSlave) {
this.launchSauceConnectOnSlave = launchSauceConnectOnSlave;
}

public String getHttpsProtocol() {
return httpsProtocol;
}

public void setHttpsProtocol(String httpsProtocol) {
this.httpsProtocol = httpsProtocol;
}

@Override
public OutputStream decorateLogger(AbstractBuild build, OutputStream logger) throws IOException, InterruptedException, Run.RunnerAbortedException {
this.logParser = new SauceOnDemandLogParser(logger, build.getCharset());
Expand Down Expand Up @@ -523,7 +540,7 @@ public ITunnelHolder call() throws IOException {
SauceTunnelManager sauceManager = null;
try {
sauceManager = HudsonSauceManagerFactory.getInstance().createSauceConnectManager();
Process process = sauceManager.openConnection(username, key, port, sauceConnectJar, listener.getLogger());
Process process = sauceManager.openConnection(username, key, port, sauceConnectJar, httpsProtocol, listener.getLogger());
return tunnelHolder;
} catch (ComponentLookupException e) {
throw new IOException(e);
Expand Down
Expand Up @@ -88,7 +88,7 @@ public SauceOnDemandReportFactory getTestData(AbstractBuild<?, ?> build, Launche
if (jsonObject.get("name").equals(JSONObject.NULL)) {
updates.put("name", id[1]);
}
updates.put("build", build.toString());
updates.put("build", SauceOnDemandBuildWrapper.sanitiseBuildNumber(build.toString()));
sauceREST.updateJobInfo(id[0], updates);
} catch (IOException e) {
e.printStackTrace(buildListener.error("Error while updating job " + id));
Expand Down
@@ -0,0 +1,53 @@
package hudson.plugins.sauce_ondemand;

import com.saucelabs.ci.SeleniumBuilderManager;
import hudson.Extension;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.model.Descriptor;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.Builder;
import org.kohsuke.stapler.DataBoundConstructor;

import java.io.IOException;

/**
* @author Ross Rowe
*/
public class SeleniumBuilderBuilder extends Builder {

private String scriptFile;

@DataBoundConstructor
public SeleniumBuilderBuilder(String scriptFile) {
this.scriptFile = scriptFile;
}

@Override
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
SeleniumBuilderManager seleniumBuilderManager = new SeleniumBuilderManager();
seleniumBuilderManager.executeSeleniumBuilder(false, getScriptFile());

return true;
}

public String getScriptFile() {
return scriptFile;
}

@Extension
public static final class DescriptorImpl extends BuildStepDescriptor<Builder> {

@Override
public String getDisplayName() {
return "Invoke Selenium Builder script";
}

@Override
public boolean isApplicable(Class<? extends AbstractProject> jobType) {
return true;
}
}
}
Expand Up @@ -71,6 +71,9 @@
<f:entry title="${%Sauce OnDemand Port}" field="seleniumPort">
<f:textbox/>
</f:entry>
<f:entry title="${%HTTPS Protocols}" field="httpsProtocol">
<f:textbox/>
</f:entry>
</f:advanced>
</f:section>
</f:block>
Expand Down
@@ -0,0 +1,11 @@
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout"
xmlns:t="/lib/hudson" xmlns:f="/lib/form">

<f:block>
<f:section title="Selenium Builder Options">
<f:entry title="${%Blah Script File}" field="scriptFile">
<f:textbox id="scriptFile"/>
</f:entry>
</f:section>
</f:block>
</j:jelly>

1 comment on commit c3047f5

@buildhive
Copy link

Choose a reason for hiding this comment

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

Jenkins » sauce-ondemand-plugin #58 FAILURE
Looks like this commit caused a build failure
(what's this?)

Please sign in to comment.