// Returns null if the report is empty protected static string GenerateReport( Alert alert, string htmlTemplate, IEnumerable <DataModelIssue> beginIssues, IEnumerable <DataModelIssue> endIssues, IEnumerable <Label> areaLabels) { IEnumerable <DataModelIssue> beginQuery = alert.Query.Evaluate(beginIssues); IEnumerable <DataModelIssue> endQuery = alert.Query.Evaluate(endIssues); IEnumerable <DataModelIssue> goneIssues = beginQuery.Except_ByIssueNumber(endQuery); IEnumerable <DataModelIssue> newIssues = endQuery.Except_ByIssueNumber(beginQuery); if (goneIssues.None() && newIssues.None()) { Console.WriteLine(" No changes to the query, skipping."); Console.WriteLine(); return(null); } string text = htmlTemplate; text = text.Replace("%ISSUES_LINKED_COUNTS%", AlertReport.GetLinkedCount("", newIssues.Concat(goneIssues))); IEnumerable <IssueEntry> newIssueEntries = newIssues .Select(issue => new IssueEntry(issue, IssueEntry.EntryKind.New)); IEnumerable <IssueEntry> goneIssueEntries = goneIssues .Select(issue => { DataModelIssue newIssue = endIssues.FirstOrNull_ByIssueNumber(issue); if (newIssue == null) { // Closed issue return(new IssueEntry(issue, IssueEntry.EntryKind.Closed)); } return(new IssueEntry(newIssue, IssueEntry.EntryKind.Moved, areaLabels, "moved_area")); }); text = text.Replace("%ISSUES_TABLE%", FormatIssueTable(newIssueEntries.Concat(goneIssueEntries) .OrderBy(entry => entry.OrderType) .ThenBy(entry => entry.IssueNumber))); return(text); }
// Returns null if the report is empty protected static string GenerateReport( Alert alert, string htmlTemplate, IEnumerable <DataModelIssue> issues, IEnumerable <string> inputFiles, ExpressionUntriaged untriagedExpression) { IEnumerable <DataModelIssue> matchingIssues = alert.Query.Evaluate(issues); var untriagedFlagsMap = new Dictionary <DataModelIssue, ExpressionUntriaged.Flags>(); foreach (DataModelIssue issue in matchingIssues) { ExpressionUntriaged.Flags flags = untriagedExpression.GetUntriagedFlags(issue); if (flags != 0) { untriagedFlagsMap[issue] = flags; } } if (untriagedFlagsMap.None()) { Console.WriteLine(" No untriaged issues, skipping."); Console.WriteLine(); return(null); } string text = htmlTemplate; text = text.Replace("%UNTRIAGED_ISSUES_START%", ""); text = text.Replace("%UNTRIAGED_ISSUES_END%", ""); text = text.Replace("%UNTRIAGED_ISSUES_LINKED_COUNTS%", AlertReport.GetLinkedCount("is:issue is:open", untriagedFlagsMap.Keys)); IEnumerable <IssueEntry> untriagedIssueEntries = untriagedFlagsMap.Keys.Select(issue => new IssueEntry(issue)); text = text.Replace("%UNTRIAGED_ISSUES_TABLE%", FormatIssueTable(untriagedFlagsMap)); text = text.Replace("%INPUT_FILES_LIST%", FormatInputFilesList(inputFiles)); return(text); }
// Returns null if the report is empty protected static string GenerateReport( Alert alert, string htmlTemplate, IEnumerable <DataModelIssue> issues, IEnumerable <DataModelIssue> comments) { // Create a Dictionary mapping issues to comments for that issue Dictionary <int, List <DataModelIssue> > issueComments = new Dictionary <int, List <DataModelIssue> >(); Dictionary <int, DataModelIssue> issuesMap = new Dictionary <int, DataModelIssue>(); IEnumerable <DataModelIssue> matchingIssues = alert.Query.Evaluate(issues); if (matchingIssues.None()) { Console.WriteLine(" No changes to the query, skipping."); Console.WriteLine(); return(null); } foreach (DataModelIssue issue in matchingIssues) { issueComments.Add(issue.Number, new List <DataModelIssue>()); issuesMap.Add(issue.Number, issue); } foreach (DataModelIssue comment in comments) { int startIndex = comment.HtmlUrl.IndexOf("/issues/") + 8; if (startIndex < 8) { startIndex = comment.HtmlUrl.IndexOf("/pull/") + 6; } int endIndex = comment.HtmlUrl.IndexOf("#"); string issueString = comment.HtmlUrl.Substring(startIndex, endIndex - startIndex); int issueID = int.Parse(issueString); if (issueComments.ContainsKey(issueID)) { issueComments[issueID].Add(comment); } } // Filter our issues to ones that haven't had an owner response after our grace waiting period Dictionary <DataModelIssue, TimeSpan?> needsResponse = new Dictionary <DataModelIssue, TimeSpan?>(); foreach (KeyValuePair <int, List <DataModelIssue> > pair in issueComments) { TimeSpan?lastComment; // First check if there are no comments and the issue was opened past the threshold. if (pair.Value.Count == 0 && ((lastComment = (DateTime.Now - issuesMap[pair.Key].CreatedAt)) > _acceptableResponseDelay)) { needsResponse.Add(issuesMap[pair.Key], lastComment); } // Next check if the last issue occurred past the threshold else if (pair.Value.Count > 0 && ((lastComment = (DateTime.Now - pair.Value.Max((issue) => issue.CreatedAt))) > _acceptableResponseDelay)) { needsResponse.Add(issuesMap[pair.Key], lastComment); } } if (needsResponse.None()) { Console.WriteLine(" No changes to the query, skipping."); Console.WriteLine(); return(null); } string text = htmlTemplate; text = text.Replace("%NEEDSMSRESPONSE_ACCEPTABLE_RESPONSE_DELAY%", _acceptableResponseDelay.Days.ToString()); text = text.Replace("%NEEDSMSRESPONSE_ISSUES_START%", ""); text = text.Replace("%NEEDSMSRESPONSE_ISSUES_END%", ""); text = text.Replace("%NEEDSMSRESPONSE_ISSUES_LINKED_COUNTS%", AlertReport.GetLinkedCount("is:issue is:open", needsResponse.Keys)); text = text.Replace("%NEEDSMSRESPONSE_ISSUES_COUNT%", needsResponse.Count().ToString()); text = text.Replace("%NEEDSMSRESPONSE_ISSUES_TABLE%", FormatIssueTable(needsResponse.OrderByDescending((pair) => pair.Value.Value.Days))); return(text); }