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); } }
private string GetJobInfo() { var lane_id = Utils.TryParseInt32(Request ["lane_id"]); var host_id = Utils.TryParseInt32(Request ["host_id"]); var response = Utils.LocalWebService.GetViewLaneData2( login, lane_id, Request ["lane"], host_id, Request ["host"], Utils.TryParseInt32(Request ["revision_id"]), Request ["revision"], false); DBRevision dbr = response.Revision; DBRevisionWork revisionwork = response.RevisionWork; DBLane lane = response.Lane; DBHost host = response.Host; DBRevision revision = response.Revision; var jobinfo = new { revision = dbr.revision, status = revisionwork.State, author = dbr.author, commit_date = dbr.date.ToUniversalTime(), host = response.WorkHost.host, host_id = response.WorkHost.id }; return(JsonConvert.SerializeObject(jobinfo, Formatting.Indented)); }
/// <summary> /// Finds pending steps for the current revision /// </summary> /// <returns></returns> public static List <DBWorkView2> GetNextWork(this DBRevisionWork rw, DB db, DBLane lane, DBHost host, DBRevision revision, bool multiple_work) { List <DBWorkView2> result = new List <DBWorkView2> ();; if (revision == null) { throw new ArgumentNullException("revision"); } if (lane == null) { throw new ArgumentNullException("lane"); } if (host == null) { throw new ArgumentNullException("host"); } rw.FilterPendingWork(db, db.GetWork(rw), result, multiple_work); if (result.Count == 0 && !rw.completed) { rw.completed = true; rw.UpdateState(db); } return(result); }
/// <summary> /// Sets workhost to the specified host and saves it to the db. /// </summary> /// <param name="db"></param> /// <param name="host"></param> public static bool SetWorkHost(this DBRevisionWork rw, DB db, DBHost host) { object result; string update_cmd = string.Format(@"UPDATE RevisionWork SET workhost_id = {0}, assignedtime = NOW() WHERE id = {1} AND workhost_id IS NULL;", host.id, rw.id); using (IDbCommand cmd = db.CreateCommand()) { cmd.CommandText = update_cmd; var rv = cmd.ExecuteNonQuery(); if (rv != 1) { log.DebugFormat("{0}: {1} (failed)", cmd.CommandText, rv); return(false); } } using (IDbCommand cmd = db.CreateCommand()) { cmd.CommandText = @" SELECT workhost_id FROM RevisionWork where id = @id AND workhost_id = @workhost_id; "; DB.CreateParameter(cmd, "workhost_id", host.id); DB.CreateParameter(cmd, "id", rw.id); result = cmd.ExecuteScalar(); if (result != null && (result is int || result is long)) { rw.workhost_id = host.id; log.DebugFormat("{0}: {1} (succeeded)", update_cmd, result); return(true); } log.DebugFormat("{0}: {1} (failed 2)", update_cmd, result); return(false); } }
/// <summary> /// Returns a list of all the files this revisionwork has produced /// </summary> /// <param name="db"></param> /// <returns></returns> public static List <DBWorkFile> GetFiles(this DBRevisionWork rw, DB db) { List <DBWorkFile> result = new List <DBWorkFile> (); using (IDbCommand cmd = db.CreateCommand()) { cmd.CommandText = @" SELECT WorkFile.* FROM WorkFile INNER JOIN Work ON WorkFile.work_id = Work.id INNER JOIN RevisionWork ON Work.revisionwork_id = RevisionWork.id WHERE RevisionWork.id = @id; "; DB.CreateParameter(cmd, "id", rw.id); using (IDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { result.Add(new DBWorkFile(reader)); } } } return(result); }
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.completed ? revisionWork.endtime : revision.date, Lane = lane.lane, Project = parentLane.lane, State = revisionWork.State, Author = revision.author, BuildBot = host.host, Url = url }); }
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 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); } } }
public static void UpdateRevisionWorkState (this DBWork w, DB db) { DBRevisionWork rw = w.GetRevisionWork (db); if (rw != null) rw.UpdateState (db); }
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); }
/// <summary> /// Calculates the state. Always hits the db. /// </summary> /// <param name="db"></param> /// <returns></returns> public static DBState CalculateState(this DBRevisionWork rw, DB db) { bool completed; rw.State = CalculateState(db, rw.id, out completed); rw.completed = completed; return(rw.State); }
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 }); }
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)); }
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); }
public virtual void Notify(DBWork work, DBRevisionWork revision_work) { List <DBPerson> people = new List <DBPerson> (); DBRevision revision; DBLane lane; DBHost host; string message; bool nonfatal; log.DebugFormat("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)) { log.DebugFormat("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); }
/** * 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}, Host: {1}, Status: {2}, Step: {3}, StepStatus: {4}", info.laneName, info.hostName, revision_work.State, info.command, work.State ), STATE_TO_GITHUB [revision_work.State] ); sendNotification(info.repoURL, info.hash, statusObj); }
/// <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); }
/// <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); } } }
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) } }); }
/// <summary> /// Puts pending steps in result /// </summary> /// <param name="lane"></param> /// <param name="revision"></param> /// <returns></returns> private static void FilterPendingWork(this DBRevisionWork rw, DB db, List <DBWorkView2> steps, List <DBWorkView2> result, bool multiple_work) { bool failed_revision = false; for (int i = 0; i < steps.Count; i++) { if (steps [i].State == DBState.NotDone || steps [i].State == DBState.Executing) { // After a failed and fatal step, don't add any steps which aren't marked as alwaysexecute. if (failed_revision && !steps [i].alwaysexecute) { DBWork_Extensions.SetState(db, steps [i].id, steps [i].State, DBState.Skipped); continue; } // if we already have steps, don't add steps with higher sequence numbers if (!multiple_work && result.Count > 0 && result [0].sequence != steps [i].sequence) { continue; } result.Add(steps [i]); } else if (steps [i].State == DBState.Paused) { // Don't add any steps after a paused step break; } else { if (!steps [i].nonfatal && (steps [i].State == DBState.Failed || steps [i].State == DBState.Timeout || steps [i].State == DBState.Aborted)) { failed_revision = true; } } } }
protected abstract void Notify(DBWork work, DBRevisionWork revision_work, List <DBPerson> people, string message);
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) { log.Info("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))); }
protected override void Notify(DBWork work, DBRevisionWork revision_work, List <DBPerson> people, string message) { throw new NotImplementedException(); }
/// <summary> /// Calculates a new state if the current state is NotDone /// </summary> /// <param name="db"></param> /// <returns></returns> public static DBState EnsureState(this DBRevisionWork rw, DB db) { rw.State = EnsureState(db, rw.id, rw.State); return(rw.State); }
public static void UpdateState(this DBRevisionWork rw, DB db) { rw.CalculateState(db); SaveState(db, rw.id, rw.State, rw.completed); }
protected void Page_Load(object sender, EventArgs e) { GetWorkHostHistoryResponse response; int host_id; int limit; int offset; string action; int lane_id = 0; int revision_id = 0; int masterhost_id = 0; try { if (!int.TryParse(Request ["host_id"], out host_id)) { // ? return; } int.TryParse(Request ["lane_id"], out lane_id); int.TryParse(Request ["revision_id"], out revision_id); int.TryParse(Request ["masterhost_id"], out masterhost_id); action = Request ["action"]; if (!string.IsNullOrEmpty(action) && masterhost_id > 0 && lane_id > 0 && revision_id > 0) { switch (action) { case "clearrevision": Master.WebService.ClearRevision(Master.WebServiceLogin, lane_id, masterhost_id, revision_id); break; case "deleterevision": Master.WebService.RescheduleRevision(Master.WebServiceLogin, lane_id, masterhost_id, revision_id); break; case "abortrevision": Master.WebService.AbortRevision(Master.WebServiceLogin, lane_id, masterhost_id, revision_id); break; } Response.Redirect(string.Format("ViewHostHistory.aspx?host_id={0}", host_id), false); Page.Visible = false; return; } if (!int.TryParse(Request.QueryString ["limit"], out limit)) { limit = 25; } if (!int.TryParse(Request.QueryString ["offset"], out offset)) { offset = 0; } response = Master.WebService.GetWorkHostHistory(Master.WebServiceLogin, Utils.TryParseInt32(Request ["host_id"]), Request ["host"], limit, offset); string hdr; if (Authentication.IsInRole(response, MonkeyWrench.DataClasses.Logic.Roles.Administrator)) { hdr = string.Format("History for <a href='EditHost.aspx?host_id={1}'>{0}</a>", response.Host.host, response.Host.id); } else { hdr = string.Format("History for {0}", response.Host.host); } hostheader.InnerHtml = "<h2>" + hdr + "</h2>"; StringBuilder table = new StringBuilder(); table.AppendLine("<table class='buildstatus'>"); table.AppendLine("<tr><td>Lane</td><td>Host</td><td>Revision</td><td>State</td><td>StartTime</td><td>Completed</td><td>Duration</td><td>Commands</td></tr>"); for (int i = 0; i < response.RevisionWorks.Count; i++) { DBRevisionWork rw = response.RevisionWorks [i]; string lane = response.Lanes [i]; string revision = response.Revisions [i]; string host = response.Hosts [i]; DateTime starttime = response.StartTime [i].ToLocalTime(); int duration = response.Durations [i]; table.Append("<tr>"); table.AppendFormat("<td><a href='ViewTable.aspx?lane_id={1}&host_id={2}'>{0}</a></td>", lane, rw.lane_id, rw.host_id); table.AppendFormat("<td>{0}</td>", host); table.AppendFormat("<td><a href='ViewLane.aspx?lane_id={0}&host_id={1}&revision_id={2}'>{3}</a></td>", rw.lane_id, rw.host_id, rw.revision_id, revision); table.AppendFormat("<td class='{0}'>{1}</td>", rw.State.ToString().ToLower(), rw.State.ToString()); table.AppendFormat("<td>{0}</td>", starttime.ToString("yyyy/MM/dd HH:mm:ss UTC")); table.AppendFormat("<td>{0}</td>", rw.completed ? "Yes" : "No"); table.AppendFormat("<td>{0}</td>", TimeSpan.FromSeconds(duration).ToString()); table.AppendFormat("<td>" + "<a href='ViewHostHistory.aspx?lane_id={0}&host_id={1}&revision_id={2}&masterhost_id={3}&action=clearrevision'>Reset work</a> " + "<a href='ViewHostHistory.aspx?lane_id={0}&host_id={1}&revision_id={2}&masterhost_id={3}&action=deleterevision'>Delete work</a> " + "<a href='ViewHostHistory.aspx?lane_id={0}&host_id={1}&revision_id={2}&masterhost_id={3}&action=abortrevision'>Abort work</a> " + "</td>", rw.lane_id, rw.workhost_id, rw.revision_id, rw.host_id); table.AppendLine("</tr>"); } table.AppendLine("</table>"); hosthistory.InnerHtml = table.ToString(); } catch (Exception ex) { Response.Write(HttpUtility.HtmlEncode(ex.ToString()).Replace("\n", "<br/>")); } }
protected override void Notify(DBWork work, DBRevisionWork revision_work, List <DBPerson> people, string message) { if (identity.servers.Contains("hooks.slack.com") || identity.servers.Contains("hooks-slack-com")) { NotifySlack(work, revision_work, people, message); return; } log.DebugFormat("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)) { log.DebugFormat("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); } } }
protected override void Notify(DBWork work, DBRevisionWork revision_work, List <DBPerson> people, string message) { if (!this.emails.Any()) { log.DebugFormat("Notify no emails"); return; } if (this.emails.Any(x => !x.EndsWith("@hipchat.xamarin.com", StringComparison.OrdinalIgnoreCase))) { log.Warn("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()) { log.Debug("Notify no actionable emails!"); return; } log.DebugFormat("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)) { log.DebugFormat("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)) { log.DebugFormat("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); log.DebugFormat("response from server: {0}", resString); } }
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) { var msg = nick + ": " + message; if (cache [msg] != null) { continue; } cache.Add(msg, string.Empty, new DateTimeOffset(DateTime.UtcNow.AddHours(1), TimeSpan.Zero)); state.Client.SendMessage(SendType.Message, channel, nick + ": " + message, Priority.Critical); } } if (!identity.join_channels) { Disconnect(state); } } }