private async Task ProcessBuildNotificationsAsync(Build build)
        {
            const string fullBranchPrefix = "refs/heads/";

            foreach (var monitor in _options.Value.Monitor.Builds)
            {
                if (!string.Equals(build.Project.Name, monitor.Project, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                if (!string.Equals(monitor.DefinitionPath, $"{build.Definition.Path}\\{build.Definition.Name}", StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                if (monitor.Branches.All(mb => !string.Equals($"{fullBranchPrefix}{mb}",
                                                              build.SourceBranch,
                                                              StringComparison.OrdinalIgnoreCase)))
                {
                    continue;
                }

                string prettyBranch = build.SourceBranch;
                if (prettyBranch.StartsWith(fullBranchPrefix))
                {
                    prettyBranch = prettyBranch.Substring(fullBranchPrefix.Length);
                }

                _logger.LogInformation(
                    "Build '{buildNumber}' in project '{projectName}' with definition '{definitionPath}' and branch '{branch}' matches monitoring criteria, sending notification",
                    build.BuildNumber,
                    build.Project.Name,
                    build.Definition.Path,
                    build.SourceBranch);

                _logger.LogInformation("Fetching timeline messages...");
                string timelineMessage = await BuildTimelineMessage(build);

                _logger.LogInformation("Fetching changes messages...");
                string changesMessage = await BuildChangesMessage(build);

                BuildMonitorOptions.IssuesOptions repo = _options.Value.Issues;
                IGitHubClient github = await _gitHubApplicationClientFactory.CreateGitHubClientAsync(repo.Owner, repo.Name);

                DateTimeOffset?finishTime = DateTimeOffset.TryParse(build.FinishTime, out var parsedFinishTime) ?parsedFinishTime: (DateTimeOffset?)null;
                DateTimeOffset?startTime  = DateTimeOffset.TryParse(build.StartTime, out var parsedStartTime) ? parsedStartTime:(DateTimeOffset?)null;

                string timeString     = "";
                string durationString = "";
                if (finishTime.HasValue)
                {
                    timeString = finishTime.Value.ToString("R");
                    if (startTime.HasValue)
                    {
                        durationString = ((int)(finishTime.Value - startTime.Value).TotalMinutes) + " minutes";
                    }
                }

                string icon = build.Result == "failed" ? ":x:" : ":warning:";

                string body = @$ "Build [#{build.BuildNumber}]({build.Links.Web.Href}) {build.Result}

## {icon} : {build.Project.Name} / {build.Definition.Name} {build.Result}

### Summary
**Finished** - {timeString}
**Duration** - {durationString}
**Requested for** - {build.RequestedFor.DisplayName}
**Reason** - {build.Reason}

### Details

{timelineMessage}

### Changes

{changesMessage}
Beispiel #2
0
        private async Task ProcessBuildNotificationsAsync(Build build)
        {
            const string fullBranchPrefix = "refs/heads/";

            foreach (var monitor in _options.Value.Monitor.Builds)
            {
                if (!string.Equals(build.Project.Name, monitor.Project, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                if (!string.Equals(monitor.DefinitionPath, $"{build.Definition.Path}\\{build.Definition.Name}", StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                if (monitor.Branches.All(mb => !string.Equals($"{fullBranchPrefix}{mb}",
                                                              build.SourceBranch,
                                                              StringComparison.OrdinalIgnoreCase)))
                {
                    continue;
                }

                if (monitor.Tags != null && monitor.Tags.Any() && !(monitor.Tags.Intersect(build.Tags).Any()))
                {
                    // We should only skip processing if tags were specified in the monitor, and none of those tags were found in the build
                    continue;
                }

                string prettyBranch = build.SourceBranch;
                if (prettyBranch.StartsWith(fullBranchPrefix))
                {
                    prettyBranch = prettyBranch.Substring(fullBranchPrefix.Length);
                }

                string prettyTags = (monitor.Tags != null && monitor.Tags.Any()) ? $"{string.Join(", ", build.Tags)}" : "";

                _logger.LogInformation(
                    "Build '{buildNumber}' in project '{projectName}' with definition '{definitionPath}', tags '{prettyTags}', and branch '{branch}' matches monitoring criteria, sending notification",
                    build.BuildNumber,
                    build.Project.Name,
                    build.Definition.Path,
                    prettyTags,
                    build.SourceBranch);

                _logger.LogInformation("Fetching timeline messages...");
                string timelineMessage = await BuildTimelineMessage(build);

                _logger.LogInformation("Fetching changes messages...");
                string changesMessage = await BuildChangesMessage(build);

                BuildMonitorOptions.IssuesOptions repo = _options.Value.Issues.SingleOrDefault(i => string.Equals(monitor.IssuesId, i.Id, StringComparison.OrdinalIgnoreCase));

                if (repo != null)
                {
                    IGitHubClient github = await _gitHubApplicationClientFactory.CreateGitHubClientAsync(repo.Owner, repo.Name);

                    DateTimeOffset?finishTime = DateTimeOffset.TryParse(build.FinishTime, out var parsedFinishTime) ?parsedFinishTime: (DateTimeOffset?)null;
                    DateTimeOffset?startTime  = DateTimeOffset.TryParse(build.StartTime, out var parsedStartTime) ? parsedStartTime:(DateTimeOffset?)null;

                    string timeString     = "";
                    string durationString = "";
                    if (finishTime.HasValue)
                    {
                        timeString = finishTime.Value.ToString("R");
                        if (startTime.HasValue)
                        {
                            durationString = ((int)(finishTime.Value - startTime.Value).TotalMinutes) + " minutes";
                        }
                    }

                    string icon = build.Result == "failed" ? ":x:" : ":warning:";

                    string body             = @$ "Build [#{build.BuildNumber}]({build.Links.Web.Href}) {build.Result}

## {icon} : {build.Project.Name} / {build.Definition.Name} {build.Result}

### Summary
**Finished** - {timeString}
**Duration** - {durationString}
**Requested for** - {build.RequestedFor.DisplayName}
**Reason** - {build.Reason}

### Details

{timelineMessage}

### Changes

{changesMessage}
";
                    string issueTitlePrefix = $"Build failed: {build.Definition.Name}/{prettyBranch} {prettyTags}";

                    if (repo.UpdateExisting)
                    {
                        // There is no way to get the username of our bot directly from the GithubApp with the C# api.
                        // Issue opened in Octokit: https://github.com/octokit/octokit.net/issues/2335
                        // We do, however, have access to the HtmlUrl, which ends with the name of the bot.
                        // Additionally, when the bot opens issues, the username used ends with [bot], which isn't strictly
                        // part of the name anywhere else. So, to get the correct creator name, get the HtmlUrl, grab
                        // the bot's name from it, and append [bot] to that string.
                        var    githubAppClient = _gitHubApplicationClientFactory.CreateGitHubAppClient();
                        string creator         = (await githubAppClient.GitHubApps.GetCurrent()).HtmlUrl.Split("/").Last();

                        RepositoryIssueRequest issueRequest = new RepositoryIssueRequest {
                            Creator       = $"{creator}[bot]",
                            State         = ItemStateFilter.Open,
                            SortProperty  = IssueSort.Created,
                            SortDirection = SortDirection.Descending
                        };

                        foreach (string label in repo.Labels.OrEmpty())
                        {
                            issueRequest.Labels.Add(label);
                        }

                        foreach (string label in monitor.Labels.OrEmpty())
                        {
                            issueRequest.Labels.Add(label);
                        }

                        List <Issue> matchingIssues = (await github.Issue.GetAllForRepository(repo.Owner, repo.Name, issueRequest)).ToList();
                        Issue        matchingIssue  = matchingIssues.FirstOrDefault(i => i.Title.StartsWith(issueTitlePrefix));

                        if (matchingIssue != null)
                        {
                            _logger.LogInformation("Found matching issue {issueNumber} in {owner}/{repo}. Will attempt to add a new comment.", matchingIssue.Number, repo.Owner, repo.Name);
                            // Add a new comment to the issue with the body
                            IssueComment newComment = await github.Issue.Comment.Create(repo.Owner, repo.Name, matchingIssue.Number, body);

                            _logger.LogInformation("Logged comment in {owner}/{repo}#{issueNumber} for build failure", repo.Owner, repo.Name, matchingIssue.Number);

                            return;
                        }
                        else
                        {
                            _logger.LogInformation("Matching issues for {issueTitlePrefix} not found. Creating a new issue.", issueTitlePrefix);
                        }
                    }

                    // Create new issue if repo.UpdateExisting is false or there were no matching issues
                    var newIssue =
                        new NewIssue($"{issueTitlePrefix} #{build.BuildNumber}")
                    {
                        Body = body,
                    };

                    if (!string.IsNullOrEmpty(monitor.Assignee))
                    {
                        newIssue.Assignees.Add(monitor.Assignee);
                    }

                    foreach (string label in repo.Labels.OrEmpty())
                    {
                        newIssue.Labels.Add(label);
                    }

                    foreach (string label in monitor.Labels.OrEmpty())
                    {
                        newIssue.Labels.Add(label);
                    }

                    Issue issue = await github.Issue.Create(repo.Owner, repo.Name, newIssue);

                    _logger.LogInformation("Logged issue {owner}/{repo}#{issueNumber} for build failure", repo.Owner, repo.Name, issue.Number);
                }