Skip to content

Commit

Permalink
Fix JENKINS-12888
Browse files Browse the repository at this point in the history
  • Loading branch information
gboissinot committed Feb 26, 2012
1 parent d79cd94 commit ed9a90b
Show file tree
Hide file tree
Showing 6 changed files with 312 additions and 26 deletions.
83 changes: 59 additions & 24 deletions src/main/java/org/jenkinsci/lib/xtrigger/AbstractTrigger.java
Expand Up @@ -7,24 +7,25 @@
import hudson.triggers.Trigger;
import hudson.util.NullStream;
import hudson.util.StreamTaskListener;
import org.apache.commons.io.FileUtils;
import org.jenkinsci.lib.envinject.EnvInjectException;
import org.jenkinsci.lib.envinject.service.EnvVarsResolver;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.text.DateFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.logging.Level;
import java.util.logging.Logger;


/**
* @author Gregory Boissinot
*/
public abstract class AbstractTrigger extends Trigger<BuildableItem> implements Serializable {

private static Logger LOGGER = Logger.getLogger(AbstractTrigger.class.getName());
protected static Logger LOGGER = Logger.getLogger(AbstractTrigger.class.getName());

protected transient boolean offlineSlaveOnStartup = false;

Expand All @@ -33,7 +34,7 @@ public abstract class AbstractTrigger extends Trigger<BuildableItem> implements
* Calls an implementation trigger
*
* @param cronTabSpec the scheduler value
* @throws ANTLRException
* @throws antlr.ANTLRException
*/
public AbstractTrigger(String cronTabSpec) throws ANTLRException {
super(cronTabSpec);
Expand All @@ -53,28 +54,38 @@ public AbstractTrigger(String cronTabSpec) throws ANTLRException {
*/
protected abstract boolean requiresWorkspaceForPolling();


@Override
public void start(BuildableItem project, boolean newInstance) {
super.start(project, newInstance);

XTriggerLog log = new XTriggerLog(new StreamTaskListener(new NullStream()));
Node launcherNode = getPollingNode(log);
if (launcherNode == null) {
log.info("Can't find any complete active node. Checking again in next polling schedule.");
Node pollingNode = getPollingNode(log);
if (pollingNode == null) {
log.info("Can't find any complete active node.");
log.info("Checking again in next polling schedule.");
offlineSlaveOnStartup = true;
return;
}
if (launcherNode.getRootPath() == null) {
log.info("The running slave might be offline at the moment. Waiting for next schedule.");

if (pollingNode.getRootPath() == null) {
log.info("The running slave might be offline at the moment.");
log.info("Waiting for next schedule.");
offlineSlaveOnStartup = true;
return;
}

start(launcherNode, project, newInstance, log);
try {
start(pollingNode, project, newInstance, log);
} catch (XTriggerException xe) {
LOGGER.log(Level.SEVERE, "Can't initialize trigger", xe);
}
}

protected abstract void start(Node pollingNode, BuildableItem project, boolean newInstance, XTriggerLog log);
/**
* Can be overridden if needed
*/
protected void start(Node pollingNode, BuildableItem project, boolean newInstance, XTriggerLog log) throws XTriggerException {
}

@SuppressWarnings("unused")
protected String resolveEnvVars(String value, AbstractProject project, Node node) throws XTriggerException {
Expand All @@ -90,19 +101,23 @@ protected String resolveEnvVars(String value, AbstractProject project, Node node

@Override
public void run() {
AbstractProject project = (AbstractProject) job;
XTriggerDescriptor descriptor = getDescriptor();
ExecutorService executorService = descriptor.getExecutor();
StreamTaskListener listener;
try {
listener = new StreamTaskListener(getLogFile());
XTriggerLog log = new XTriggerLog(listener);
if (!Hudson.getInstance().isQuietingDown() && ((AbstractProject) job).isBuildable()) {
if (Hudson.getInstance().isQuietingDown()) {
log.info("Jenkins is quieting down.");
} else if (!project.isBuildable()) {
log.info("The job is not buildable. Activate it to poll again.");
} else if (project.isBuilding()) {
log.info("The job is building. Waiting for next poll.");
} else {
Runner runner = new Runner(getName(), log);
executorService.execute(runner);
} else {
log.info("Jenkins is quieting down or the job is not buildable.");
}

} catch (Throwable t) {
LOGGER.log(Level.SEVERE, "Severe Error during the trigger execution " + t.getMessage());
t.printStackTrace();
Expand Down Expand Up @@ -131,31 +146,37 @@ public Runner(String triggerName, XTriggerLog log) {

@Override
public void run() {

long start = System.currentTimeMillis();
log.info("Polling started on " + DateFormat.getDateTimeInstance().format(new Date(start)));
log.info("Polling for the job " + job.getName());

try {
log.info("Polling for the job " + job.getName());

Node pollingNode = getPollingNode(log);
if (pollingNode == null) {
log.info("Can't find any complete active node for the polling action. Maybe slaves are not yet active at this time or the number of executor of the master is 0. Checking again in next polling schedule.");
log.info("Can't find any complete active node for the polling action.");
log.info("Maybe slaves are not yet active at this time or the number of executor of the master is 0.");
log.info("Checking again in next polling schedule.");
return;
}

if (pollingNode.getRootPath() == null) {
log.info("The running slave might be offline at the moment. Waiting for next schedule.");
log.info("The running slave might be offline at the moment.");
log.info("Waiting for next schedule.");
return;
}

displayPollingNode(pollingNode, log);

long start = System.currentTimeMillis();
log.info("Polling started on " + DateFormat.getDateTimeInstance().format(new Date(start)));
//Check if there are modifications in the environment
boolean changed = checkIfModified(pollingNode, log);
log.info("\nPolling complete. Took " + Util.getTimeSpanString(System.currentTimeMillis() - start) + ".");

if (changed) {
log.info("Changes found. Scheduling a build.");
AbstractProject project = (AbstractProject) job;
project.scheduleBuild(0, new XTriggerCause(triggerName, getCause()), getScheduledActions(pollingNode, log));
project.scheduleBuild(0, new XTriggerCause(triggerName, getCause(), true), getScheduledXTriggerActions(pollingNode, log));
} else {
log.info("No changes.");
}
Expand All @@ -169,13 +190,27 @@ public void run() {
}
}

protected Action[] getScheduledXTriggerActions(Node pollingNode, XTriggerLog log) throws XTriggerException {
Action[] actions = getScheduledActions(pollingNode, log);
int nbNewAction = actions.length + 1;
Action[] newActions = new Action[nbNewAction];
for (int i = 0; i < actions.length; i++) {
newActions[i] = actions[i];
}
try {
newActions[newActions.length - 1] = new XTriggerCauseAction(FileUtils.readFileToString(getLogFile()));
} catch (IOException ioe) {
throw new XTriggerException(ioe);
}
return newActions;
}

protected abstract Action[] getScheduledActions(Node pollingNode, XTriggerLog log);

/**
* Checks if the new folder content has been modified
* The date time and the content file are used.
* Checks if there are modifications in the environment between last poll
*
* @return true if the new folder content has been modified
* @return true if there are modifications
*/
protected abstract boolean checkIfModified(Node pollingNode, XTriggerLog log) throws XTriggerException;

Expand Down
@@ -0,0 +1,66 @@
package org.jenkinsci.lib.xtrigger;

import antlr.ANTLRException;
import hudson.model.BuildableItem;
import hudson.model.Node;


/**
* @author Gregory Boissinot
*/
public abstract class AbstractTriggerByFullContext<C extends XTriggerContext> extends AbstractTrigger {

private transient C context;

/**
* Builds a trigger object
* Calls an implementation trigger
*
* @param cronTabSpec the scheduler value
* @throws ANTLRException
*/
public AbstractTriggerByFullContext(String cronTabSpec) throws ANTLRException {
super(cronTabSpec);
}

/**
* Can be overridden if needed
*/
@Override
protected void start(Node pollingNode, BuildableItem project, boolean newInstance, XTriggerLog log) throws XTriggerException {
context = getContext(pollingNode, log);
}

@Override
protected boolean checkIfModified(Node pollingNode, XTriggerLog log) throws XTriggerException {

C newContext = getContext(pollingNode, log);

if (offlineSlaveOnStartup) {
log.info("Slave(s) were offline at startup or at previous poll.");
log.info("Recording environment context and waiting for next schedule to check if there are modifications.");
offlineSlaveOnStartup = false;
setNewContext(newContext);
return false;
}

boolean changed = checkIfModified(context, newContext, log);
setNewContext(newContext);
return changed;
}


private void setNewContext(C context) {
this.context = context;
}

protected abstract C getContext(Node pollingNode, XTriggerLog log) throws XTriggerException;

/**
* Checks if there are modifications in the environment between last poll
*
* @return true if there are modifications
*/
protected abstract boolean checkIfModified(C oldContext, C newContext, XTriggerLog log) throws XTriggerException;

}
55 changes: 53 additions & 2 deletions src/main/java/org/jenkinsci/lib/xtrigger/XTriggerCause.java
@@ -1,27 +1,78 @@
package org.jenkinsci.lib.xtrigger;

import hudson.model.AbstractBuild;
import hudson.model.Cause;
import hudson.model.Hudson;
import hudson.remoting.Callable;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* @author Gregory Boissinot
*/
public class XTriggerCause extends Cause {

private static Logger LOGGER = Logger.getLogger(XTriggerCause.class.getName());

private String triggerName;

private String causeFrom;

protected XTriggerCause(String triggerName, String causeFrom) {
private boolean logEnabled;

protected XTriggerCause(String triggerName, String causeFrom, boolean logEnabled) {
this.triggerName = triggerName;
this.causeFrom = causeFrom;
this.logEnabled = logEnabled;
}

@Override
public void onAddedTo(final AbstractBuild build) {
final XTriggerCauseAction causeAction = build.getAction(XTriggerCauseAction.class);
if (causeAction != null) {
try {
Hudson.getInstance().getRootPath().act(new Callable<Void, XTriggerException>() {
@Override
public Void call() throws XTriggerException {
causeAction.setBuild(build);
File triggerLogFile = causeAction.getLogFile();
String logContent = causeAction.getLogMessage();
try {
FileUtils.writeStringToFile(triggerLogFile, logContent);
} catch (IOException ioe) {
throw new XTriggerException(ioe);
}
return null;
}
});
} catch (IOException ioe) {
LOGGER.log(Level.SEVERE, "Problem to attach cause object to build object.", ioe);
} catch (InterruptedException ie) {
LOGGER.log(Level.SEVERE, "Problem to attach cause object to build object.", ie);
} catch (XTriggerException xe) {
LOGGER.log(Level.SEVERE, "Problem to attach cause object to build object.", xe);
}
}
}

@Override
public String getShortDescription() {
if (causeFrom == null) {
return "[" + triggerName + "]";
} else {
} else if (!logEnabled) {
return String.format("[%s] %s", triggerName, causeFrom);
} else {
return String.format("[%s] %s (%s)", triggerName, causeFrom, "<a href=\"triggerCauseAction\">log</a>");
}
}

@SuppressWarnings("unused")
public String getTriggerName() {
return triggerName;
}

}

0 comments on commit ed9a90b

Please sign in to comment.