protected override async Task ExecuteCoreAsync(ReportExecutionContext context) { context.Log.LogInformation($"Started function execution: {DateTime.Now}"); var storageConnString = Environment.GetEnvironmentVariable("AzureWebJobsStorage"); BlobServiceClient bsc = new BlobServiceClient(storageConnString); BlobContainerClient bcc = bsc.GetBlobContainerClient(ContainerName); // create the container bcc.CreateIfNotExists(); context.Log.LogInformation("Storage account accessed"); DateTime to = DateTime.UtcNow; foreach (RepositoryConfiguration repositoryConfiguration in context.RepositoryConfigurations) { // retrieve the last accessed time for this repository BlobClient bc = bcc.GetBlobClient($"{repositoryConfiguration.Owner}_{repositoryConfiguration.Name}"); DateTime lastDateRun = DateTime.UtcNow.AddDays(-1); try { string content = StreamHelpers.GetContentAsString(bc.Download().Value.Content); lastDateRun = DateTime.Parse(content); } catch { } context.Log.LogInformation("Last processed date for {0} is {1}", repositoryConfiguration, lastDateRun); string owner = repositoryConfiguration.Owner; string repo = repositoryConfiguration.Name; context.Log.LogInformation("Processing repository {0}\\{1}", owner, repo); HtmlPageCreator emailBody = new HtmlPageCreator($"New items in {repo}"); // get new issues RetrieveNewItems(context, CreateQueryForNewItems(repositoryConfiguration, IssueIsQualifier.Issue), lastDateRun, emailBody, "New issues"); // get new PRs RetrieveNewItems(context, CreateQueryForNewItems(repositoryConfiguration, IssueIsQualifier.PullRequest), lastDateRun, emailBody, "New PRs"); // get needs attention issues RetrieveNeedsAttentionIssues(context, repositoryConfiguration, emailBody); emailBody.AddContent($"<p>Last checked range: {lastDateRun} -> {to} </p>"); context.Log.LogInformation("Sending email..."); // send the email EmailSender.SendEmail(context.SendGridToken, context.FromAddress, emailBody.GetContent(), repositoryConfiguration.ToEmail, repositoryConfiguration.CcEmail, $"New issues in the {repo} repo as of {to.ToShortDateString()}", context.Log); context.Log.LogInformation("Email sent..."); bc.Upload(StreamHelpers.GetStreamForString(to.ToUniversalTime().ToString()), overwrite: true); context.Log.LogInformation($"Persisted last event time for {repositoryConfiguration.Owner}\\{repositoryConfiguration.Name} as {to}"); } }
public override void Execute() { foreach (RepositoryConfig repositoryConfig in _cmdLine.RepositoriesList) { HtmlPageCreator emailBody = new HtmlPageCreator($"Pull Requests older than 3 months in {repositoryConfig.Name}"); bool hasFoundPRs = FindStalePRsInRepo(repositoryConfig, emailBody); if (hasFoundPRs) { // send the email EmailSender.SendEmail(_cmdLine.EmailToken, _cmdLine.FromEmail, emailBody.GetContent(), repositoryConfig.ToEmail, repositoryConfig.CcEmail, $"Pull Requests older than 3 months in {repositoryConfig.Name}", _log); } } }
public override void Execute() { foreach (var repositoryConfig in _cmdLine.RepositoriesList) { HtmlPageCreator emailBody = new HtmlPageCreator($"Customer reported issues with invalid state in {repositoryConfig.Repo}"); bool hasFoundIssues = ValidateCustomerReportedIssues(repositoryConfig, emailBody); if (hasFoundIssues) { // send the email EmailSender.SendEmail(_cmdLine.EmailToken, _cmdLine.FromEmail, emailBody.GetContent(), repositoryConfig.ToEmail, repositoryConfig.CcEmail, $"Customer reported issues in invalid state in repo {repositoryConfig.Repo}", _log); } } }
public override void Execute() { foreach (RepositoryConfig repositoryConfig in _cmdLine.RepositoriesList) { HtmlPageCreator emailBody = new HtmlPageCreator($"Issues in expired milestones for {repositoryConfig.Name}"); bool hasFoundIssues = GetIssuesInBacklogMilestones(repositoryConfig, emailBody); if (hasFoundIssues) { // send the email EmailSender.SendEmail(_cmdLine.EmailToken, _cmdLine.FromEmail, emailBody.GetContent(), repositoryConfig.ToEmail, repositoryConfig.CcEmail, $"Issues in old milestone for {repositoryConfig.Name}", _log); } } }
protected override async Task ExecuteCoreAsync(ReportExecutionContext context) { foreach (RepositoryConfiguration repositoryConfiguration in context.RepositoryConfigurations) { HtmlPageCreator emailBody = new HtmlPageCreator($"Pull Requests older than 3 months in {repositoryConfiguration.Name}"); bool hasFoundPRs = FindStalePRsInRepo(context, repositoryConfiguration, emailBody); if (hasFoundPRs) { // send the email EmailSender.SendEmail(context.SendGridToken, context.FromAddress, emailBody.GetContent(), repositoryConfiguration.ToEmail, repositoryConfiguration.CcEmail, $"Pull Requests older than 3 months in {repositoryConfiguration.Name}", context.Log); } } }
protected override async Task ExecuteCoreAsync(ReportExecutionContext context) { foreach (RepositoryConfiguration repositoryConfiguration in context.RepositoryConfigurations) { HtmlPageCreator emailBody = new HtmlPageCreator($"Customer reported issues with invalid state in {repositoryConfiguration.Name}"); bool hasFoundIssues = ValidateCustomerReportedIssues(context, repositoryConfiguration, emailBody); if (hasFoundIssues) { // send the email EmailSender.SendEmail(context.SendGridToken, context.FromAddress, emailBody.GetContent(), repositoryConfiguration.ToEmail, repositoryConfiguration.CcEmail, $"Customer reported issues in invalid state in repo {repositoryConfiguration.Name}", context.Log); } } }
protected override async Task ExecuteCoreAsync(ReportExecutionContext context) { foreach (RepositoryConfiguration repositoryConfiguration in context.RepositoryConfigurations) { HtmlPageCreator emailBody = new HtmlPageCreator($"Issues in expired milestones for {repositoryConfiguration.Name}"); bool hasFoundIssues = GetIssuesInBacklogMilestones(context, repositoryConfiguration, emailBody); if (hasFoundIssues) { // send the email EmailSender.SendEmail(context.SendGridToken, context.FromAddress, emailBody.GetContent(), repositoryConfiguration.ToEmail, repositoryConfiguration.CcEmail, $"Issues in old milestone for {repositoryConfiguration.Name}", context.Log); } } }
protected override async Task ExecuteCoreAsync(ReportExecutionContext context) { foreach (RepositoryConfiguration repositoryConfiguration in context.RepositoryConfigurations) { await ExecuteWithRetryAsync(3, async() => { HtmlPageCreator emailBody = new HtmlPageCreator($"Test related issues in {repositoryConfiguration.Name}"); bool hasFoundIssues = FindIssuesWithLabel(context, repositoryConfiguration, emailBody); if (hasFoundIssues) { // send the email EmailSender.SendEmail(context.SendGridToken, context.FromAddress, emailBody.GetContent(), repositoryConfiguration.ToEmail, repositoryConfiguration.CcEmail, $"Issues with test-* labels for {repositoryConfiguration.Name}", Logger); } }); } }
private bool FindStalePRsInRepo(RepositoryConfig repositoryConfig, HtmlPageCreator emailBody) { TableCreator tc = new TableCreator($"Pull Requests older than {DateTime.Now.AddMonths(-3).ToShortDateString()}"); tc.DefineTableColumn("Title", TableCreator.Templates.Title); tc.DefineTableColumn("Labels", TableCreator.Templates.Labels); tc.DefineTableColumn("Author", TableCreator.Templates.Author); tc.DefineTableColumn("Assigned", TableCreator.Templates.Assigned); _log.LogInformation($"Retrieving PR information for repo {repositoryConfig.Name}"); List <ReportIssue> oldPrs = new List <ReportIssue>(); foreach (Issue issue in _gitHub.SearchForGitHubIssues(CreateQuery(repositoryConfig))) { _log.LogInformation($"Found stale PR {issue.Number}"); oldPrs.Add(new ReportIssue() { Issue = issue, Note = string.Empty, Milestone = null }); } emailBody.AddContent(tc.GetContent(oldPrs)); return(oldPrs.Any()); }
private bool RetrieveNeedsAttentionIssues(RepositoryConfig repositoryConfig, HtmlPageCreator emailBody) { TableCreator tc = new TableCreator("Issues that need attention"); tc.DefineTableColumn("Title", TableCreator.Templates.Title); tc.DefineTableColumn("Labels", TableCreator.Templates.Labels); tc.DefineTableColumn("Author", TableCreator.Templates.Author); tc.DefineTableColumn("Assigned", TableCreator.Templates.Assigned); List <ReportIssue> issues = new List <ReportIssue>(); foreach (Issue issue in _gitHub.SearchForGitHubIssues(CreateQueryForNeedsAttentionItems(repositoryConfig))) { issues.Add(new ReportIssue() { Issue = issue, Milestone = issue.Milestone, Note = string.Empty }); } emailBody.AddContent(tc.GetContent(issues)); return(issues.Any()); }
private bool FindIssuesInPastDuesMilestones(ReportExecutionContext context, RepositoryConfiguration repositoryConfig, HtmlPageCreator emailBody) { TableCreator tc = new TableCreator("Issues in past-due milestones"); tc.DefineTableColumn("Milestone", TableCreator.Templates.Milestone); tc.DefineTableColumn("Title", TableCreator.Templates.Title); tc.DefineTableColumn("Labels", TableCreator.Templates.Labels); tc.DefineTableColumn("Author", TableCreator.Templates.Author); tc.DefineTableColumn("Assigned", TableCreator.Templates.Assigned); context.Log.LogInformation($"Retrieving milestone information for repo {repositoryConfig.Name}"); IEnumerable <Milestone> milestones = context.GitHubClient.ListMilestones(repositoryConfig).GetAwaiter().GetResult(); List <Milestone> pastDueMilestones = new List <Milestone>(); foreach (Milestone item in milestones) { if (item.DueOn != null && DateTimeOffset.Now > item.DueOn) { context.Log.LogWarning($"Milestone {item.Title} past due ({item.DueOn.Value}) has {item.OpenIssues} open issue(s)."); if (item.OpenIssues > 0) { pastDueMilestones.Add(item); } } } context.Log.LogInformation($"Found {pastDueMilestones.Count} past due milestones with active issues"); List <ReportIssue> issuesInPastMilestones = new List <ReportIssue>(); foreach (Milestone item in pastDueMilestones) { context.Log.LogInformation($"Retrieve issues for milestone {item.Title}"); foreach (Issue issue in context.GitHubClient.SearchForGitHubIssues(CreateQuery(repositoryConfig, item))) { issuesInPastMilestones.Add(new ReportIssue() { Issue = issue, Milestone = item, Note = string.Empty }); } } emailBody.AddContent(tc.GetContent(issuesInPastMilestones)); return(issuesInPastMilestones.Any()); }
private bool GetIssuesInBacklogMilestones(RepositoryConfig repositoryConfig, HtmlPageCreator emailBody) { _log.LogInformation($"Retrieving milestone information for repo {repositoryConfig.Name}"); IEnumerable <Milestone> milestones = _gitHub.ListMilestones(repositoryConfig).GetAwaiter().GetResult(); List <Milestone> backlogMilestones = new List <Milestone>(); foreach (Milestone item in milestones) { if (item.DueOn == null) { _log.LogWarning($"Milestone {item.Title} has {item.OpenIssues} open issue(s)."); if (item.OpenIssues > 0) { backlogMilestones.Add(item); } } } _log.LogInformation($"Found {backlogMilestones.Count} past due milestones with active issues"); List <ReportIssue> issuesInBacklogMilestones = new List <ReportIssue>(); foreach (Milestone item in backlogMilestones) { _log.LogInformation($"Retrieve issues for milestone {item.Title}"); foreach (Issue issue in _gitHub.SearchForGitHubIssues(CreateQuery(repositoryConfig, item))) { issuesInBacklogMilestones.Add(new ReportIssue() { Issue = issue, Milestone = item, Note = string.Empty }); } } // Split the list into 3: // > 12months // > 6months // 0-6months IEnumerable <IGrouping <string, ReportIssue> > groups = issuesInBacklogMilestones.GroupBy(i => i.Issue.CreatedAt > DateTime.Now.AddMonths(-6) ? "C. Issues created in the last 6 months" : i.Issue.CreatedAt <= DateTime.Now.AddMonths(-6) && i.Issue.CreatedAt > DateTime.Now.AddMonths(-12) ? "B. Issues created between 6 and 12 months ago" : "A. Issues created more than 12 months ago"); foreach (IGrouping <string, ReportIssue> group in groups.OrderBy(g => g.Key)) { TableCreator tc = new TableCreator(group.Key); tc.DefineTableColumn("Milestone", TableCreator.Templates.Milestone); tc.DefineTableColumn("Created", i => i.Issue.CreatedAt.UtcDateTime.ToShortDateString()); tc.DefineTableColumn("Title", TableCreator.Templates.Title); tc.DefineTableColumn("Labels", TableCreator.Templates.Labels); tc.DefineTableColumn("Author", TableCreator.Templates.Author); tc.DefineTableColumn("Assigned", TableCreator.Templates.Assigned); emailBody.AddContent(tc.GetContent(group)); } return(issuesInBacklogMilestones.Any()); }
public override void Execute() { _log.LogInformation($"Started function execution: {DateTime.Now}"); var storageConnString = Environment.GetEnvironmentVariable("AzureWebJobsStorage"); BlobServiceClient bsc = new BlobServiceClient(storageConnString); BlobContainerClient bcc = bsc.GetBlobContainerClient(ContainerName); // create the container bcc.CreateIfNotExists(); _log.LogInformation("Storage account accessed"); DateTime to = DateTime.UtcNow; DateTime fromTwoDaysBack = DateTime.UtcNow.AddDays(-2); foreach (var repositoryConfig in _cmdLine.RepositoriesList) { // retrieve the last accessed time for this repository BlobClient bc = bcc.GetBlobClient($"{repositoryConfig.Owner}_{repositoryConfig.Repo}"); DateTime lastDateRun = DateTime.UtcNow.AddDays(-1); try { string content = StreamHelpers.GetContentAsString(bc.Download().Value.Content); lastDateRun = DateTime.Parse(content); } catch { } _log.LogInformation("Last processed date for {0} is {1}", repositoryConfig, lastDateRun); string owner = repositoryConfig.Owner; string repo = repositoryConfig.Repo; _log.LogInformation("Processing repository {0}\\{1}", owner, repo); HtmlPageCreator emailBody = new HtmlPageCreator($"New items in {repo}"); SearchIssuesRequest requestOptions = new SearchIssuesRequest() { #pragma warning disable CS0618 // Type or member is obsolete Created = DateRange.Between(fromTwoDaysBack, to), #pragma warning restore CS0618 // Type or member is obsolete Order = SortDirection.Descending, Repos = new RepositoryCollection() }; requestOptions.Repos.Add(owner, repo); // get the issues requestOptions.Is = new[] { IssueIsQualifier.Open, IssueIsQualifier.Issue }; RetrieveItemsFromGitHub(requestOptions, lastDateRun, emailBody, "New issues"); // get the PRs requestOptions.Is = new[] { IssueIsQualifier.Open, IssueIsQualifier.PullRequest }; RetrieveItemsFromGitHub(requestOptions, lastDateRun, emailBody, "New PRs"); emailBody.AddContent($"<p>Last checked range: {lastDateRun} -> {to} </p>"); _log.LogInformation("Sending email..."); // send the email EmailSender.SendEmail(_cmdLine.EmailToken, _cmdLine.FromEmail, emailBody.GetContent(), repositoryConfig.ToEmail, repositoryConfig.CcEmail, $"New issues in the {repo} repo as of {to.ToShortDateString()}", _log); _log.LogInformation("Email sent..."); bc.Upload(StreamHelpers.GetStreamForString(to.ToUniversalTime().ToString()), overwrite: true); _log.LogInformation($"Persisted last event time for {repositoryConfig.Owner}\\{repositoryConfig.Repo} as {to}"); } }
private bool RetrieveNewItems(ReportExecutionContext context, SearchIssuesRequest requestOptions, DateTime from, HtmlPageCreator emailBody, string header) { TableCreator tc = new TableCreator(header); tc.DefineTableColumn("Title", TableCreator.Templates.Title); tc.DefineTableColumn("State", i => i.Issue.State.ToString()); tc.DefineTableColumn("Labels", TableCreator.Templates.Labels); tc.DefineTableColumn("Author", TableCreator.Templates.Author); tc.DefineTableColumn("Assigned", TableCreator.Templates.Assigned); List <ReportIssue> issues = new List <ReportIssue>(); foreach (Issue issue in context.GitHubClient.SearchForGitHubIssues(requestOptions)) { if (issue.CreatedAt.ToUniversalTime() >= from.ToUniversalTime()) { issues.Add(new ReportIssue() { Issue = issue, Note = string.Empty, Milestone = null }); } } //sort the issues by state, descending becasue Open should show up before Closed emailBody.AddContent(tc.GetContent(issues.OrderByDescending(i => i.Issue.State.ToString()))); return(issues.Any()); }
private bool RetrieveItemsFromGitHub(SearchIssuesRequest requestOptions, DateTime from, HtmlPageCreator emailBody, string header) { TableCreator tc = new TableCreator(header); tc.DefineTableColumn("Title", TableCreator.Templates.Title); tc.DefineTableColumn("Labels", TableCreator.Templates.Labels); tc.DefineTableColumn("Author", TableCreator.Templates.Author); tc.DefineTableColumn("Assigned", TableCreator.Templates.Assigned); Colorizer.WriteLine("Retrieving issues"); List <ReportIssue> issues = new List <ReportIssue>(); foreach (var issue in _gitHub.SearchForGitHubIssues(requestOptions)) { if (issue.CreatedAt.ToUniversalTime() >= from.ToUniversalTime()) { issues.Add(new ReportIssue() { Issue = issue, Note = string.Empty, Milestone = null }); } } emailBody.AddContent(tc.GetContent(issues)); return(issues.Any()); }
private bool FindIssuesWithLabel(ReportExecutionContext context, RepositoryConfiguration repositoryConfig, HtmlPageCreator emailBody) { List <ReportIssue> testIssues = new List <ReportIssue>(); foreach (string label in _labels) { Logger.LogInformation($"Retrieve issues for label {label}"); foreach (Issue issue in context.GitHubClient.SearchForGitHubIssues(CreateQuery(repositoryConfig, label))) { testIssues.Add(new ReportIssue() { Issue = issue, Note = $"Label: {label}" }); } } IEnumerable <IGrouping <string, ReportIssue> > groups = testIssues.GroupBy(g => g.Note); foreach (IGrouping <string, ReportIssue> group in groups.OrderBy(g => g.Key)) { TableCreator tc = new TableCreator(group.Key); tc.DefineTableColumn("Milestone", TableCreator.Templates.Milestone); tc.DefineTableColumn("Title", TableCreator.Templates.Title); tc.DefineTableColumn("Labels", TableCreator.Templates.Labels); tc.DefineTableColumn("Author", TableCreator.Templates.Author); tc.DefineTableColumn("Assigned", TableCreator.Templates.Assigned); emailBody.AddContent(tc.GetContent(group)); } return(testIssues.Any()); }
private bool ValidateCustomerReportedIssues(ReportExecutionContext context, RepositoryConfiguration repositoryConfig, HtmlPageCreator emailBody) { TableCreator tc = new TableCreator("Customer reported issues"); tc.DefineTableColumn("Title", TableCreator.Templates.Title); tc.DefineTableColumn("Labels", TableCreator.Templates.Labels); tc.DefineTableColumn("Author", TableCreator.Templates.Author); tc.DefineTableColumn("Assigned", TableCreator.Templates.Assigned); tc.DefineTableColumn("Issues Found", i => i.Note); List <ReportIssue> issuesWithNotes = new List <ReportIssue>(); foreach (Issue issue in context.GitHubClient.SearchForGitHubIssues(CreateQuery(repositoryConfig))) { if (!ValidateIssue(issue, out string issuesFound)) { issuesWithNotes.Add(new ReportIssue() { Issue = issue, Note = issuesFound }); Logger.LogWarning($"{issue.Number}: {issuesFound}"); } } // order the issues by the list of issues they have. issuesWithNotes = issuesWithNotes.OrderBy(i => i.Note).ToList(); emailBody.AddContent(tc.GetContent(issuesWithNotes)); return(issuesWithNotes.Any()); }