Index: src/main/resources/hudson/plugins/accurev/AccurevSCM/global.jelly =================================================================== --- src/main/resources/hudson/plugins/accurev/AccurevSCM/global.jelly (revision 20179) +++ src/main/resources/hudson/plugins/accurev/AccurevSCM/global.jelly Mon Jul 27 17:54:18 CEST 2009 @@ -26,6 +26,10 @@ + + + Index: src/main/webapp/help/validTransactionTypes.html =================================================================== --- src/main/webapp/help/validTransactionTypes.html Mon Jul 27 17:54:50 CEST 2009 +++ src/main/webapp/help/validTransactionTypes.html Mon Jul 27 17:54:50 CEST 2009 @@ -0,0 +1,27 @@ +
+ WARNING: By changing the valid types of transactions you can miss vital changes made to your source code.
+

+ By default, the AccuRev-plugin will allow any type of transaction to trigger a build.

+ This behaviour is not always wanted, resulting in issue-triggered builds.
+
+ To solve this you specify the types of transactions that you want to use.
+ You enter the transaction types separated by semicolons like this

+ add;chstream;co;defcomp;defunct;keep;mkstream;move;promote;purge

+ The types you are able to choose are the AccuRev transaction types, +

+

+ +

+
\ No newline at end of file Index: src/main/java/hudson/plugins/accurev/AccurevSCM.java =================================================================== --- src/main/java/hudson/plugins/accurev/AccurevSCM.java (revision 20179) +++ src/main/java/hudson/plugins/accurev/AccurevSCM.java Wed Jul 29 17:57:25 CEST 2009 @@ -1,41 +1,9 @@ package hudson.plugins.accurev; -import java.io.BufferedOutputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Serializable; -import java.io.StringReader; -import java.io.ObjectStreamException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Arrays; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.logging.Logger; - import hudson.FilePath; import hudson.Launcher; import hudson.Util; -import hudson.model.AbstractBuild; -import hudson.model.AbstractProject; -import hudson.model.BuildListener; -import hudson.model.ModelObject; -import hudson.model.Result; -import hudson.model.Run; -import hudson.model.TaskListener; -import hudson.model.Descriptor; +import hudson.model.*; import hudson.plugins.jetty.security.Password; import hudson.remoting.Callable; import hudson.remoting.VirtualChannel; @@ -45,6 +13,7 @@ import hudson.scm.SCMDescriptor; import hudson.util.ArgumentListBuilder; import hudson.util.IOException2; +import net.sf.json.JSONObject; import org.codehaus.plexus.util.StringOutputStream; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.StaplerRequest; @@ -52,8 +21,16 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; -import net.sf.json.JSONObject; +import java.io.*; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Logger; + /** * Created by IntelliJ IDEA. * @@ -77,7 +54,7 @@ private final boolean synctime; private final String workspace; private final String workspaceSubPath; - + private static String notificationTransactionTypes; // --------------------------- CONSTRUCTORS --------------------------- /** @@ -177,6 +154,22 @@ return useWorkspace; } + /** + * + * @return what types of transactions should render a notification to the author if the build fails + */ + public static String getNotificationTransactionTypes() { + return notificationTransactionTypes; + } + + /** + * + * @param notifTransactionTypes what types of transactions should render a notification to the author if the build fails + */ + public static void setNotificationTransactionTypes(String notifTransactionTypes) { + notificationTransactionTypes = notifTransactionTypes; + } + // ------------------------ INTERFACE METHODS ------------------------ // --------------------- Interface Describable --------------------- @@ -532,7 +525,8 @@ * {@inheritDoc} */ public ChangeLogParser createChangeLogParser() { - return new AccurevChangeLogParser(); + //include notifyTransactionTypes so that notification-filtering works + return new AccurevChangeLogParser(getNotificationTransactionTypes()); } /** @@ -734,6 +728,20 @@ } } + /** + * + * @param server + * @param accurevEnv + * @param workspace + * @param listener + * @param accurevPath + * @param launcher + * @param stream + * @param buildDate + * @return if there are any new transactions in the stream since the last build was done + * @throws IOException + * @throws InterruptedException + */ private boolean checkStreamForChanges(AccurevServer server, Map accurevEnv, FilePath workspace, @@ -743,80 +751,105 @@ String stream, Date buildDate) throws IOException, InterruptedException { + AccurevTransaction latestCodeChangeTransaction = new AccurevTransaction(); + latestCodeChangeTransaction.setDate(new Date(0)); + + //query AccuRev for the latest transactions of each kind defined in transactionTypes using getTimeOfLatestTransaction + for (String transactionType : server.getValidTransactionTypes().split(";")) { + AccurevTransaction tempTransaction; + + try { + tempTransaction = getLatestTransaction(server, accurevEnv, workspace, listener, accurevPath, launcher, stream, transactionType); + if (latestCodeChangeTransaction.getDate().before(tempTransaction.getDate())) { + latestCodeChangeTransaction = tempTransaction; + } + } + catch(NullPointerException e){ + listener.getLogger().println("There is no transactions of the type " + transactionType + " in the stream " + stream); + } + catch(Exception e) { + listener.getLogger().println("getTimeOfLatestTransaction failed when checking the stream " + stream + " for changes with transaction type " + transactionType); + e.printStackTrace(listener.getLogger()); + logger.warning(e.getMessage()); + } + } + + //log transaction-information + listener.getLogger().println("Last change on " + latestCodeChangeTransaction.getDate()); + listener.getLogger().println("#" + latestCodeChangeTransaction.getId() + " " + latestCodeChangeTransaction.getAuthor() + " " + latestCodeChangeTransaction.getAction()); + if(latestCodeChangeTransaction.getMsg() != null ) { + listener.getLogger().println(latestCodeChangeTransaction.getMsg()); + } + + return buildDate == null || buildDate.before(latestCodeChangeTransaction.getDate()); + } + + /** + * + * + * @param server + * @param accurevEnv + * @param workspace + * @param listener + * @param accurevPath + * @param launcher + * @param stream + * @param transactionType Specify what type of transaction to search for + * @return the latest transaction of the specified type from the selected stream + * @throws Exception + */ + private AccurevTransaction getLatestTransaction(AccurevServer server, + Map accurevEnv, + FilePath workspace, + TaskListener listener, + String accurevPath, + Launcher launcher, + String stream, + String transactionType) + throws Exception { + //initialize code that extracts the latest transaction of a certain type using -k flag - ArgumentListBuilder cmd = new ArgumentListBuilder(); - cmd.add(accurevPath); - cmd.add("hist"); - addServer(cmd, server); - cmd.add("-fx"); - cmd.add("-p"); - cmd.add(depot); - cmd.add("-s"); - cmd.add(stream); - cmd.add("-t"); - cmd.add("now.1"); + ArgumentListBuilder cmd = new ArgumentListBuilder(); + cmd.add(accurevPath); + cmd.add("hist"); + addServer(cmd, server); + cmd.add("-fx"); + cmd.add("-p"); + cmd.add(depot); + cmd.add("-s"); + cmd.add(stream); + cmd.add("-t"); + cmd.add("now.1"); + cmd.add("-k"); + cmd.add(transactionType); - StringOutputStream sos = new StringOutputStream(); + StringOutputStream sos = new StringOutputStream(); - int rv; - if (0 != (rv = launchAccurev(launcher, cmd, accurevEnv, null, sos, workspace))) { - listener.fatalError("History command failed with exit code " + rv); - return false; + + //execute code that extracts the latest transaction + int rv = launchAccurev(launcher, cmd, accurevEnv, null, sos, workspace); + if (0 != rv) { + throw new Exception("History command failed with exit code " + rv + " when trying to get the latest transaction of type " + transactionType); - } + } - try { + //parse the result from the transaction-query XmlPullParser parser = newPullParser(); parser.setInput(new StringReader(sos.toString())); - while (true) { - int event = parser.next(); - if (event == XmlPullParser.END_DOCUMENT) { - // we've got to the end with no transaction tags, - // therefore no changes in this stream - return false; - } - if (event != XmlPullParser.START_TAG) { - continue; - } - if (!"transaction".equalsIgnoreCase(parser.getName())) { - continue; - } - break; - } - String transactionId = parser.getAttributeValue("", "id"); - String transactionType = parser.getAttributeValue("", "type"); - String transactionTime = parser.getAttributeValue("", "time"); - String transactionUser = parser.getAttributeValue("", "user"); - Date transactionDate = convertAccurevTimestamp(transactionTime); - listener.getLogger().println("Last change on " + transactionDate); - listener.getLogger().println("#" + transactionId + " " + transactionUser + " " + transactionType); - String transactionComment = null; - boolean inComment = false; - while (transactionComment == null) { - switch (parser.next()) { - case XmlPullParser.START_TAG: - inComment = "comment".equalsIgnoreCase(parser.getName()); - break; - case XmlPullParser.END_TAG: - inComment = false; - break; - case XmlPullParser.TEXT: - if (inComment) { - transactionComment = parser.getText(); + AccurevTransaction resultTransaction = new AccurevTransaction(); + while (parser.next() != XmlPullParser.END_DOCUMENT) { + if (parser.getEventType() == XmlPullParser.START_TAG) { + if(parser.getName().equalsIgnoreCase("transaction")) { + //parse transaction-values + resultTransaction.setId( ( Integer.parseInt( parser.getAttributeValue("", "id")))); + resultTransaction.setAction( parser.getAttributeValue("","type")); + resultTransaction.setDate( convertAccurevTimestamp(parser.getAttributeValue("", "time"))); + resultTransaction.setUser( parser.getAttributeValue("", "user")); + } else if (parser.getName().equalsIgnoreCase("comment")) { + //parse comments + resultTransaction.setMsg(parser.nextText()); - } + } - break; - case XmlPullParser.END_DOCUMENT: - transactionComment = ""; - default: } } - listener.getLogger().println(transactionComment); - - return buildDate == null || buildDate.compareTo(transactionDate) < 0; - } catch (XmlPullParserException e) { - e.printStackTrace(listener.getLogger()); - logger.warning(e.getMessage()); - return false; + return resultTransaction; - } + } - } - /** * Helper method to retrieve include/exclude rules for a given stream. * @@ -1071,7 +1104,7 @@ private String password; private transient List winCmdLocations; private transient List nixCmdLocations; - + private String validTransactionTypes; /** * The default search paths for Windows clients. */ @@ -1097,7 +1130,7 @@ } @DataBoundConstructor - public AccurevServer(String name, String host, int port, String username, String password) { + public AccurevServer(String name, String host, int port, String username, String password, String validTransactionTypes) { this.name = name; this.host = host; this.port = port; @@ -1105,6 +1138,8 @@ this.password = Password.obfuscate(password); winCmdLocations = new ArrayList(DEFAULT_WIN_CMD_LOCATIONS); nixCmdLocations = new ArrayList(DEFAULT_NIX_CMD_LOCATIONS); + this.validTransactionTypes = validTransactionTypes; + setNotificationTransactionTypes(validTransactionTypes); } /** @@ -1186,8 +1221,23 @@ return winCmdLocations.toArray(new String[winCmdLocations.size()]); } + /** + * + * @return returns the currently set transaction types that are seen as valid for triggering builds and whos authors get notified when a build fails + */ + public String getValidTransactionTypes() { + return validTransactionTypes; - } + } + /** + * + * @param validTransactionTypes the currently set transaction types that are seen as valid for triggering builds and whos authors get notified when a build fails + */ + public void setValidTransactionTypes(String validTransactionTypes) { + this.validTransactionTypes = validTransactionTypes; + } + } + private static final class PurgeWorkspaceContents implements FilePath.FileCallable { private final TaskListener listener; @@ -1243,6 +1293,14 @@ private static final class AccurevChangeLogParser extends ChangeLogParser { + private String notificationTransactionTypes; + + public AccurevChangeLogParser(){} + + public AccurevChangeLogParser(String notifTransactionTypes){ + notificationTransactionTypes = notifTransactionTypes; + } + /** * {@inheritDoc} */ @@ -1292,9 +1350,14 @@ currentTransaction = new AccurevTransaction(); transactions.add(currentTransaction); currentTransaction.setRevision(parser.getAttributeValue("", "id")); - currentTransaction.setUser(parser.getAttributeValue("", "user")); currentTransaction.setDate(convertAccurevTimestamp(parser.getAttributeValue("", "time"))); currentTransaction.setAction(parser.getAttributeValue("", "type")); + currentTransaction.setUser(" "); + for (String transactionType : notificationTransactionTypes.split(";")) { + if (currentTransaction.getAction().equalsIgnoreCase(transactionType)) { + currentTransaction.setUser(parser.getAttributeValue("", "user")); + } + } } else if ("version".equalsIgnoreCase(tagName) && currentTransaction != null) { String path = parser.getAttributeValue("", "path"); if (path != null) { Index: src/main/java/hudson/plugins/accurev/AccurevTransaction.java =================================================================== --- src/main/java/hudson/plugins/accurev/AccurevTransaction.java (revision 20179) +++ src/main/java/hudson/plugins/accurev/AccurevTransaction.java Mon Jul 27 13:56:04 CEST 2009 @@ -19,6 +19,7 @@ private String msg; private String action; private List affectedPaths = new ArrayList(); + private int id; public String getRevision() { return revision; @@ -96,4 +97,29 @@ public void addAffectedPath(String path) { affectedPaths.add(path); } + /** + * Getter for action + * Enables accurate filtering by AccuRev transaction type since the metod getEditType censors the actual type. + * @return transaction type of the AccuRev transaction + */ + public String getAction() { + return action; -} + } + + /** + * Getter for id + * Enables logging with AccuRev transaction id + * @return transaction id of the AccuRev transaction + */ + public int getId() { + return id; + } + + /** + * Setter for id + * @param id transaction id of the AccuRev transaction + */ + public void setId(int id) { + this.id = id; + } +}