/*
* The MIT License
*
* Copyright (c) 2009, Ushus Technologies LTD.,Shinod K Mohandas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.plugins.postbuildtask;
import hudson.Launcher;
import hudson.model.AbstractProject;
import hudson.model.AbstractBuild;
import hudson.model.Action;
import hudson.model.BuildListener;
import hudson.model.Descriptor;
import hudson.model.Job;
import hudson.model.JobProperty;
import hudson.model.JobPropertyDescriptor;
import hudson.model.Result;
import hudson.util.EditDistance;
import org.kohsuke.stapler.StaplerRequest;
import hudson.tasks.BatchFile;
import hudson.tasks.CommandInterpreter;
import hudson.tasks.Shell;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.IOException;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import hudson.tasks.Publisher;
/**
* Post build tasks added as {@link Publisher}.
*
*
* @author Shinod Mohandas
*/
public class PostbuildTask extends Publisher {
private volatile TaskProperties[] tasks;
public PostbuildTask(TaskProperties... tasks) {
this.tasks = tasks;
}
public PostbuildTask(Collection<TaskProperties> tasks) {
this((TaskProperties[]) tasks.toArray(new TaskProperties[tasks.size()]));
}
/**
* This method will return the taskProperties foe the specified logText
*
* @return TaskProperties[]
*/
// TODO need to finish later
public TaskProperties[] getAllTasks() {
return tasks;
}
/**
* This method will return all the tasks
*
* @return List<TaskProperties>
*/
public List<TaskProperties> getTasks() {
if (tasks == null)
return new ArrayList<TaskProperties>();
else
return Collections.unmodifiableList(Arrays.asList(tasks));
}
@Override
public boolean perform(AbstractBuild build, Launcher launcher,
BuildListener listener) throws InterruptedException, IOException {
String buildLog = build.getLog();
listener.getLogger().println("Performing Post build task...");
Result pr = build.getResult();
try {
for (int i = 0; i < tasks.length; i++) {
TaskProperties taskProperties = tasks[i];
String script = taskProperties.script;
if (checkLogTextMatch(taskProperties.getLogProperties(),
buildLog, listener)) {
listener.getLogger().println(
"Logical operation result is TRUE");
/*script = getGroupedScript(taskProperties
.getLogProperties(), taskProperties.script, buildLog);*/
if (taskProperties.getRunIfJobSuccessful() && pr!=null && pr.isWorseThan(Result.UNSTABLE)) {
listener.getLogger().println("Skipping post build task "+i+" - job status is worse than unstable : "+build.getResult());
continue;
}
listener.getLogger().println("Running script : " + script);
CommandInterpreter runner = getCommandInterpreter(launcher,
script);
Result result = runner.perform(build, launcher, listener) ? Result.SUCCESS
: Result.FAILURE;
listener.getLogger().println(
"POST BUILD TASK : " + result.toString());
listener.getLogger().println(
"END OF POST BUILD TASK : " + i);
if((result == Result.FAILURE) && (taskProperties.getEscalateStatus())){
listener.getLogger().println("ESCALATE FAILED POST BUILD TASK TO JOB STATUS");
build.setResult(Result.FAILURE);
}
} else {
listener.getLogger().println(
"Logical operation result is FALSE");
listener.getLogger()
.println("Skipping script : " + script);
listener.getLogger().println(
"END OF POST BUILD TASK : " + i);
}
}
} catch (Exception e) {
listener.getLogger().println(
"Exception when executing the batch command : "
+ e.getMessage());
return false;
}
return true;
}
private String getGroupedScript(LogProperties[] logTexts, String script,
String buildLog) {
StringBuilder appendedLogs = new StringBuilder();
for (int i = 0; i < logTexts.length; i++) {
LogProperties logInfo = logTexts[i];
Pattern pattern = Pattern.compile(logInfo.getLogText());
Matcher matcher = pattern.matcher(buildLog);
for (int k = 0; k < matcher.groupCount(); k++) {
script = script.replace("%" + k, matcher.group(k));
}
}
return script;
}
private boolean checkLogTextMatch(LogProperties[] logTexts,
String buildLog, BuildListener listener) {
boolean logmatch = false;
boolean match1 = false;
boolean match2 = false;
String operator1 = "";
for (int i = 0; i < logTexts.length; i++) {
LogProperties logInfo = logTexts[i];
String logText = logInfo.getLogText();
String operator = logInfo.getOperator();
match1 = isMatching(buildLog, logText, listener);
if (i != 0) {
match1 = doOperation(logmatch, match1, operator1);
} else {
logmatch = match1;
}
i++;
if (i < logTexts.length) {
LogProperties logInfo1 = logTexts[i];
String logText1 = logInfo1.getLogText();
operator1 = logInfo1.getOperator();
match2 = isMatching(buildLog, logText1, listener);
logmatch = doOperation(match1, match2, operator);
} else {
logmatch = match1;
}
}
return logmatch;
}
private boolean doOperation(boolean match1, boolean match2, String operation) {
if (operation.equals("AND"))
return (match1 & match2);
else
return (match1 | match2);
}
private boolean isMatching(String buildLog, String logText,
BuildListener listener) {
Pattern pattern = Pattern.compile(logText);
Matcher matcher = pattern.matcher(buildLog);
boolean match = matcher.find();
if (match) {
listener.getLogger().println(
"Match found for :" + logText + " : True");
} else {
listener.getLogger().println(
"Could not match :" + logText + " : False");
}
return match;
}
/**
* This method will return the command intercepter as per the node OS
*
* @param launcher
* @param script
* @return CommandInterpreter
*/
private CommandInterpreter getCommandInterpreter(Launcher launcher,
String script) {
if (launcher.isUnix())
return new Shell(script);
else
return new BatchFile(script);
}
/**
* This method will return the descriptorobject.
*
* @return DESCRIPTOR
*/
public DescriptorImpl getDescriptor() {
return DESCRIPTOR;
}
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
public static final class DescriptorImpl extends Descriptor<Publisher> {
public DescriptorImpl() {
super(PostbuildTask.class);
load();
}
public boolean isApplicable(Class<? extends Job> jobType) {
return AbstractProject.class.isAssignableFrom(jobType);
}
@Override
public String getDisplayName() {
return "Post build task";
}
@Override
public String getHelpFile() {
return "/plugin/postbuild-task/help/main.html";
}
public PostbuildTask newInstance(StaplerRequest req)
throws FormException {
// if(req.getParameter("postbuild-task.")!=null)
List<LogProperties> logprops = req.bindParametersToList(
LogProperties.class, "postbuild-task.logProperties.");
List<TaskProperties> tasksprops = req.bindParametersToList(
TaskProperties.class, "postbuild-task.taskpropertes.");
for (Iterator iterator = tasksprops.iterator(); iterator.hasNext();) {
TaskProperties taskProperties = (TaskProperties) iterator
.next();
List<LogProperties> logPropsList = new ArrayList<LogProperties>();
for (Iterator iterator2 = logprops.iterator(); iterator2
.hasNext();) {
LogProperties logProperties = (LogProperties) iterator2
.next();
if (!logProperties.getLogText().equals("@$#endofblock")) {
logPropsList.add(logProperties);
} else {
logprops.remove(logProperties);
logprops.removeAll(logPropsList);
break;
}
}
taskProperties.setLogTexts((LogProperties[]) logPropsList
.toArray(new LogProperties[logPropsList.size()]));
}
return new PostbuildTask(tasksprops);
}
}
}