/* * Created on Apr 22, 2007 */ package hudson.plugins.im.bot; import hudson.Extension; import hudson.model.Item; import hudson.model.ParameterValue; import hudson.model.SimpleParameterDefinition; import hudson.model.AbstractProject; import hudson.model.Cause; import hudson.model.ParameterDefinition; import hudson.model.ParametersAction; import hudson.model.ParametersDefinitionProperty; import hudson.model.Queue; import hudson.plugins.im.IMCause; import hudson.plugins.im.Sender; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang.ArrayUtils; /** * Build command for the instant messaging bot. * * @author Pascal Bleser * @author kutzi */ @Extension public class BuildCommand extends AbstractTextSendingCommand { private static final Pattern NUMERIC_EXTRACTION_REGEX = Pattern.compile("^(\\d+)"); private static final String SYNTAX = " <job> [now|<delay>[s|m|h]] [<parameterkey>=<value>]*"; private static final String HELP = SYNTAX + " - schedule a job build, with standard, custom or no quiet period"; @Override public Collection<String> getCommandNames() { return Arrays.asList("build","schedule"); } /** * @return whether the build was actually scheduled */ private boolean scheduleBuild(Bot bot, AbstractProject<?, ?> project, int delaySeconds, Sender sender, List<ParameterValue> parameters) { String senderId = sender.getId(); if (senderId == null) { senderId = sender.getNickname(); } Cause cause = new IMCause("Started by " + bot.getImId() + " on request of '" + senderId + "'"); if (parameters.isEmpty()) { return project.scheduleBuild(delaySeconds, cause); } else { return project.scheduleBuild(delaySeconds, cause, new ParametersAction(parameters)); } } @Override public String getReply(Bot bot, Sender sender, String args[]) { if (args.length >= 2) { String jobName = args[1]; jobName = jobName.replaceAll("\"", ""); AbstractProject<?, ?> project = getJobProvider().getJobByNameOrDisplayName(jobName); if (project != null) { String checkPermission = checkPermission(sender, project); if (checkPermission != null) { return checkPermission; } StringBuilder reply = new StringBuilder(); if (!project.isBuildable()) { return sender.getNickname() + ": job " + jobName + " is disabled"; } else { int delay = project.getQuietPeriod(); List<ParameterValue> parameters = new ArrayList<ParameterValue>(); if (args.length >= 3) { int parametersStartIndex = 2; if (!args[2].contains("=")) { // otherwise looks like a parameter parametersStartIndex = 3; String delayStr = args[2].trim(); if ("now".equalsIgnoreCase(delayStr)) { delay = 0; } else { int multiplicator = 1; if (delayStr.endsWith("m") || delayStr.endsWith("min")) { multiplicator = 60; } else if (delayStr.endsWith("h")) { multiplicator = 3600; } else { char c = delayStr.charAt(delayStr.length() - 1); if (! (c == 's' || Character.isDigit(c))) { return giveSyntax(sender.getNickname(), args[0]); } } Matcher matcher = NUMERIC_EXTRACTION_REGEX.matcher(delayStr); if (matcher.find()) { int value = Integer.parseInt(matcher.group(1)); delay = multiplicator * value; } else { return giveSyntax(sender.getNickname(), args[0]); } } } if (parametersStartIndex < args.length) { String[] potentialParameters = (String[]) ArrayUtils.subarray(args, parametersStartIndex,args.length); parameters = parseBuildParameters(potentialParameters, project, reply); } } if (scheduleBuild(bot, project, delay, sender, parameters)) { if (delay == 0) { return reply.append(sender.getNickname() + ": job " + jobName + " build scheduled now").toString(); } else { return reply.append(sender.getNickname() + ": job " + jobName + " build scheduled with a quiet period of " + delay + " seconds").toString(); } } else { // probably already queued Queue.Item queueItem = project.getQueueItem(); if (queueItem != null) { return sender.getNickname() + ": job " + jobName + " is already in the build queue (" + queueItem.getWhy() + ")"; } else { // could be race condition (build left build-queue while we were checking) or other reason return sender.getNickname() + ": job " + jobName + " scheduling failed or already in build queue"; } } } } else { return giveSyntax(sender.getNickname(), args[0]); } } else { return sender.getNickname() + ": Error, syntax is: '" + args[0] + SYNTAX + "'"; } } List<ParameterValue> parseBuildParameters(String[] args, AbstractProject<?, ?> project, StringBuilder commandReply) { if (args.length > 0 && !project.isParameterized()) { commandReply.append("Ignoring parameters as project is not parametrized!\n"); return Collections.emptyList(); } else if (!project.isParameterized()) { return Collections.emptyList(); } // parse possible parameters from the command Map<String, String> parsedParameters = new HashMap<String, String>(); for (int i=0; i < args.length; i++) { String[] split = args[i].split("="); if (split.length == 2) { parsedParameters.put(split[0], split[1]); } else { commandReply.append("Unparseable parameter: " + args[i] + "\n"); } } List<ParameterValue> parameters = new ArrayList<ParameterValue>(); ParametersDefinitionProperty propDefs = project.getProperty(ParametersDefinitionProperty.class); for (ParameterDefinition pd : propDefs.getParameterDefinitions()) { if (pd.getName() != null && parsedParameters.containsKey(pd.getName())) { if (pd instanceof SimpleParameterDefinition) { SimpleParameterDefinition spd = (SimpleParameterDefinition) pd; parameters.add(spd.createValue(parsedParameters.get(pd.getName()))); } else { commandReply.append("Unsupported parameter type " + pd.getClass().getSimpleName() + " for parameter " + pd.getName() + "!\n"); } } else { ParameterValue pv = pd.getDefaultParameterValue(); if (pv != null) { parameters.add(pv); } } } return parameters; } private String checkPermission(Sender sender, AbstractProject<?, ?> project) { if (!project.hasPermission(Item.BUILD)) { return sender.getNickname() + ": you're not allowed to build job " + project.getDisplayName() + "!"; } return null; } private String giveSyntax(String sender, String cmd) { return sender + ": syntax is: '" + cmd + SYNTAX + "'"; } public String getHelp() { return HELP; } }