示例#1
0
		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);
					}
				}
			}
		}
示例#5
0
		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);
				}
			}
		}
示例#6
0
		protected abstract void Notify (DBWork work, DBRevisionWork revision_work, List<DBPerson> people, string message);
示例#7
0
		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);
			}
		}
示例#8
0
		/// <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;
				}
			}
		}
示例#9
0
		/// <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);
		}
示例#11
0
		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;
		}
示例#12
0
		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) }
			};
		}
示例#13
0
		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);
			}
		}
示例#14
0
		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 });
		}
示例#15
0
		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;
				}
			}
		}
示例#17
0
		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;
			}
		}
示例#18
0
		public static void BroadcastBuildNotification (DBWork work, DBRevisionWork revisionWork)
		{
			BroadcastBuildNotification (new Lazy<Build> (() => GetBuildFromDBItems (work, revisionWork)));
		}
示例#19
0
		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);
		}
示例#20
0
		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
			};
		}
示例#21
0
		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);
			}
		}
示例#22
0
		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;
			}
		}