Exemple #1
0
        private async Task ProcessOpenedTriageIssue(IssuesHookData issuePayload, IList <TriageItem> triageItems, IGitHubClient gitHubClient)
        {
            var issue = await gitHubClient.Issue.Get(issuePayload.Repository.Id, issuePayload.Issue.Number);

            if (!issue.Labels.Any(l => l.Name == _markingLabelName))
            {
                var update = issue.ToUpdate();
                update.AddLabel(_markingLabelName);
                foreach (var label in _issueLabels.Except(issue.Labels.Select(l => l.Name)))
                {
                    update.AddLabel(label);
                }
                await gitHubClient.Issue.Update(issuePayload.Repository.Id, issuePayload.Issue.Number, update);

                await AddToZenHubTopic(issuePayload, gitHubClient, issue);
            }

            foreach (var triageItem in triageItems)
            {
                triageItem.Url = issuePayload.Issue.HtmlUrl;
                _logger.LogInformation($"New triage item: {triageItem}");
            }
            await IngestTriageItemsIntoKusto(triageItems);

            await gitHubClient.Issue.Comment.Create(issuePayload.Repository.Id, issuePayload.Issue.Number, $"Bot has updated the 'TimelineIssuesTriage' database.\n**PowerBI reports may take up to 24 hours to refresh**\n\nSee {_docLink} for more information.");
        }
Exemple #2
0
        private async Task UpdateExistingIssue(IssuesHookData issuePayload, IList <TriageItem> triageItems, Issue existingIssueToUpdate, IGitHubClient gitHubClient)
        {
            var existingIssueItems = GetTriageItems(existingIssueToUpdate.Body);

            // update existing issue body
            var existintIssueUpdate = new IssueUpdate
            {
                Body = UpdateExistingIssueBody(issuePayload, triageItems, existingIssueToUpdate, existingIssueItems),
            };
            await gitHubClient.Issue.Update(issuePayload.Repository.Id, existingIssueToUpdate.Number, existintIssueUpdate);

            // insert TimelineIssuesTriage with existing issue URL
            var toBeUpdatedTriageItems = triageItems.Except(existingIssueItems).ToList();

            foreach (var triageItem in toBeUpdatedTriageItems)
            {
                triageItem.Url = existingIssueToUpdate.HtmlUrl;
                _logger.LogInformation($"buildId: {triageItem.BuildId}, recordId: {triageItem.RecordId}, index: {triageItem.Index}, category: {triageItem.UpdatedCategory}, url: {triageItem.Url}");
            }
            await IngestTriageItemsIntoKusto(toBeUpdatedTriageItems);

            await gitHubClient.Issue.Comment.Create(issuePayload.Repository.Id, existingIssueToUpdate.Number,
                                                    $"Bot has updated the issue and 'TimelineIssuesTriage' database by data from issue {issuePayload.Issue.HtmlUrl}.\n**PowerBI reports may take up to 24 hours to refresh**\n\nSee {_docLink} for more information.");

            // add comment to opened issue and close it
            await gitHubClient.Issue.Comment.Create(issuePayload.Repository.Id, issuePayload.Issue.Number,
                                                    $"Existing issue was detected and additional builds was added to it.\n\nClosing as updated into {existingIssueToUpdate.HtmlUrl}\n\nFor more information see {_docLink}");

            var issueUpdate = new IssueUpdate
            {
                State = ItemState.Closed,
            };
            await gitHubClient.Issue.Update(issuePayload.Repository.Id, issuePayload.Issue.Number, issueUpdate);
        }
Exemple #3
0
        private bool IsDuplicate(IssuesHookData issuePayload, IList <TriageItem> triageItems, IReadOnlyList <Issue> existingTriageIssues, out Issue existingDuplicate)
        {
            existingDuplicate = existingTriageIssues.FirstOrDefault(e =>
                                                                    issuePayload.Issue.Number != e.Number &&
                                                                    IsDuplicate(triageItems, GetTriageItems(e.Body)));

            return(existingDuplicate != null);
        }
Exemple #4
0
        private bool ShallUpdateExistingIssue(IssuesHookData issuePayload, IList <TriageItem> triageItems, IReadOnlyList <Issue> existingTriageIssues, out Issue existingIssueToUpdate)
        {
            existingIssueToUpdate = existingTriageIssues.FirstOrDefault(e =>
                                                                        issuePayload.Issue.Number != e.Number &&
                                                                        ShallExistingIssueBeUpdated(triageItems, GetTriageItems(e.Body)));

            return(existingIssueToUpdate != null);
        }
Exemple #5
0
        private static async Task CloseAsDuplicate(IssuesHookData issuePayload, Issue existingDuplicateIssue, IGitHubClient gitHubClient)
        {
            await gitHubClient.Issue.Comment.Create(issuePayload.Repository.Id, issuePayload.Issue.Number,
                                                    $"Duplicate issue was detected.\n\nClosing as duplicate of {existingDuplicateIssue.HtmlUrl}\n\nFor more information see {_docLink}");

            var issueUpdate = new IssueUpdate
            {
                State = ItemState.Closed,
            };
            await gitHubClient.Issue.Update(issuePayload.Repository.Id, issuePayload.Issue.Number, issueUpdate);
        }
        public void IssueEventDeserialization_SameAsExpected()
        {
            var expected = new IssuesHookData
            {
                Action = "labeled",
                Issue  = new IssuesHookIssue
                {
                    Assignee = new IssuesHookUser
                    {
                        Login = "******",
                    },
                    Labels = ImmutableArray.Create(new[]
                    {
                        new IssuesHookLabel {
                            Name = "area-GC-coreclr"
                        },
                        new IssuesHookLabel {
                            Name = "area-Serialization"
                        },
                        new IssuesHookLabel {
                            Name = "area-cat"
                        },
                    }),
                    Number  = 217,
                    State   = ItemState.Open,
                    Title   = "Intermittent serialization error in GC during build",
                    Url     = "https://api.github.com/repos/thatguy-int-tests/issue-notify-tests/issues/217",
                    HtmlUrl = "https://github.com/thatguy-int-tests/issue-notify-tests/issues/217",
                    Body    = "This one is a mystery"
                },
                Label = new IssuesHookLabel
                {
                    Name = "area-cat"
                },
                Repository = new IssuesHookRepository
                {
                    Name  = "issue-notify-tests",
                    Owner = new IssuesHookUser {
                        Login = "******"
                    },
                    Id = 987654321,
                },
                Sender = new IssuesHookUser
                {
                    Login = "******",
                }
            };

            var issueEvent = JsonSerializer.Deserialize <IssuesHookData>(GetTestPayload(), GitHubHookController.SerializerOptions());

            issueEvent.Should().BeEquivalentTo(expected);
        }
Exemple #7
0
        public async Task ProcessIssueEvent(IssuesHookData issuePayload)
        {
            if (issuePayload.Action != "opened" &&
                issuePayload.Action != "reopened" &&
                issuePayload.Action != "closed")
            {
                _logger.LogInformation($"Received GitHub action '{issuePayload.Action}', no triage issue handling for on such action.");
                return;
            }

            var triageItems = GetTriageItems(issuePayload.Issue.Body);

            if (!triageItems.Any())
            {
                _logger.LogInformation($"{issuePayload.Issue.Url} is not a time line triage type issue.");
                return;
            }

            IGitHubClient gitHubClient = await _gitHubApplicationClientFactory.CreateGitHubClientAsync(issuePayload.Repository.Owner.Login, issuePayload.Repository.Name);

            var existingTriageIssues = await ExistingTriageItems(issuePayload, gitHubClient);

            if (issuePayload.Action == "opened" || issuePayload.Action == "reopened")
            {
                if (IsDuplicate(issuePayload, triageItems, existingTriageIssues, out var existingDuplicateIssue))
                {
                    await CloseAsDuplicate(issuePayload, existingDuplicateIssue, gitHubClient);
                }
                else if (ShallUpdateExistingIssue(issuePayload, triageItems, existingTriageIssues, out var existingIssueToUpdate))
                {
                    await UpdateExistingIssue(issuePayload, triageItems, existingIssueToUpdate, gitHubClient);
                }
                else
                {
                    await ProcessOpenedTriageIssue(issuePayload, triageItems, gitHubClient);
                }
            }
            else if (issuePayload.Action == "closed")
            {
                await RecatogorizeFailedBuildsIfRequested(issuePayload, triageItems, gitHubClient);
            }
            else
            {
                throw new InvalidOperationException($"Unexpected action {issuePayload.Action} during handling time line triage issue");
            }
        }
Exemple #8
0
        private async Task <IReadOnlyList <Issue> > ExistingTriageItems(IssuesHookData issuePayload, IGitHubClient gitHubClient)
        {
            var openIssues = new RepositoryIssueRequest
            {
                Filter        = IssueFilter.All,
                State         = ItemStateFilter.Open,
                SortProperty  = IssueSort.Created,
                SortDirection = SortDirection.Ascending,
            };

            openIssues.Labels.Add(_markingLabelName);

            _logger.LogInformation("Getting open issues");
            var existingTriageIssues = await gitHubClient.Issue.GetAllForRepository(issuePayload.Repository.Id, openIssues);

            _logger.LogInformation($"There are {existingTriageIssues.Count} open issues with the '{_markingLabelName}' label");
            return(existingTriageIssues);
        }
Exemple #9
0
        private async Task AddToZenHubTopic(IssuesHookData issuePayload, IGitHubClient gitHubClient, Issue issue)
        {
            // add into notification epic -> currently 8/2020 it's First Response epic
            NotificationEpicOptions epic = _githubOptions.Value.NotificationEpic;

            if (epic != null)
            {
                var epicRepoData = await gitHubClient.Repository.Get(_githubOptions.Value.Organization, epic.Repository);

                _logger.LogInformation("Adding the issue to ZenHub Epic...");
                await _zenHub.AddIssueToEpicAsync(
                    new ZenHubClient.IssueIdentifier(issuePayload.Repository.Id, issue.Number),
                    new ZenHubClient.IssueIdentifier(epicRepoData.Id, epic.IssueNumber)
                    );
            }
            else
            {
                _logger.LogInformation("No ZenHub epic configured, skipping...");
            }
        }
Exemple #10
0
        private async Task RecatogorizeFailedBuildsIfRequested(IssuesHookData issuePayload, IList <TriageItem> triageItems, IGitHubClient gitHubClient)
        {
            if (issuePayload.Issue.Labels.All(l => l.Name != _markingLabelName))
            {
                // do not handle issues which are not marked by label
                return;
            }

            IReadOnlyList <IssueComment> comments = gitHubClient.Issue.Comment.GetAllForIssue(issuePayload.Repository.Id, issuePayload.Issue.Number).Result;

            // find the latest comment with category command
            string updatedCategory = null;

            foreach (var comment in comments)
            {
                string category = GetTriageIssueProperty("category", comment.Body);
                if (!string.IsNullOrEmpty(category))
                {
                    updatedCategory = category;
                }
            }

            if (updatedCategory != null)
            {
                foreach (var triageItem in triageItems)
                {
                    triageItem.UpdatedCategory = updatedCategory;
                }

                foreach (var triageItem in triageItems)
                {
                    triageItem.Url = issuePayload.Issue.HtmlUrl;
                    _logger.LogInformation($"Updated category of triage item: {triageItem}");
                }

                await IngestTriageItemsIntoKusto(triageItems);

                await gitHubClient.Issue.Comment.Create(issuePayload.Repository.Id, issuePayload.Issue.Number, $"Bot has updated the 'TimelineIssuesTriage' database with new category '{updatedCategory}'.\n**PowerBI reports may take up to 24 hours to refresh**\n\nSee {_docLink} for more information.");
            }
        }
Exemple #11
0
 private string UpdateExistingIssueBody(IssuesHookData issuePayload, IList <TriageItem> triageItems, Issue existingIssue, IList <TriageItem> existingIssueItems)
 {
     return(_internal.UpdateExistingIssueBody(triageItems, issuePayload.Issue.Body, existingIssueItems, existingIssue.Body));
 }
        public async Task ProcessIssueEvent(IssuesHookData issuePayload)
        {
            if (issuePayload.Action != "opened" &&
                issuePayload.Action != "reopened" &&
                issuePayload.Action != "closed")
            {
                _logger.LogInformation($"Received github action '{issuePayload.Action}', nothing to do");
                return;
            }

            // Determine identifiable information for triage items
            var triageItems = GetTriageItems(issuePayload.Issue.Body);

            if (!triageItems.Any())
            {
                /* Item is not a triage item (does not contain identifiable information), do nothing */
                _logger.LogInformation($"{issuePayload.Issue.Url} is not a triage type issue.");

                return;
            }

            IGitHubClient gitHubClient = await _gitHubApplicationClientFactory.CreateGitHubClientAsync(issuePayload.Repository.Owner.Login, issuePayload.Repository.Name);

            if (issuePayload.Action == "opened" || issuePayload.Action == "reopened")
            {
                // First, look for duplicate issues that are open
                var openIssues = new RepositoryIssueRequest
                {
                    Filter        = IssueFilter.All,
                    State         = ItemStateFilter.Open,
                    SortProperty  = IssueSort.Created,
                    SortDirection = SortDirection.Ascending,
                };
                openIssues.Labels.Add(_markingLabelName);

                _logger.LogInformation("Getting open issues");
                var existingTriageIssues = await gitHubClient.Issue.GetAllForRepository(issuePayload.Repository.Id, openIssues);

                _logger.LogInformation($"There are {existingTriageIssues.Count} open issues with the '{_markingLabelName}' label");
                foreach (var existingIssue in existingTriageIssues)
                {
                    if (existingIssue.Number != issuePayload.Issue.Number)
                    {
                        var existingIssueItems = GetTriageItems(existingIssue.Body);
                        if (IsDuplicate(triageItems, existingIssueItems))
                        {
                            await gitHubClient.Issue.Comment.Create(issuePayload.Repository.Id, issuePayload.Issue.Number, $"Duplicate issue was detected.\n\nClosing as duplicate of {existingIssue.HtmlUrl}\n\nFor more information see {_docLink}");

                            var issueUpdate = new IssueUpdate
                            {
                                State = ItemState.Closed,
                            };
                            await gitHubClient.Issue.Update(issuePayload.Repository.Id, issuePayload.Issue.Number, issueUpdate);

                            return;
                        }
                    }
                }

                // No duplicates, add label and move issue to triage
                var issue = await gitHubClient.Issue.Get(issuePayload.Repository.Id, issuePayload.Issue.Number);

                if (!issue.Labels.Any(l => l.Name == _markingLabelName))
                {
                    var update = issue.ToUpdate();
                    update.AddLabel(_markingLabelName);
                    foreach (var label in _issueLabels)
                    {
                        if (issue.Labels.All(l => l.Name != label))
                        {
                            update.AddLabel(label);
                        }
                    }
                    await gitHubClient.Issue.Update(issuePayload.Repository.Id, issuePayload.Issue.Number, update);

                    await AddToZenHubTopic(issuePayload, gitHubClient, issue);
                }
            }

            if (issuePayload.Action == "closed")
            {
                IReadOnlyList <IssueComment> comments = gitHubClient.Issue.Comment.GetAllForIssue(issuePayload.Repository.Id, issuePayload.Issue.Number).Result;

                // find the latest comment with category command
                string updatedCategory = null;
                foreach (var comment in comments)
                {
                    string category = GetTriageIssueProperty("category", comment.Body);
                    if (!string.IsNullOrEmpty(category))
                    {
                        updatedCategory = category;
                    }
                }
                if (updatedCategory != null)
                {
                    foreach (var triageItem in triageItems)
                    {
                        triageItem.UpdatedCategory = updatedCategory;
                    }
                }
            }

            foreach (var triageItem in triageItems)
            {
                triageItem.Url = issuePayload.Issue.HtmlUrl;
                _logger.LogInformation($"buildId: {triageItem.BuildId}, recordId: {triageItem.RecordId}, index: {triageItem.Index}, category: {triageItem.UpdatedCategory}, url: {triageItem.Url}");
            }

            await IngestTriageItemsIntoKusto(triageItems);

            await gitHubClient.Issue.Comment.Create(issuePayload.Repository.Id, issuePayload.Issue.Number, $"Bot has updated the 'TimelineIssuesTriage' database.\n**PowerBI reports may take up to 24 hours to refresh**\n\nSee {_docLink} for more information.");

            return;
        }