상속: DBRecord
예제 #1
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);
			}
		}
예제 #2
0
		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);
					}
				}
			}
		}
예제 #3
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));
		}
예제 #4
0
		public void UploadLinks (WebServiceLogin login, DBWork work, string [] links)
		{
			using (DB db = new DB ()) {
				VerifyUserInRole (db, login, Roles.BuildBot, true);
				using (var cmd = db.CreateCommand ()) {
					StringBuilder sql = new StringBuilder ();
					for (int i = 0; i < links.Length; i++) {
						sql.AppendFormat ("INSERT INTO FileLink (link, work_id) VALUES (@link{0}, {1});", i, work.id);
						DB.CreateParameter (cmd, "link" + i.ToString (), links [i]);
					}
					cmd.CommandText = sql.ToString ();
					cmd.ExecuteNonQuery ();
				}
			}
		}
예제 #5
0
		public DBState GetWorkState (WebServiceLogin login, DBWork work)
		{
			using (DB db = new DB ()) {
				VerifyUserInRole (db, login, Roles.BuildBot, true);
				work.Reload (db);
				return work.State;
			}
		}
예제 #6
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);
		}
예제 #7
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);
			}
		}
예제 #8
0
		public static void BroadcastBuildNotification (DBWork work, DBRevisionWork revisionWork)
		{
			BroadcastBuildNotification (new Lazy<Build> (() => GetBuildFromDBItems (work, revisionWork)));
		}
예제 #9
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
			};
		}
예제 #10
0
		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 DBWork GetNextStep (string lane)
		{
			DBWork result = null;

			using (IDbCommand cmd = CreateCommand ()) {
				cmd.CommandText = "SELECT * FROM steps WHERE lane = @lane AND (state = 0 OR state = 1) ORDER BY revision DESC, sequence LIMIT 1";
				DB.CreateParameter (cmd, "lane", lane);
				using (IDataReader reader = cmd.ExecuteReader ()) {
					while (reader.Read ()) {
						if (result != null)
							throw new Exception ("Got more than one step");
						result = new DBWork ();
						result.Load (reader);
					}
				}
			}

			return result;
		}
예제 #12
0
		public ReportBuildStateResponse ReportBuildState (WebServiceLogin login, DBWork work)
		{
			ReportBuildStateResponse response = new ReportBuildStateResponse ();

			using (DB db = new DB ()) {
				VerifyUserInRole (db, login, Roles.BuildBot, true);
				Logger.Log (2, "ReportBuildState, state: {0}, start time: {1}, end time: {2}", work.State, work.starttime, work.endtime);
				if (work.starttime > new DateTime (2000, 1, 1) && work.endtime < work.starttime) {
					// the issue here is that the server interprets the datetime as local time, while it's always as utc.
					try {
						using (IDbCommand cmd = db.CreateCommand ()) {
							cmd.CommandText = "SELECT starttime FROM Work WHERE id = " + work.id;
							work.starttime = (DateTime) cmd.ExecuteScalar ();
						}
					} catch (Exception ex) {
						Logger.Log ("ReportBuildState: Exception while fixing timezone data: {0}", ex.Message);
					}
				}
				work.Save (db);
				work.Reload (db);

				response.Work = work;

				DBRevisionWork rw = DBRevisionWork_Extensions.Create (db, work.revisionwork_id);
				bool was_completed = rw.completed;
				rw.UpdateState (db);
				if (!was_completed && rw.completed) {
					rw.endtime = DBRecord.DatabaseNow;
					rw.Save (db);
				}
				response.RevisionWorkCompleted = rw.completed;

				MonkeyWrench.Web.WebService.Notifications.Notify (work, rw);

				return response;
			}
		}
예제 #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
		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;
			}
		}
예제 #16
0
		private static void UpdateBuildLogDB (DB db, DBLane lane, List<DBHost> hosts, List<DBHostLane> hostlanes)
		{
			List<DBRevision> revisions;
			List<DBCommand> commands = null;
			List<DBLaneDependency> dependencies = null;
			DBHostLane hostlane;
			DBWork work;
			bool got_dependencies = false;
			bool got_commands = false;

			try {
				Logger.Log ("Updating build db log... Got {0} hosts", hosts.Count);
				foreach (DBHost host in hosts) {
					hostlane = null;
					for (int i = 0; i < hostlanes.Count; i++) {
						if (hostlanes [i].lane_id == lane.id && hostlanes [i].host_id == host.id) {
							hostlane = hostlanes [i];
							break;
						}
					}
					if (hostlane == null) {
						Logger.Log ("Lane '{0}' is not configured for host '{1}', not adding any work.", lane.lane, host.host);
						continue;
					} else if (!hostlane.enabled) {
						Logger.Log ("Lane '{0}' is disabled for host '{1}', not adding any work.", lane.lane, host.host);
						continue;
					}

					AddRevisionWork (db, lane, host);

					revisions = db.GetDBRevisionsWithoutWork (lane.id, host.id);

					Logger.Log ("Updating build db log... Got {0} revisions for host {1}", revisions.Count, host.host);

					foreach (DBRevision revision in revisions) {
						bool dependencies_satisfied = true;

						if (!got_commands) {
							commands = db.GetCommands (lane.id);
							got_commands = true;
						}

						if (!got_dependencies) {
							dependencies = DBLaneDependency_Extensions.GetDependencies (db, lane);
							got_dependencies = true;
						}

						if (dependencies != null) {
							Logger.Log ("Lane '{0}', revision '{1}' checking dependencies...", lane.lane, revision.revision);

							foreach (DBLaneDependency dependency in dependencies)
								dependencies_satisfied &= dependency.IsSuccess (db, revision.revision);

							Logger.Log ("Lane '{0}', revision '{1}' dependency checking resulted in: {2}.", lane.lane, revision.revision, dependencies_satisfied);
						}

						int revisionwork_id;
						bool pending_dependencies;

						using (IDbCommand cmd = db.CreateCommand ()) {
							cmd.CommandText = "SELECT add_revisionwork (@lane_id, @host_id, @revision_id);";
							DB.CreateParameter (cmd, "lane_id", lane.id);
							DB.CreateParameter (cmd, "host_id", host.id);
							DB.CreateParameter (cmd, "revision_id", revision.id);
							revisionwork_id = (int) cmd.ExecuteScalar ();
						}

						using (IDbCommand cmd = db.CreateCommand ()) {
							cmd.CommandText = "SELECT state FROM RevisionWork WHERE id = @id;";
							DB.CreateParameter (cmd, "id", revisionwork_id);
							pending_dependencies = (int) DBState.DependencyNotFulfilled == (int) cmd.ExecuteScalar ();
						}

						if (pending_dependencies && !dependencies_satisfied)
							continue;

						Logger.Log ("Pending dependencies: {0}", pending_dependencies);

						foreach (DBCommand command in commands) {
							work = null;
							if (pending_dependencies) {
								using (IDbCommand cmd = db.CreateCommand ()) {
									cmd.CommandText = "SELECT * FROM Work WHERE revisionwork_id = @revisionwork_id AND command_id = @command_id;";
									DB.CreateParameter (cmd, "revisionwork_id", revisionwork_id);
									DB.CreateParameter (cmd, "command_id", command.id);
									using (IDataReader reader = cmd.ExecuteReader ()) {
										if (reader.Read ())
											work = new DBWork (reader);
									}
								}
							}

							if (work == null) {
								work = new DBWork ();
								work.command_id = command.id;
								work.revisionwork_id = revisionwork_id;
							}
							work.State = dependencies_satisfied ? DBState.NotDone : DBState.DependencyNotFulfilled;
							work.Save (db);
							Logger.Log ("Saved revision {0}, host {2}, command {1}", revision.revision, command.command, host.host);
						}

						if (!dependencies_satisfied) {
							db.ExecuteScalar (string.Format ("UPDATE RevisionWork SET state = 9 WHERE id = {0} AND state = 0;", revisionwork_id));
						} else {
							db.ExecuteScalar (string.Format ("UPDATE RevisionWork SET state = 0 WHERE id = {0} AND state = 9;", revisionwork_id));
						}
					}
				}
			} catch (Exception ex) {
				Logger.Log ("There was an exception while updating build db: {0}", ex.ToString ());
			}
			Logger.Log ("Updating build db log... [Done]");
		}
예제 #17
0
		protected abstract void Notify (DBWork work, DBRevisionWork revision_work, List<DBPerson> people, string message);
예제 #18
0
		public ReportBuildStateResponse ReportBuildState (WebServiceLogin login, DBWork work)
		{
			ReportBuildStateResponse response = new ReportBuildStateResponse ();

			using (DB db = new DB ()) {
				VerifyUserInRole (db, login, Roles.BuildBot, true);
				Logger.Log (2, "ReportBuildState, state: {0}, start time: {1}, end time: {2}", work.State, work.starttime, work.endtime);
				if (work.starttime > new DateTime (2000, 1, 1) && work.endtime < work.starttime) {
					// the issue here is that the server interprets the datetime as local time, while it's always as utc.
					try {
						using (IDbCommand cmd = db.CreateCommand ()) {
							cmd.CommandText = "SELECT starttime FROM Work WHERE id = " + work.id;
							work.starttime = (DateTime) cmd.ExecuteScalar ();
						}
					} catch (Exception ex) {
						Logger.Log ("ReportBuildState: Exception while fixing timezone data: {0}", ex.Message);
					}
				}
				work.Save (db);
				work.Reload (db);

				response.Work = work;

				DBRevisionWork rw = DBRevisionWork_Extensions.Create (db, work.revisionwork_id);
				bool was_completed = rw.completed;
				rw.UpdateState (db);
				if (!was_completed && rw.completed) {
					rw.endtime = DBRecord.DatabaseNow;
					rw.Save (db);
				}
				response.RevisionWorkCompleted = rw.completed;

				using (var cmd = db.CreateCommand ()) {
					cmd.CommandText = "UPDATE Lane SET changed_date = @date WHERE id = @id;";
					DB.CreateParameter (cmd, "date", DateTime.UtcNow);
					DB.CreateParameter (cmd, "id", rw.lane_id);
					cmd.ExecuteNonQuery ();
				}

				Notifications.Notify (work, rw);

				// Check if any other lane depends on this one
				if (response.RevisionWorkCompleted) {
					using (IDbCommand cmd = db.CreateCommand ()) {
						cmd.CommandText = "SELECT id FROM LaneDependency WHERE dependent_lane_id = @lane_id LIMIT 1;";
						DB.CreateParameter (cmd, "lane_id", rw.lane_id);

						object value = cmd.ExecuteScalar ();
						if (value != null && value.GetType () == typeof (int)) {
							// If so, run the scheduler
							MonkeyWrench.Scheduler.Scheduler.ExecuteSchedulerAsync (false);
						}
					}
				}

				return response;
			}
		}
예제 #19
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);
			}
		}
예제 #20
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);
				}
			}
		}
예제 #21
0
		public void UploadCompressedFile (WebServiceLogin login, DBWork work, string filename, byte [] contents, bool hidden, string compressed_mime)
		{
			using (DB db = new DB ()) {
				VerifyUserInRole (db, login, Roles.BuildBot, true);

				string tmp = null;
				try {
					tmp = Path.GetTempFileName ();
					File.WriteAllBytes (tmp, contents);
					work.AddFile (db, tmp, filename, hidden, compressed_mime);
				} finally {
					if (!string.IsNullOrEmpty (tmp)) {
						try {
							File.Delete (tmp);
						} catch {
							// ignore exceptions
						}
					}
				}
			}
		}
예제 #22
0
		/**
		 * 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);
		}
예제 #23
0
		public void UploadFile (WebServiceLogin login, DBWork work, string filename, byte [] contents, bool hidden)
		{
			UploadCompressedFile (login, work, filename, contents, hidden, null);
		}
예제 #24
0
		// 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 ();
		}
예제 #25
0
		public ReportBuildStateResponse ReportBuildState (WebServiceLogin login, DBWork work)
		{
			ReportBuildStateResponse response = new ReportBuildStateResponse ();

			using (DB db = new DB ())
			using (var transaction = db.BeginTransaction ()) {
				VerifyUserInRole (db, login, Roles.BuildBot, true);
				log.DebugFormat ("ReportBuildState, state: {0}, start time: {1}, end time: {2}", work.State, work.starttime, work.endtime);
				if (work.starttime > new DateTime (2000, 1, 1) && work.endtime < work.starttime) {
					// the issue here is that the server interprets the datetime as local time, while it's always as utc.
					try {
						using (IDbCommand cmd = db.CreateCommand ()) {
							cmd.CommandText = "SELECT starttime FROM Work WHERE id = " + work.id;
							var value = cmd.ExecuteScalar ();
							if (value is DateTime)
								work.starttime = (DateTime) value;
						}
					} catch (Exception ex) {
						log.ErrorFormat ("ReportBuildState: Exception while fixing timezone data: {0}", ex);
					}
				}
				work.Save (db);
				work.Reload (db);

				response.Work = work;

				DBRevisionWork rw = DBRevisionWork_Extensions.Create (db, work.revisionwork_id);
				bool was_completed = rw.completed;
				rw.UpdateState (db);

				if (rw.startedtime == null) {
					rw.startedtime = work.starttime;
					rw.Save (db);
				}

				if (!was_completed && rw.completed) {
					rw.endtime = DBRecord.DatabaseNow;
					rw.Save (db);
				}

				Notifications.Notify (work, rw);

				if (!was_completed && rw.completed) {
					var notifyInfo = new GenericNotificationInfo ();
					notifyInfo.laneID = rw.lane_id;
					notifyInfo.hostID = rw.host_id;
					notifyInfo.revisionID = rw.revision_id;
					notifyInfo.message = "Completed";
					notifyInfo.state = rw.State;

					Notifications.NotifyGeneric (notifyInfo);
				}
				response.RevisionWorkCompleted = rw.completed;

				using (var cmd = db.CreateCommand ()) {
					cmd.CommandText = "UPDATE Lane SET changed_date = @date WHERE id = @id;";
					DB.CreateParameter (cmd, "date", DateTime.UtcNow);
					DB.CreateParameter (cmd, "id", rw.lane_id);
					cmd.ExecuteNonQuery ();
				}

				// Check if any other lane depends on this one
				if (response.RevisionWorkCompleted) {
					using (IDbCommand cmd = db.CreateCommand ()) {
						cmd.CommandText = "SELECT 1 FROM LaneDependency WHERE dependent_lane_id = @lane_id LIMIT 1;";
						DB.CreateParameter (cmd, "lane_id", rw.lane_id);

						object value = cmd.ExecuteScalar ();
						if (value is int) {
							// If so, run the scheduler
							MonkeyWrench.Scheduler.Scheduler.ExecuteSchedulerAsync (false);
						}
					}
				}

				transaction.Commit ();
				return response;
			}
		}
예제 #26
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;
			}
		}