Index: src/main/java/hudson/plugins/twitter/PluginImpl.java =================================================================== --- src/main/java/hudson/plugins/twitter/PluginImpl.java (revision 17762) +++ src/main/java/hudson/plugins/twitter/PluginImpl.java (working copy) @@ -1,6 +1,7 @@ package hudson.plugins.twitter; import hudson.Plugin; +import hudson.model.UserProperties; import hudson.tasks.BuildStep; /** @@ -9,8 +10,12 @@ * @author justinedelson */ public class PluginImpl extends Plugin { + + public static final UserTwitterPropertyDescriptor USER_SCORE_PROPERTY_DESCRIPTOR = new UserTwitterPropertyDescriptor(); + public void start() throws Exception { BuildStep.PUBLISHERS.addNotifier(TwitterPublisher.DESCRIPTOR); + UserProperties.LIST.add(USER_SCORE_PROPERTY_DESCRIPTOR); } @Override Index: src/main/java/hudson/plugins/twitter/TwitterPublisher.java =================================================================== --- src/main/java/hudson/plugins/twitter/TwitterPublisher.java (revision 17762) +++ src/main/java/hudson/plugins/twitter/TwitterPublisher.java (working copy) @@ -4,17 +4,24 @@ import hudson.Launcher; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; -import hudson.model.Build; import hudson.model.BuildListener; import hudson.model.Descriptor; import hudson.model.Result; +import hudson.model.User; +import hudson.scm.ChangeLogSet; +import hudson.scm.ChangeLogSet.Entry; import hudson.tasks.Mailer; import hudson.tasks.Publisher; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.lang.reflect.Constructor; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -27,9 +34,7 @@ import org.kohsuke.stapler.StaplerRequest; import twitter4j.AsyncTwitter; -import twitter4j.Status; -import twitter4j.TwitterAdapter; -import twitter4j.TwitterException; +import twitter4j.Twitter; /** * @author cactusman @@ -44,6 +49,7 @@ private String password; private Boolean onlyOnFailureOrRecovery; private Boolean includeUrl; + private String defaultMsg; /** * {@stapler-constructor} @@ -55,6 +61,7 @@ this.includeUrl = includeUrl; this.id = id; this.password = password; + this.defaultMsg = defaultMsg; } private static String createTinyUrl(String url) throws IOException { @@ -64,7 +71,14 @@ int status = client.executeMethod(gm); if (status == HttpStatus.SC_OK) { - return gm.getResponseBodyAsString(); + InputStream in = gm.getResponseBodyAsStream(); + BufferedReader buf = new BufferedReader(new InputStreamReader(in)); + StringBuffer resp = new StringBuffer(); + String line; + while ((line = buf.readLine()) != null) { + resp.append(line); + } + return resp.toString(); } else { throw new IOException("Non-OK response code back from tinyurl: " + status); } @@ -90,52 +104,89 @@ public String getPassword() { return password; } + + public String getDefaultMsg() { + return defaultMsg; + } public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) { return _perform(build, launcher, listener); } - protected

, B extends AbstractBuild> boolean _perform(B build, - Launcher launcher, BuildListener listener) { - if (shouldTweet(build)) { + protected

, B extends AbstractBuild> boolean _perform( + B build, Launcher launcher, BuildListener listener) { + if (shouldTweet(build)) { - String newStatus = null; - if (shouldIncludeUrl()) { - try { - newStatus = createStatusWithURL(build); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Unable to tinyfy url", e); - newStatus = createStatusWithoutURL(build); - } - } else { - newStatus = createStatusWithoutURL(build); - } + String newStatus = null; - try { - DESCRIPTOR.updateTwit(id, password, newStatus); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Unable to send tweet.", e); - } - } - return true; + try { + newStatus = createTwStatus(build); + } catch (Exception e) { + } - } + try { + DESCRIPTOR.updateTwit(id, password, newStatus); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Unable to send tweet.", e); + } + } + return true; - protected

, B extends AbstractBuild> String createStatusWithoutURL(B build) { - String projectName = build.getProject().getName(); - String result = build.getResult().toString(); - return String.format("%s:%s #%d", result, projectName, build.number); - } + } - protected

, B extends AbstractBuild> String createStatusWithURL(B build) - throws IOException { - String projectName = build.getProject().getName(); - String result = build.getResult().toString(); - String absoluteBuildURL = DESCRIPTOR.getUrl() + build.getUrl(); - String tinyUrl = createTinyUrl(absoluteBuildURL); - return String.format("%s:%s #%d - %s", result, projectName, build.number, tinyUrl); - } + protected

, B extends AbstractBuild> String createTwStatus( + B build) throws IOException { + String projectName = build.getProject().getName(); + String result = build.getResult().toString(); + String toblame = ""; + try { + if (!build.getResult().equals(Result.SUCCESS)) { + toblame = updateUserStatus(build); + } + } catch (Exception e) { + } + String tinyUrl = ""; + if (shouldIncludeUrl()) { + String absoluteBuildURL = DESCRIPTOR.getUrl() + build.getUrl(); + try { + tinyUrl = createTinyUrl(absoluteBuildURL); + } catch (Exception e) { + tinyUrl = "?"; + } + } + String msg = shouldIncludeMsg(); + System.out.println("out " + msg); + return String.format("%s[%s:%s#%d - %s]%s", toblame, result.substring( + 0, 4), projectName, build.number, tinyUrl, msg); + } + @SuppressWarnings("unchecked") + private String updateUserStatus(B build) + throws IOException { + StringBuffer tid = new StringBuffer(""); + Set culprits = build.getCulprits(); + ChangeLogSet changeSet = build.getChangeSet(); + if (culprits != null && culprits.size() > 0) { + tid = new StringBuffer("blame:"); + for (User user : culprits) { + UserTwitterProperty follower = user + .getProperty(UserTwitterProperty.class); + tid.append(follower.getTwitterid()); + tid.append(" "); + } + } else if (changeSet != null) { + tid = new StringBuffer("blame:"); + for (Entry entry : changeSet) { + User user = entry.getAuthor(); + UserTwitterProperty follower = user + .getProperty(UserTwitterProperty.class); + tid.append(follower.getTwitterid()); + tid.append(" "); + } + } + return tid.toString(); + } + /** * Detrmine if this build represents a failure or recovery. A build failure * includes both failed and unstable builds. A recovery is defined as a @@ -169,6 +220,16 @@ } } + protected String shouldIncludeMsg() { + if (defaultMsg != null) { + return defaultMsg; + } else if (DESCRIPTOR.defaultMsg != null) { + return DESCRIPTOR.defaultMsg; + } else { + return ""; + } + } + /** * Determine if this build results should be tweeted. Uses the local * settings if they are provided, otherwise the global settings. @@ -201,6 +262,7 @@ public String hudsonUrl; public boolean onlyOnFailureOrRecovery; public boolean includeUrl; + public String defaultMsg; private Class asyncTwitterClass = AsyncTwitter.class; @@ -267,6 +329,10 @@ public boolean isOnlyOnFailureOrRecovery() { return onlyOnFailureOrRecovery; } + + public String getDefaultMsg() { + return defaultMsg; + } @Override public Publisher newInstance(StaplerRequest req, JSONObject formData) throws FormException { @@ -288,20 +354,44 @@ LOGGER.info("Attempting to update Twitter status to: " + message); - AsyncTwitter twitter = createAsyncTwitter(id, password); - twitter.updateAsync(message, new TwitterAdapter() { - - @Override - public void onException(TwitterException e, int method) { - LOGGER.warning("Exception updating Twitter status: " + e.toString()); - } - - @Override - public void updated(Status statuses) { - LOGGER.info("Updated Twitter status: " + statuses.getText()); - } - - }); + if (message.length() > 140) { + String s = message; + ArrayList as = new ArrayList(); + for (int i = 0, j = 0; i < s.length(); i += 137, j++) { + String string = ""; + if (i + 137 < s.length()) { + string = s.substring(i, i + 137) + "#" + j; + as.add(string); + } else { + string = s.substring(i, s.length()) + "#" + j; + as.add(string); + } + } + for (String string : as) { + LOGGER.info("Attempting to update Twitter status to: " + + string + " len: " + string.length()); + Twitter twitter = createTwitter(id, password); + twitter.update(string); + } + } else { + Twitter twitter = createTwitter(id, password); + twitter.update(message); + } + +// AsyncTwitter twitter = createAsyncTwitter(id, password); +// twitter.updateAsync(message, new TwitterAdapter() { +// +// @Override +// public void onException(TwitterException e, int method) { +// LOGGER.warning("Exception updating Twitter status: " + e.toString()); +// } +// +// @Override +// public void updated(Status statuses) { +// LOGGER.info("Updated Twitter status: " + statuses.getText()); +// } +// +// }); } private AsyncTwitter createAsyncTwitter(String id, String password) throws Exception { @@ -310,5 +400,9 @@ return con.newInstance(id, password); } + + private Twitter createTwitter(String id, String password) throws Exception { + return new Twitter(id, password); + } } } \ No newline at end of file Index: src/main/java/hudson/plugins/twitter/UserTwitterPropertyDescriptor.java =================================================================== --- src/main/java/hudson/plugins/twitter/UserTwitterPropertyDescriptor.java (revision 0) +++ src/main/java/hudson/plugins/twitter/UserTwitterPropertyDescriptor.java (revision 0) @@ -0,0 +1,58 @@ +package hudson.plugins.twitter; + +import hudson.model.User; +import hudson.model.UserProperty; +import hudson.model.UserPropertyDescriptor; +import net.sf.json.JSONObject; + +import org.kohsuke.stapler.StaplerRequest; + +/** + * Descriptor for the {@link UserTwitterProperty}. + * + * @author Erik Ramfelt + */ +public class UserTwitterPropertyDescriptor extends UserPropertyDescriptor { + + public UserTwitterPropertyDescriptor() { + super(UserTwitterProperty.class); + } + + @Override + public String getDisplayName() { + return "Twitter User"; + } + + /** + * Method kept for backward compability. Prior to 1.222 the JSONObject + * formdata was always null. This method should be removed in the future. + * + * @param req + * request coming from config.jelly + * @return a UserScoreProperty object + */ + private UserTwitterProperty newInstanceIfJSONIsNull(StaplerRequest req) throws FormException { + if (req.getParameter("twitter-hudson.twitterid") != null) { + return new UserTwitterProperty(req.getParameter("twitter-hudson.twitterid")); + } else { + return new UserTwitterProperty(); + } + } + + @Override + public UserTwitterProperty newInstance(StaplerRequest req, JSONObject formData) throws hudson.model.Descriptor.FormException { + if (formData == null) { + return newInstanceIfJSONIsNull(req); + } + if (formData.has("twitterid")) { + return req.bindJSON(UserTwitterProperty.class, formData); + } else { + return new UserTwitterProperty(); + } + } + + @Override + public UserProperty newInstance(User arg0) { + return null; + } +} Index: src/main/java/hudson/plugins/twitter/UserTwitterProperty.java =================================================================== --- src/main/java/hudson/plugins/twitter/UserTwitterProperty.java (revision 0) +++ src/main/java/hudson/plugins/twitter/UserTwitterProperty.java (revision 0) @@ -0,0 +1,45 @@ +package hudson.plugins.twitter; + +import hudson.model.User; +import hudson.model.UserProperty; +import hudson.model.UserPropertyDescriptor; + +import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.export.Exported; +import org.kohsuke.stapler.export.ExportedBean; + +/** + * + * @author landir + */ +@ExportedBean(defaultVisibility = 999) +public class UserTwitterProperty extends UserProperty { + + private String twitterid; + + public UserTwitterProperty() { + } + + @DataBoundConstructor + public UserTwitterProperty(String twitterid) { + this.twitterid = twitterid; + } + + public UserPropertyDescriptor getDescriptor() { + return PluginImpl.USER_SCORE_PROPERTY_DESCRIPTOR; + } + + @Exported + public User getUser() { + return user; + } + + @Exported + public String getTwitterid() { + return twitterid; + } + + public void setTwitterid(String twitterid) { + this.twitterid = twitterid; + } +} Index: src/main/resources/hudson/plugins/twitter/TwitterPublisher/config.jelly =================================================================== --- src/main/resources/hudson/plugins/twitter/TwitterPublisher/config.jelly (revision 17762) +++ src/main/resources/hudson/plugins/twitter/TwitterPublisher/config.jelly (working copy) @@ -22,5 +22,9 @@ + + + + \ No newline at end of file Index: src/main/resources/hudson/plugins/twitter/TwitterPublisher/global.jelly =================================================================== --- src/main/resources/hudson/plugins/twitter/TwitterPublisher/global.jelly (revision 17762) +++ src/main/resources/hudson/plugins/twitter/TwitterPublisher/global.jelly (working copy) @@ -19,5 +19,9 @@ + + + + \ No newline at end of file Index: src/main/resources/hudson/plugins/twitter/UserTwitterProperty/config.jelly =================================================================== --- src/main/resources/hudson/plugins/twitter/UserTwitterProperty/config.jelly (revision 0) +++ src/main/resources/hudson/plugins/twitter/UserTwitterProperty/config.jelly (revision 0) @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file Index: pom.xml =================================================================== --- pom.xml (revision 17762) +++ pom.xml (working copy) @@ -23,6 +23,11 @@ 1.1.0 + commons-httpclient + commons-httpclient + 3.1 + + mockobjects mockobjects-core 0.09