public static void Notify (DBWork work, DBRevisionWork revision_work) { Logger.Log ("Notifications.Notify (lane_id: {1} revision_id: {2} host_id: {3} State: {0})", work.State, revision_work.lane_id, revision_work.revision_id, revision_work.host_id); if (notifications == null) return; if (!(work.State == DBState.Failed || work.State == DBState.Issues || work.State == DBState.Timeout)) return; ThreadPool.QueueUserWorkItem ((v) => ProcessNotify (work, revision_work)); }
/** * Notification callback for work updates. */ public override void Notify (DBWork work, DBRevisionWork revision_work) { // Get info RevisionWorkInfo info; using (var db = new DB ()) info = getWorkInfo (db, revision_work.id, work.id); // Create object to send var statusObj = createPayload(revision_work.lane_id, revision_work.host_id, revision_work.revision_id, String.Format("Lane: {0}, Status: {1}, Step: {2}, StepStatus: {3}", info.laneName, revision_work.State, info.command, work.State ), STATE_TO_GITHUB [revision_work.State] ); sendNotification (info.repoURL, info.hash, statusObj); }
// Don't care about related people and the autogenerated message. protected override void Notify (DBWork work, DBRevisionWork revision_work, List<DBPerson> people, string message) { throw new NotImplementedException (); }
void NotifySlack (DBWork work, DBRevisionWork revision_work, List<DBPerson> people, string message) { bool nonfatal = false; if (!Evaluate (work, revision_work, out nonfatal)) { log.DebugFormat ("SlackNotification: lane_id: {1} revision_id: {2} host_id: {3} State: {0}: evaluation returned false", work.State, revision_work.lane_id, revision_work.revision_id, revision_work.host_id); return; } else { log.DebugFormat ("SlackNotification: lane_id: {1} revision_id: {2} host_id: {3} State: {0} enabled: {4}, {5} people", work.State, revision_work.lane_id, revision_work.revision_id, revision_work.host_id, enabled, people.Count); } if (nonfatal) { message = "Test failure"; } else { message = "Build failure"; } DBRevision revision; DBLane lane; DBHost host; using (DB db = new DB ()) { revision = DBRevision_Extensions.Create (db, revision_work.revision_id); lane = DBLane_Extensions.Create (db, revision_work.lane_id); host = DBHost_Extensions.Create (db, revision_work.host_id); } message = string.Format ("{0} in revision {1} on {2}/{3} ({4}/ViewLane.aspx?lane_id={5}&host_id={6}&revision_id={7})", message, (revision.revision.Length > 8 ? revision.revision.Substring (0, 8) : revision.revision), lane.lane, host.host, Configuration.GetWebSiteUrl (), lane.id, host.id, revision.id); foreach (var person in people) { if (string.IsNullOrEmpty (person.irc_nicknames)) { using (var db = new DB ()) { var computed_nicks = new List<string> (); var email_lists = new List<IEnumerable<string>> (); email_lists.Add (person.GetEmails (db)); if (person.Emails != null) email_lists.Add (person.Emails); foreach (var emails in email_lists) { foreach (var email in emails) { var at = email.IndexOf ('@'); if (at > 0) { computed_nicks.Add (email.Substring (0, at)); } } } if (computed_nicks.Count == 0 && !string.IsNullOrEmpty (person.fullname)) computed_nicks.Add (person.fullname); person.irc_nicknames = string.Join (",", computed_nicks.ToArray ()); } } if (string.IsNullOrEmpty (person.irc_nicknames)) { log.DebugFormat ("SlackNotification: could not find somebody to notify for revision with id {0} on lane {1}", revision_work.revision_id, revision_work.lane_id); continue; } } var rooms = identity.channels.Split (new char [] { ',' }, StringSplitOptions.RemoveEmptyEntries); var finalApi = identity.servers; var webClient = new WebClient (); foreach (var r in rooms) { string prefix; string room = r; if (room.StartsWith ("*")) { room = room.Substring (1); prefix = ""; } else { prefix = "@"; } var prefixNames = string.Join (", ", people.SelectMany (x => x.irc_nicknames.Split (',')).Distinct ().Select (x => string.Format("{1}{0}", x, prefix))); var finalMessage = prefixNames + ": " + message; if (cache [room + "|" + finalMessage] != null) continue; cache.Add (room + "|" + finalMessage, string.Empty, new DateTimeOffset (DateTime.UtcNow.AddHours (1), TimeSpan.Zero)); var json = string.Format (@" {{ ""channel"": ""{0}"", ""username"": ""Wrench"", ""text"": ""*{1}*"", ""attachments"": [ {{ ""fallback"": ""{2}{3}"", ""color"": ""{4}"", ""fields"":[ {{ ""value"": ""{2}{3}"", ""short"": false }} ] }} ] }} ", r, nonfatal ? "Test failure" : "Build failure", nonfatal ? ":crying_cat_face: " : ":pouting_cat: ", finalMessage.Replace ("\\", "\\\\").Replace ("\"", "\\\""), nonfatal ? "warning" : "danger" ); var postData = new NameValueCollection (); postData.Add ("payload", json); try { var res = webClient.UploadValues (finalApi, postData); var resString = Encoding.UTF8.GetString (res); log.DebugFormat ("SlackNotification: response from server: {0}", resString); } catch (WebException wex) { string responseText = null; if (wex.Response != null) { using (var responseStream = wex.Response.GetResponseStream ()) { if (responseStream != null) { using (var reader = new StreamReader (responseStream)) responseText = reader.ReadToEnd (); } } } if (responseText == null) { log.ErrorFormat ("SlackNotification: exception from server (no response): {0}", wex.Message); } else { log.ErrorFormat ("SlackNotification: server error: {0} with exception: {1}", responseText, wex.Message); } } } }
protected override void Notify (DBWork work, DBRevisionWork revision_work, List<DBPerson> people, string message) { IrcState state; Logger.Log ("IrcNotification.Notify (lane_id: {1} revision_id: {2} host_id: {3} State: {0}) enabled: {4}", work.State, revision_work.lane_id, revision_work.revision_id, revision_work.host_id, enabled); if (!enabled) return; foreach (var person in people) { if (string.IsNullOrEmpty (person.irc_nicknames)) { using (DB db = new DB ()) { List<string> computed_nicks = new List<string> (); List<IEnumerable<string>> email_lists = new List<IEnumerable<string>> (); email_lists.Add (person.GetEmails (db)); if (person.Emails != null) email_lists.Add (person.Emails); foreach (var emails in email_lists) { foreach (var email in emails) { int at = email.IndexOf ('@'); if (at > 0) { computed_nicks.Add (email.Substring (0, at)); } } } if (computed_nicks.Count == 0 && !string.IsNullOrEmpty (person.fullname)) computed_nicks.Add (person.fullname); person.irc_nicknames = string.Join (",", computed_nicks.ToArray ()); } } if (string.IsNullOrEmpty (person.irc_nicknames)) { Logger.Log ("IrcNotification: could not find somebody to notify for revision with id {0} on lane {1}", revision_work.revision_id, revision_work.lane_id); continue; } message = message.Replace ("{red}", "\u00034").Replace ("{bold}", "\u0002").Replace ("{default}", "\u000F"); if (!identity.join_channels) { state = Connect (); if (!state.WaitForConnected (TimeSpan.FromSeconds (30))) { Logger.Log ("IrcNotification: could not connect to server in 30 seconds."); continue; } } else { state = joined_state; } foreach (var nick in person.irc_nicknames.Split (',')) { foreach (var channel in channels) { state.Client.SendMessage (SendType.Message, channel, nick + ": " + message); } } if (!identity.join_channels) { if (!state.WaitForEmptySendBuffer (TimeSpan.FromSeconds (30))) Logger.Log ("IrcNotification: waited for 30 seconds for messages to be sent, disconnecting now"); Disconnect (state); } } }
protected abstract void Notify (DBWork work, DBRevisionWork revision_work, List<DBPerson> people, string message);
protected override void Notify (DBWork work, DBRevisionWork revision_work, List<DBPerson> people, string message) { Logger.Log ("IrcNotification.Notify (lane_id: {1} revision_id: {2} host_id: {3} State: {0}) enabled: {4}, {5} people", work.State, revision_work.lane_id, revision_work.revision_id, revision_work.host_id, enabled, people.Count); if (!enabled) return; foreach (var person in people) { if (string.IsNullOrEmpty (person.irc_nicknames)) { using (DB db = new DB ()) { List<string> computed_nicks = new List<string> (); List<IEnumerable<string>> email_lists = new List<IEnumerable<string>> (); email_lists.Add (person.GetEmails (db)); if (person.Emails != null) email_lists.Add (person.Emails); foreach (var emails in email_lists) { foreach (var email in emails) { int at = email.IndexOf ('@'); if (at > 0) { computed_nicks.Add (email.Substring (0, at)); } } } if (computed_nicks.Count == 0 && !string.IsNullOrEmpty (person.fullname)) computed_nicks.Add (person.fullname); person.irc_nicknames = string.Join (",", computed_nicks.ToArray ()); } } if (string.IsNullOrEmpty (person.irc_nicknames)) { Logger.Log ("IrcNotification: could not find somebody to notify for revision with id {0} on lane {1}", revision_work.revision_id, revision_work.lane_id); continue; } message = message.Replace ("{red}", "\u00034").Replace ("{bold}", "\u0002").Replace ("{default}", "\u000F"); var messages = new List<string> (); foreach (var nick in person.irc_nicknames.Split (',')) { var msg = nick + ": " + message; if (cache [msg] != null) continue; cache.Add (msg, string.Empty, new DateTimeOffset (DateTime.UtcNow.AddHours (1), TimeSpan.Zero)); messages.Add (msg); } if (messages.Count > 0) SendMessages (messages); } }
/// <summary> /// Checks if the specified RevisionWork is the latest. /// </summary> /// <param name="current"></param> /// <returns></returns> public bool IsLatestRevisionWork (DBRevisionWork current) { using (IDbCommand cmd = CreateCommand ()) { cmd.CommandText = @" SELECT RevisionWork.id FROM RevisionWork INNER JOIN Revision ON RevisionWork.revision_id = Revision.id WHERE lock_expires < now () AND RevisionWork.host_id = @host_id AND RevisionWork.lane_id = @lane_id AND RevisionWork.completed = false ORDER BY Revision.date DESC LIMIT 1 ;"; DB.CreateParameter (cmd, "host_id", current.host_id); DB.CreateParameter (cmd, "lane_id", current.lane_id); using (IDataReader reader = cmd.ExecuteReader ()) { if (!reader.Read ()) { log.Debug ("IsLatestRevisionWork: No result."); return true; } if (reader.GetInt32 (0) <= current.id) return true; log.DebugFormat ("IsLatestRevisionWork: Latest id: {0}, current id: {1}", reader.GetInt32 (0), current.id); return false; } } }
/// <summary> /// Will return a locked revision work. /// </summary> /// <param name="lane"></param> /// <param name="host"></param> /// <returns></returns> public DBRevisionWork GetRevisionWork (DBLane lane, DBHost host, DBHost workhost) { DBRevisionWork result = null; using (IDbCommand cmd = CreateCommand ()) { // sorting by RevisionWork.workhost_id ensures that we'll get // revisionwork which has been started at the top of the list. cmd.CommandText = @" SELECT RevisionWork.* FROM RevisionWork INNER JOIN Revision ON RevisionWork.revision_id = Revision.id WHERE RevisionWork.host_id = @host_id AND (RevisionWork.workhost_id = @workhost_id OR RevisionWork.workhost_id IS NULL) AND RevisionWork.lane_id = @lane_id AND RevisionWork.state <> @dependencynotfulfilled AND RevisionWork.state <> 10 AND RevisionWork.State <> @ignore AND RevisionWork.completed = false ORDER BY RevisionWork.workhost_id IS NULL ASC, Revision.date DESC LIMIT 1 ;"; DB.CreateParameter (cmd, "host_id", host.id); DB.CreateParameter (cmd, "lane_id", lane.id); DB.CreateParameter (cmd, "workhost_id", workhost.id); DB.CreateParameter (cmd, "dependencynotfulfilled", (int) DBState.DependencyNotFulfilled); DB.CreateParameter (cmd, "ignore", (int) DBState.Ignore); using (IDataReader reader = cmd.ExecuteReader ()) { if (reader.Read ()) result = new DBRevisionWork (reader); } } return result; }
public override void Notify (DBWork work, DBRevisionWork revision_work) { if (!(work.State == DBState.Failed || work.State == DBState.Issues || work.State == DBState.Timeout)) return; base.Notify (work, revision_work); }
public List<DBWorkView2> GetWork (DBRevisionWork revisionwork) { List<DBWorkView2> result = new List<DBWorkView2> (); using (IDbCommand cmd = CreateCommand ()) { cmd.CommandText = "SELECT * FROM WorkView2 WHERE revisionwork_id = @revisionwork_id ORDER BY sequence"; DB.CreateParameter (cmd, "revisionwork_id", revisionwork.id); using (IDataReader reader = cmd.ExecuteReader ()) { while (reader.Read ()) result.Add (new DBWorkView2 (reader)); } } return result; }
private Dictionary<String, Object> BuildStatusFrom(int laneId, int revId, DBRevisionWork work, DBHost host) { if (host == null) throw new HttpException(404, "Build has not been assigned yet, cannot generate status."); var buildView = Utils.LocalWebService.GetViewLaneData (login, laneId, "", host.id, "", revId, ""); var steps = new List<Dictionary<String, Object>>(); for (int sidx = 0; sidx < buildView.WorkViews.Count; sidx++) { var step = buildView.WorkViews [sidx]; var files = buildView.WorkFileViews [sidx]; var links = buildView.Links.Where (l => l.work_id == step.id); steps.Add (BuildStepStatus (sidx, step, files, links)); } return new Dictionary<String, Object> { { "build_host", buildView.WorkHost.host }, { "build_host_id", buildView.WorkHost.id }, { "branch", MaxRevisionToBranch (buildView.Lane.max_revision) }, { "commit", buildView.Revision.revision }, { "completed", buildView.RevisionWork.completed }, { "end_time", work.endtime }, { "host", host.host }, { "host_id", host.id }, { "lane_id", laneId }, { "lane_name", buildView.Lane.lane }, { "revision_id", revId }, { "repository", buildView.Lane.repository }, { "start_time", buildView.WorkViews [0].starttime }, { "status", work.State.ToString ().ToLowerInvariant () }, { "steps", steps }, { "url", BuildLink (laneId, revId, host.id) } }; }
private static void ProcessNotify (DBWork work, DBRevisionWork revision_work) { log.DebugFormat ("Running notifiers for lane_id: {1}, revision_id: {2}, host_id: {3}, State: {0}", work.State, revision_work.lane_id, revision_work.revision_id, revision_work.host_id); try { lock (lock_obj) { List<NotificationBase> notifiers; // We broadcast the notification to the API endpoint WebNotification.BroadcastBuildNotification (work, revision_work); if (!notifications_per_lane.TryGetValue (revision_work.lane_id, out notifiers)) { return; } foreach (var notification in notifiers) { notification.Notify (work, revision_work); } } } catch (Exception ex) { log.ErrorFormat ("Exception while processing notification: {0}", ex); } }
public static void Notify (DBWork work, DBRevisionWork revision_work) { log.DebugFormat ("Notify (lane_id: {1} revision_id: {2} host_id: {3} State: {0})", work.State, revision_work.lane_id, revision_work.revision_id, revision_work.host_id); if (notifications == null) return; queued_notifications.Add (new QueuedNotification { IsInfo = false, work = work, revision_work = revision_work }); }
private static void ProcessNotify (DBWork work, DBRevisionWork revision_work) { List<NotificationBase> notifications; Logger.Log ("Notifications.ProcessNotify (lane_id: {1} revision_id: {2} host_id: {3} State: {0})", work.State, revision_work.lane_id, revision_work.revision_id, revision_work.host_id); try { lock (lock_obj) { // We broadcast the notification to the API endpoint WebNotification.BroadcastBuildNotification (work, revision_work); if (!notifications_per_lane.TryGetValue (revision_work.lane_id, out notifications)) { Logger.Log ("Notifications.ProcessNotify (lane_id: {1} revision_id: {2} host_id: {3} State: {0}): Lane doesn't have any notifications enabled", work.State, revision_work.lane_id, revision_work.revision_id, revision_work.host_id); return; } foreach (var notification in notifications) { notification.Notify (work, revision_work); } } } catch (Exception ex) { Logger.Log ("Exception while processing notification: {0}", ex.Message); } }
public static DBRevisionWork Find (DB db, DBLane lane, DBHost host, DBRevision revision) { DBRevisionWork result; using (IDbCommand cmd = db.CreateCommand ()) { cmd.CommandText = "SELECT * FROM RevisionWork WHERE lane_id = @lane_id AND revision_id = @revision_id "; if (host != null) { cmd.CommandText += " AND host_id = @host_id;"; DB.CreateParameter (cmd, "host_id", host.id); } DB.CreateParameter (cmd, "lane_id", lane.id); DB.CreateParameter (cmd, "revision_id", revision.id); using (IDataReader reader = cmd.ExecuteReader ()) { if (!reader.Read ()) return null; result = new DBRevisionWork (reader); if (reader.Read ()) throw new ApplicationException (string.Format ("Found more than one revision work for the specified lane/host/revision ({0}/{1}/{2})", lane.lane, host == null ? "null" : host.host, revision.revision)); return result; } } }
protected bool Evaluate (DBWork work, DBRevisionWork revision_work, out bool nonfatal) { DBState newest_state = work.State; nonfatal = false; if (work.State == DBState.Success) return false; if ((work.State == DBState.Issues || work.State == DBState.Timeout) && Notification.Type == DBNotificationType.FatalFailuresOnly) return false; /* We need to see if there are any successfull builds later than this one */ using (DB db = new DB ()) { using (var cmd = db.CreateCommand ()) { cmd.CommandText += @"SELECT nonfatal FROM Command WHERE id = @command_id;"; DB.CreateParameter (cmd, "command_id", work.command_id); using (IDataReader reader = cmd.ExecuteReader ()) { if (reader.Read ()) nonfatal = reader.GetBoolean (0); } } using (IDbCommand cmd = db.CreateCommand ()) { cmd.CommandText = @" SELECT state FROM RevisionWork INNER JOIN Revision ON RevisionWork.revision_id = Revision.id WHERE RevisionWork.lane_id = @lane_id AND RevisionWork.host_id = @host_id AND RevisionWork.completed AND Revision.date > (SELECT date FROM Revision WHERE id = @revision_id) AND"; if (nonfatal) { cmd.CommandText += " RevisionWork.state = 3 "; } else { cmd.CommandText += " (RevisionWork.state = 3 OR RevisionWork.state = 8) "; } cmd.CommandText += @" ORDER BY Revision.date DESC LIMIT 1; "; DB.CreateParameter (cmd, "lane_id", revision_work.lane_id); DB.CreateParameter (cmd, "host_id", revision_work.host_id); DB.CreateParameter (cmd, "revision_id", revision_work.revision_id); DB.CreateParameter (cmd, "command_id", work.command_id); object obj_state = null; using (IDataReader reader = cmd.ExecuteReader ()) { if (reader.Read ()) obj_state = reader [0]; } if (obj_state != DBNull.Value && obj_state != null) { Logger.Log ("NotificationBase.Evaluate: Later work succeeded, nothing to notify"); return false; } } } switch (Notification.Type) { case DBNotificationType.AllFailures: return work.State == DBState.Issues || work.State == DBState.Failed || work.State == DBState.Timeout; case DBNotificationType.FatalFailuresOnly: if (nonfatal) return false; return work.State == DBState.Failed && newest_state == DBState.Failed; case DBNotificationType.NonFatalFailuresOnly: return (work.State == DBState.Issues || work.State == DBState.Timeout) || nonfatal; default: return false; } }
public static void BroadcastBuildNotification (DBWork work, DBRevisionWork revisionWork) { BroadcastBuildNotification (new Lazy<Build> (() => GetBuildFromDBItems (work, revisionWork))); }
public void Notify (DBWork work, DBRevisionWork revision_work) { List<DBPerson> people = new List<DBPerson> (); DBRevision revision; DBLane lane; DBHost host; string message; bool nonfatal; Logger.Log ("NotificationBase.Notify (lane_id: {1} revision_id: {2} host_id: {3} State: {0})", work.State, revision_work.lane_id, revision_work.revision_id, revision_work.host_id); nonfatal = false; if (!Evaluate (work, revision_work, out nonfatal)) { Logger.Log ("NotificationBase.Notify (lane_id: {1} revision_id: {2} host_id: {3} State: {0}) = evaluation returned false", work.State, revision_work.lane_id, revision_work.revision_id, revision_work.host_id); return; } if (nonfatal) { message = "Test failure"; } else { message = "{red}{bold}Build failure{default}"; } using (DB db = new DB ()) { revision = DBRevision_Extensions.Create (db, revision_work.revision_id); lane = DBLane_Extensions.Create (db, revision_work.lane_id); host = DBHost_Extensions.Create (db, revision_work.host_id); } message = string.Format ("{0} in revision {1} on {2}/{3}: {4}/ViewLane.aspx?lane_id={5}&host_id={6}&revision_id={7}", message, (revision.revision.Length > 8 ? revision.revision.Substring (0, 8) : revision.revision), lane.lane, host.host, Configuration.GetWebSiteUrl (), lane.id, host.id, revision.id); MonkeyWrench.Scheduler.Scheduler.FindPeopleForCommit (lane, revision, people); people = FindPeople (people); Notify (work, revision_work, people, message); }
static Build GetBuildFromDBItems (DBWork work, DBRevisionWork revisionWork) { DBRevision revision; DBLane lane, parentLane; DBHost host; using (DB db = new DB ()) { revision = DBRevision_Extensions.Create (db, revisionWork.revision_id); lane = DBLane_Extensions.Create (db, revisionWork.lane_id); parentLane = GetTopMostParent (lane, db); host = DBHost_Extensions.Create (db, revisionWork.host_id); } var url = Configuration.GetWebSiteUrl (); url += string.Format ("/ViewLane.aspx?lane_id={0}&host_id={1}&revision_id={2}", lane.id, host.id, revision.id); return new Build { Commit = revision.revision, CommitId = revision.id, Date = revisionWork.endtime ?? revision.date, Lane = lane.lane, Project = parentLane.lane, State = revisionWork.State, Author = revision.author, BuildBot = host.host, Url = url }; }
protected override void Notify (DBWork work, DBRevisionWork revision_work, List<DBPerson> people, string message) { if (!this.emails.Any ()) { Logger.Log ("EmailNotification.Notify no emails"); return; } if (this.emails.Any (x => !x.EndsWith ("@hipchat.xamarin.com", StringComparison.OrdinalIgnoreCase))) { Logger.Log ("EmailNotification.Notify skipping non-HipChat emails because we don't know how to send email!"); return; } var actionableEmails = this.emails.Where (x => x.EndsWith ("@hipchat.xamarin.com")).ToList (); if (!actionableEmails.Any ()) { Logger.Log ("EmailNotification.Notify no actionable emails!"); return; } Logger.Log ("EmailNotification.Notify (lane_id: {1} revision_id: {2} host_id: {3} State: {0}) enabled: {4}, {5} people", work.State, revision_work.lane_id, revision_work.revision_id, revision_work.host_id, true, people.Count); bool nonfatal = false; if (!Evaluate (work, revision_work, out nonfatal)) { Logger.Log ("EmailNotification.Notify (lane_id: {1} revision_id: {2} host_id: {3} State: {0}) = evaluation returned false", work.State, revision_work.lane_id, revision_work.revision_id, revision_work.host_id); return; } if (nonfatal) { message = "Test failure"; } else { message = "Build failure"; } DBRevision revision; DBLane lane; DBHost host; using (DB db = new DB ()) { revision = DBRevision_Extensions.Create (db, revision_work.revision_id); lane = DBLane_Extensions.Create (db, revision_work.lane_id); host = DBHost_Extensions.Create (db, revision_work.host_id); } message = string.Format ("{0} in revision {1} on {2}/{3} ({4}/ViewLane.aspx?lane_id={5}&host_id={6}&revision_id={7})", message, (revision.revision.Length > 8 ? revision.revision.Substring (0, 8) : revision.revision), lane.lane, host.host, Configuration.GetWebSiteUrl (), lane.id, host.id, revision.id); foreach (var person in people) { if (string.IsNullOrEmpty (person.irc_nicknames)) { using (var db = new DB ()) { var computed_nicks = new List<string> (); var email_lists = new List<IEnumerable<string>> (); email_lists.Add (person.GetEmails (db)); if (person.Emails != null) email_lists.Add (person.Emails); foreach (var emails in email_lists) { foreach (var email in emails) { var at = email.IndexOf ('@'); if (at > 0) { computed_nicks.Add (email.Substring (0, at)); } } } if (computed_nicks.Count == 0 && !string.IsNullOrEmpty (person.fullname)) computed_nicks.Add (person.fullname); person.irc_nicknames = string.Join (",", computed_nicks.ToArray ()); } } if (string.IsNullOrEmpty (person.irc_nicknames)) { Logger.Log ("HipChatNotification: could not find somebody to notify for revision with id {0} on lane {1}", revision_work.revision_id, revision_work.lane_id); continue; } } var apiToken = identity.password; var rooms = actionableEmails.Select (email => email.Split ('@') [0]).ToList (); const string finalApi = "https://hipchat.xamarin.com/v1/rooms/message"; var webClient = new WebClient (); foreach (var r in rooms) { string prefix; string room = r; if (room.StartsWith ("*")) { room = room.Substring (1); prefix = ""; } else { prefix = "@"; } var prefixNames = string.Join (", ", people.SelectMany (x => x.irc_nicknames.Split (',')).Distinct ().Select (x => string.Format("{1}{0}", x, prefix))); var finalMessage = prefixNames + ": " + message; if (cache [room + "|" + finalMessage] != null) continue; cache.Add (room + "|" + finalMessage, string.Empty, new DateTimeOffset (DateTime.UtcNow.AddHours (1), TimeSpan.Zero)); var postData = new NameValueCollection (); postData.Add ("auth_token", apiToken); postData.Add ("room_id", room); postData.Add ("from", "Wrench"); postData.Add ("message", finalMessage); postData.Add ("notify", nonfatal ? "0" : "1"); // TODO: Maybe send HTML eventually, though HTML doesn't allow @-mentions. :( postData.Add ("message_format", "text"); postData.Add ("color", nonfatal ? "yellow" : "red"); postData.Add ("format", "json"); var res = webClient.UploadValues (finalApi, postData); var resString = Encoding.UTF8.GetString (res); Logger.Log ("HipChatNotification: response from server: {0}", resString); } }
private bool Evaluate (DBWork work, DBRevisionWork revision_work) { DBState newest_state = work.State; /* We need to see if the latest completed build is still failing */ using (DB db = new DB ()) { using (IDbCommand cmd = db.CreateCommand ()) { cmd.CommandText = @" SELECT state FROM RevisionWork INNER JOIN Revision ON RevisionWork.revision_id = Revision.id WHERE RevisionWork.lane_id = @lane_id AND RevisionWork.host_id = @host_id AND RevisionWork.completed AND Revision.date > (SELECT date FROM Revision WHERE id = @revision_id) ORDER BY Revision.date DESC LIMIT 1 "; DB.CreateParameter (cmd, "lane_id", revision_work.lane_id); DB.CreateParameter (cmd, "host_id", revision_work.host_id); DB.CreateParameter (cmd, "revision_id", revision_work.revision_id); object obj_state = cmd.ExecuteScalar (); if (obj_state is DBState) newest_state = (DBState) obj_state; } } if (newest_state == DBState.Success) return false; switch (Notification.Type) { case DBNotificationType.AllFailures: return work.State == DBState.Issues || work.State == DBState.Failed; case DBNotificationType.FatalFailuresOnly: return work.State == DBState.Failed && newest_state == DBState.Failed; case DBNotificationType.NonFatalFailuresOnly: return work.State == DBState.Issues; default: return false; } }