package com.meyling.hudson.plugin.job_exporter;
import hudson.EnvVars;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Build;
import hudson.model.BuildListener;
import hudson.model.Cause;
import hudson.model.CauseAction;
import hudson.model.Computer;
import hudson.model.Executor;
import hudson.model.Hudson;
import hudson.model.Result;
import hudson.model.User;
import hudson.model.Cause.UserCause;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.Builder;
import hudson.tasks.Mailer;
import hudson.util.FormValidation;
import hudson.util.LogTaskListener;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
/**
* Export hudson job information into a properties file.
*
* <p>
* When the user configures the project and enables this builder,
* {@link DescriptorImpl#newInstance(StaplerRequest)} is invoked
* and a new {@link ExporterBuilder} is created. The created
* instance is persisted to the project configuration XML by using
* XStream, so this allows you to use instance fields
* to remember the configuration.
*
* <p>
* When a build is performed, the {@link #perform(Build, Launcher, BuildListener)} method
* will be invoked.
*
* @author Michael Meyling
*/
public class ExporterBuilder extends Builder {
@DataBoundConstructor
public ExporterBuilder() {
}
@Override
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) {
// this is where you 'build' the project
String prefix = "build.";
Properties export = new Properties();
try {
System.out.println(Computer.currentComputer().getHostName());
export.put(prefix + "hudson.version", StringUtils.defaultString(build.getHudsonVersion()));
export.put(prefix + "id", StringUtils.defaultString(build.getId()));
Executor executor = build.getExecutor();
if (executor != null) {
export.put(prefix + "summary", StringUtils.defaultString(build.getExecutor().getName()));
}
export.put(prefix + "number", "" + build.getNumber());
EnvVars env = build.getEnvironment(new LogTaskListener(Logger.getLogger(this.getClass().getName()), Level.INFO));
if (env != null) {
export.put(prefix + "jobName", StringUtils.defaultString(env.get("JOB_NAME")));
export.put(prefix + "cvsBranch", StringUtils.defaultString(env.get("CVS_BRANCH")));
}
log(listener.getLogger(), "exporting properties");
Mailer.DescriptorImpl descriptor = (Mailer.DescriptorImpl) Hudson.getInstance().getDescriptorByType(
Mailer.DescriptorImpl.class);
export.put(prefix + "admin.emailAddress", descriptor.getAdminAddress());
// set admin email address as fallback, if we don't get a user email address
export.put(prefix + "user.emailAddress", descriptor.getAdminAddress());
// now we iterate over the cause actions to identify the user and get his properties
List<CauseAction> cal = build.getActions(CauseAction.class);
for (CauseAction ca : cal) {
log(listener.getLogger(), ca.getDisplayName());
log(listener.getLogger(), ca.toString());
List<Cause> cl = ca.getCauses();
for (Cause c : cl) {
if (c instanceof UserCause) {
UserCause uc = (UserCause) c;
export.put(prefix + "user.name", StringUtils.defaultString(uc.getUserName()));
User u = User.get(uc.getUserName());
export.put(prefix + "user.fullName", StringUtils.defaultString(u.getFullName()));
Mailer.UserProperty umail = u.getProperty(Mailer.UserProperty.class);
String email = StringUtils.defaultString(umail.getAddress()).trim();
if (email.length() > 0) {
export.put(prefix + "user.emailAddress", email);
}
}
}
}
FilePath ws = build.getProject().getWorkspace();
FilePath hudson = ws.child("hudsonBuild.properties");
if (hudson.exists()) {
if (!hudson.delete()) {
log(listener.getLogger(), "old file can not be deleted: " + hudson);
build.setResult(Result.FAILURE);
return false;
} else {
log(listener.getLogger(), "old file deleted: " + hudson);
}
}
OutputStream out = hudson.write();
export.store(out, "created by " + this.getClass().getName());
out.close();
log(listener.getLogger(), "new properties file written: " + hudson);
} catch (IOException e) {
e.printStackTrace(listener.error("failed to read or write property file"));
build.setResult(Result.FAILURE);
return false;
} catch (InterruptedException e) {
e.printStackTrace(listener.error("failed to read or write property file"));
build.setResult(Result.FAILURE);
return false;
}
return true;
}
protected void log(final PrintStream logger, final String message) {
logger.println("[exporter] " + StringUtils.defaultString(message));
}
// overrided for better type safety.
// if your plugin doesn't really define any property on Descriptor,
// you don't have to do this.
@Override
public DescriptorImpl getDescriptor() {
return (DescriptorImpl)super.getDescriptor();
}
/**
* Descriptor for {@link ExporterBuilder}. Used as a singleton.
* The class is marked as public so that it can be accessed from views.
*
* <p>
* See <tt>views/hudson/plugins/exporter/ExporterBuilder/*.jelly</tt>
* for the actual HTML fragment for the configuration screen.
*/
@Extension // this marker indicates Hudson that this is an implementation of an extension point.
public static final class DescriptorImpl extends BuildStepDescriptor<Builder> {
// To persist global configuration information,
// simply store it in a field and call save().
// If you don't want fields to be persisted, use <tt>transient</tt>.
/**
* Performs on-the-fly validation of the form field 'name'.
*
* @param value
* This parameter receives the value that the user has typed.
* @return
* Indicates the outcome of the validation. This is sent to the browser.
*/
public FormValidation doCheckName(@QueryParameter String value) throws IOException, ServletException {
if(value.length()==0)
return FormValidation.error("Please set a name");
if(value.length()<4)
return FormValidation.warning("Isn't the name too short?");
return FormValidation.ok();
}
public boolean isApplicable(Class<? extends AbstractProject> aClass) {
// indicates that this builder can be used with all kinds of project types
return true;
}
/**
* This human readable name is used in the configuration screen.
*/
public String getDisplayName() {
return "Export job runtime parameters";
}
@Override
public boolean configure(StaplerRequest req, JSONObject o) throws FormException {
// to persist global configuration information,
// set that to properties and call save().
// still nothing to do for us
save();
return super.configure(req, o);
}
}
}