package org.thoughtslive.jenkins.plugins.hubot.config; import com.cloudbees.hudson.plugins.folder.AbstractFolder; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.Extension; import hudson.Util; import hudson.model.AbstractDescribableImpl; import hudson.model.Descriptor; import hudson.model.Item; import hudson.model.ItemGroup; import hudson.model.Job; import hudson.model.TaskListener; import hudson.model.User; import hudson.util.FormValidation; import java.io.IOException; import java.io.Serializable; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.List; import java.util.Map; import jenkins.model.Jenkins; import lombok.Builder; import lombok.Data; import org.apache.log4j.Logger; import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; import org.thoughtslive.jenkins.plugins.hubot.api.Message; import org.thoughtslive.jenkins.plugins.hubot.api.ResponseData; import org.thoughtslive.jenkins.plugins.hubot.config.notifications.Config; import org.thoughtslive.jenkins.plugins.hubot.config.notifications.Type; import org.thoughtslive.jenkins.plugins.hubot.service.HubotService; import org.thoughtslive.jenkins.plugins.hubot.util.Common; /** * Represents a configuration needed to connect to Hubot. * * @author Naresh Rayapati */ @Data @Builder public class HubotSite extends AbstractDescribableImpl<HubotSite> implements Serializable, Cloneable { private static final long serialVersionUID = -455439000126041809L; private static final Logger LOGGER = Logger.getLogger(HubotSite.class.getName()); private boolean defaultSite; private String name; private URL url; private String room; private String roomPrefix; private boolean failOnError; private boolean useFolderName; private List<Config> notifications; @DataBoundConstructor public HubotSite(final boolean defaultSite, final String name, final URL url, final String room, final String roomPrefix, final boolean failOnError, final boolean useFolderName, final List<Config> notifications) { this.defaultSite = defaultSite; this.name = Util.fixEmpty(name); this.url = url; this.room = room; this.roomPrefix = roomPrefix; this.failOnError = failOnError; this.useFolderName = useFolderName; this.notifications = notifications; } /** * Gets the effective {@link HubotSite} associated with the given project. * * @return null if no such was found. */ public static HubotSite get(Job<?, ?> job, final TaskListener listener) { HubotJobProperty jpp = job.getProperty(HubotJobProperty.class); boolean enableNotifications = false; String siteName = null; if (jpp != null) { enableNotifications = jpp.isEnableNotifications(); siteName = Util.fixEmpty(jpp.getSiteNames()); } if (enableNotifications) { return get(job, listener, siteName); } return null; } public static HubotSite get(final Job<?, ?> job, final TaskListener listener, final String siteName) { HubotSite hubotSite = null; HubotSite defaultSite = null; ItemGroup parent = job.getParent(); String folderName = null; // Site from folder(s). try { while (parent != null) { if (parent instanceof AbstractFolder) { AbstractFolder folder = (AbstractFolder) parent; if (folderName == null) { folderName = folder.getName(); } HubotFolderProperty jfp = (HubotFolderProperty) folder.getProperties() .get(HubotFolderProperty.class); if (jfp != null) { HubotSite[] sites = jfp.getSites(); if (sites != null && sites.length > 0) { for (HubotSite site : sites) { HubotSite cloneSite = site.clone(); if (cloneSite.isUseFolderName()) { cloneSite.setRoom(folder.getName()); } if (siteName != null) { if (cloneSite.getName().equalsIgnoreCase(siteName) && hubotSite == null) { hubotSite = cloneSite; } } else { if (cloneSite.isDefaultSite() && defaultSite == null) { defaultSite = cloneSite; } } } } } } if (parent instanceof Item) { parent = ((Item) parent).getParent(); } else { parent = null; } } // Global Sites. if (hubotSite == null && defaultSite == null) { for (HubotSite site : new GlobalConfig().getSites()) { HubotSite cloneSite = site.clone(); if (site.isUseFolderName()) { if (folderName != null) { cloneSite.setRoom(folderName); } } if (siteName != null) { if (cloneSite.getName().equalsIgnoreCase(siteName) && hubotSite == null) { hubotSite = cloneSite; } } else { if (cloneSite.isDefaultSite() && defaultSite == null) { defaultSite = cloneSite; } } } } } catch (Exception e) { LOGGER.error("Unable to get hubot site", e); } return hubotSite == null ? defaultSite : hubotSite; } @Override public HubotSite clone() throws CloneNotSupportedException { super.clone(); HubotSite site = HubotSite.builder().defaultSite(this.defaultSite).name(this.name).url(this.url) .room(this.room).roomPrefix(this.roomPrefix).failOnError(this.failOnError) .useFolderName(this.useFolderName).notifications(this.notifications).build(); return site; } @Extension public static class DescriptorImpl extends Descriptor<HubotSite> { @Override public String getDisplayName() { return "Hubot Site"; } /** * Checks if the site is valid and send a test message. */ @SuppressFBWarnings public FormValidation doValidate(@AncestorInPath Item project, @QueryParameter String name, @QueryParameter String url, @QueryParameter String room, @QueryParameter String roomPrefix, @QueryParameter boolean useFolderName) throws IOException { url = Util.fixEmpty(url); name = Util.fixEmpty(name); room = Util.fixEmpty(room); roomPrefix = Util.fixEmpty(roomPrefix); if (roomPrefix == null) { roomPrefix = ""; } if (name == null) { return FormValidation.error("Site name is empty or null."); } String folderName; String folderUrl; Map extraData = new HashMap<String, String>(); extraData.put("JENKINS_URL", Jenkins.getInstance().getRootUrl()); if (project instanceof AbstractFolder) { AbstractFolder folder = (AbstractFolder) project; folderName = folder.getName(); folderUrl = folder.getAbsoluteUrl(); extraData.put("FOLDER_URL", folderUrl); // Parent folder(s) sites. ItemGroup parent = project.getParent(); while (parent != null) { if (parent instanceof AbstractFolder) { AbstractFolder parentFolder = (AbstractFolder) parent; folderName = parentFolder.getName() + " ยป " + folderName; } if (parent instanceof Item) { parent = ((Item) parent).getParent(); } else { parent = null; } } extraData.put("FOLDER_NAME", folderName); } if (useFolderName) { if (project instanceof AbstractFolder) { AbstractFolder folder = (AbstractFolder) project; room = roomPrefix + folder.getName(); } else { if (room == null) { return FormValidation .error("Room Name is empty or null, is required for global config."); } } } else { if (room == null) { return FormValidation.error("Room Name is empty or null."); } } try { if (url == null) { return FormValidation.error("URL is empty or null."); } new URL(Common.sanitizeURL(url)); } catch (MalformedURLException e) { return FormValidation.error(String.format("Malformed URL (%s)", url), e); } String userName = "anonymous"; String userId = null; if (User.current() != null) { userName = User.current().getDisplayName(); userId = User.current().getId(); } try { final Message message = Message.builder().stepName(Common.STEP.TEST.name()) .message("Hubot Site: " + name + " configured successfully.") .ts(System.currentTimeMillis()).extraData(extraData) .userId(userId).userName(userName).status(Type.SUCCESS.name()).build(); HubotSite site = HubotSite.builder().room(room).url(new URL(Common.sanitizeURL(url))) .build(); HubotService service = new HubotService(site); ResponseData response = service.sendMessage(message); if (!response.isSuccessful()) { return FormValidation.error( "Hubot: Error while sending a test message - Error Code: " + response.getCode() + " Error Message: " + response.getError()); } return FormValidation .ok("Success - Please check hubot logs as well to make sure there isn't a problem with script!."); } catch (Exception e) { e.printStackTrace(); return FormValidation.error(String.format("Error while configuring site: %s", name), e); } } } }