package HudsonWindmill;
import hudson.Launcher;
import hudson.Util;
import hudson.model.AbstractBuild;
import hudson.model.BuildListener;
import hudson.model.Descriptor;
import hudson.tasks.Builder;
import hudson.model.Result;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;
import java.io.IOException;
import java.util.Map;
/**
* Sample {@link Builder}.
*
* <p>
* When the user configures the project and enables this builder,
* {@link DescriptorImpl#newInstance(StaplerRequest)} is invoked
* and a new {@link HelloWorldBuilder} is created. The created
* instance is persisted to the project configuration XML by using
* XStream, so this allows you to use instance fields (like {@link #name})
* to remember the configuration.
*
* <p>
* When a build is performed, the {@link #perform(Build, Launcher, BuildListener)} method
* will be invoked.
*
* @author admc
*/
public class WindmillBuilder extends Builder {
private String browser;
private final String startURL;
private final String tests;
private final String port;
private final String other;
private final boolean enablessl;
@DataBoundConstructor
public WindmillBuilder(String browser, String startURL, String tests, String port, String other, boolean enablessl) {
this.browser = browser;
this.startURL = startURL;
this.tests = tests;
this.port = port;
this.other = other;
this.enablessl = enablessl;
}
/**
* We'll use this from the <tt>config.jelly</tt>.
*/
public String getBrowser() {
return browser;
}
public String setBrowser(String browser) {
this.browser = browser;
return this.browser;
}
public String getStartURL() {
return startURL;
}
public String getTests() {
return tests;
}
public String getPort() {
return port;
}
public String getOther() {
return other;
}
public boolean getEnablessl(){
return enablessl;
}
public String buildCommand(){
if (browser.equals("")){
browser = "firefox";
}
String runner = "";
if (port.equals("") || port.equals("4444")){
runner = "windmill "+ browser + " " + startURL + " test=" + tests + " exit " + other;
} else {
runner = "windmill "+ browser + " " + startURL + " test=" + tests + " port="+port + " exit " + other;
}
if (enablessl){
runner += " ssl";
}
return runner;
}
@Override
public boolean perform(AbstractBuild<?,?> build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException {
// this is where you 'build' the project
//We don't need to show the port if it's the default
int exitCode = 0;
if (this.getTests().equals("")){
listener.error("Windmill can't run without any tests...");
build.setResult(Result.FAILURE);
}
else if (this.getStartURL().equals("")){
listener.error("Windmill requires that you provide a starting URL...");
build.setResult(Result.FAILURE);
}
else {
Map<String,String> envVars = build.getEnvironment(listener);
envVars.putAll(build.getBuildVariables());
//if there is a dynamically set browser, use that
if (envVars.containsKey("browser")){
this.setBrowser(envVars.get("browser"));
}
//build the exec string
String cmd = this.buildCommand();
//do magical replacement of %ACCOUNT% string
if (cmd.contains("%ACCOUNT%")){
if (browser.equals("firefox")){
cmd = cmd.replaceAll("%ACCOUNT%", "1");
}
else {
cmd = cmd.replaceAll("%ACCOUNT%", "2");
}
}
if (DESCRIPTOR.cleanup()){
try {
launcher.launch().cmds("clean_run.py", "windmill", browser).envs(envVars).stdout(listener).pwd(build.getWorkspace()).join();
}
catch(IOException e){
//do nothing because it's alright
}
}
//listener.getLogger().println("Starting Windmill Test Run\n" +cmd);
exitCode = launcher.launch().cmds(Util.tokenize(cmd)).envs(envVars).stdout(listener).pwd(build.getWorkspace()).join();
}
if (exitCode != 0){
build.setResult(Result.UNSTABLE);
}
return true;
}
/**
* Descriptor should be singleton.
*/
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
/**
* Descriptor for {@link HelloWorldBuilder}. Used as a singleton.
* The class is marked as public so that it can be accessed from views.
*
* <p>
* See <tt>views/hudson/plugins/hello_world/HelloWorldBuilder/*.jelly</tt>
* for the actual HTML fragment for the configuration screen.
*/
public static final class DescriptorImpl extends Descriptor<Builder> {
/**
* To persist global configuration information,
* simply store it in a field and call save().
*
* <p>
* If you don't want fields to be persisted, use <tt>transient</tt>.
*/
private boolean cleanup = true;
DescriptorImpl() {
super(WindmillBuilder.class);
}
/**
* Performs on-the-fly validation of the form field 'name'.
*
* @param value
* This receives the current value of the field.
*/
// public FormValidation doCheckBrowser(@QueryParameter final String value) {
// /**
// * The real check goes here. In the end, depending on which
// * method you call, the browser shows text differently.
// */
// if(value==null || value.length()==0)
// return FormValidation.error("Please set a name");
// else
// if(value.length()<1)
// return FormValidation.warning("Isn't the name too short?");
// else
// return FormValidation.ok();
// }
/**
* This human readable name is used in the configuration screen.
*/
@Override
public String getDisplayName() {
return "Windmill Test";
}
@Override
public boolean configure(StaplerRequest req, JSONObject o) throws FormException {
// to persist global configuration information,
// set that to properties and call save().
cleanup = o.getBoolean("cleanup");
save();
return super.configure(req, o);
}
/**
* This method returns true if the global configuration says we should speak
*/
public boolean cleanup() {
return cleanup;
}
}
}