Пример #1
0
        public IActionResult Index(string repoSet, string gitHubAccessToken, string gitHubName)
        {
            // Authenticated and all claims have been read

            if (!RepoSetProvider.RepoSetExists(repoSet))
            {
                return(HttpNotFound());
            }

            var requestStopwatch = new Stopwatch();

            requestStopwatch.Start();

            var repos         = RepoSetProvider.GetRepoSet(repoSet);
            var distinctRepos =
                repos.Repos
                .Distinct()
                .Where(repo => repo.RepoInclusionLevel != RepoInclusionLevel.None)
                .ToArray();
            var personSetName     = repos.AssociatedPersonSetName;
            var personSet         = PersonSetProvider.GetPersonSet(personSetName);
            var peopleInPersonSet = personSet?.People ?? new string[0];
            var workingLabels     = repos.WorkingLabels ?? new string[0];

            var allIssuesByRepo       = new ConcurrentDictionary <RepoDefinition, RepoTask <IReadOnlyList <Issue> > >();
            var allPullRequestsByRepo = new ConcurrentDictionary <RepoDefinition, RepoTask <IReadOnlyList <PullRequest> > >();

            var gitHubClient = GitHubUtils.GetGitHubClient(gitHubAccessToken);

            Parallel.ForEach(distinctRepos, repo => allIssuesByRepo[repo]       = GetIssuesForRepo(repo, gitHubClient));
            Parallel.ForEach(distinctRepos, repo => allPullRequestsByRepo[repo] = GetPullRequestsForRepo(repo, gitHubClient));

            // while waiting for queries to run, do some other work...

            var labelQuery = GetLabelQuery(repos.LabelFilter);

            var openIssuesQuery       = GetOpenIssuesQuery(GetExcludedMilestonesQuery(), labelQuery, distinctRepos);
            var workingIssuesQuery    = GetWorkingIssuesQuery(labelQuery, workingLabels, distinctRepos);
            var unassignedIssuesQuery = GetUnassignedIssuesQuery(GetExcludedMilestonesQuery(), labelQuery, distinctRepos);
            var untriagedIssuesQuery  = GetUntriagedIssuesQuery(labelQuery, distinctRepos);
            var openPRsQuery          = GetOpenPRsQuery(distinctRepos);
            var stalePRsQuery         = GetStalePRsQuery(distinctRepos);

            // now wait for queries to finish executing

            try
            {
                Task.WaitAll(allIssuesByRepo.Select(x => x.Value.Task).ToArray());
            }
            catch (AggregateException)
            {
                // Just hide the exceptions here - faulted tasks will be aggregated later
            }

            try
            {
                Task.WaitAll(allPullRequestsByRepo.Select(x => x.Value.Task).ToArray());
            }
            catch (AggregateException)
            {
                // Just hide the exceptions here - faulted tasks will be aggregated later
            }

            var repoFailures = new List <RepoFailure>();

            repoFailures.AddRange(
                allIssuesByRepo
                .Where(repoTask => repoTask.Value.Task.IsFaulted || repoTask.Value.Task.IsCanceled)
                .Select(repoTask =>
                        new RepoFailure
            {
                Repo           = repoTask.Key,
                FailureMessage = string.Format("Issues couldn't be retrieved for the {0}/{1} repo", repoTask.Key.Owner, repoTask.Key.Name),
            }));
            repoFailures.AddRange(
                allPullRequestsByRepo
                .Where(repoTask => repoTask.Value.Task.IsFaulted || repoTask.Value.Task.IsCanceled)
                .Select(repoTask =>
                        new RepoFailure
            {
                Repo           = repoTask.Key,
                FailureMessage = string.Format("Pull requests couldn't be retrieved for the {0}/{1} repo", repoTask.Key.Owner, repoTask.Key.Name),
            }));

            var allIssues = allIssuesByRepo
                            .Where(repoTask => !repoTask.Value.Task.IsFaulted && !repoTask.Value.Task.IsCanceled)
                            .SelectMany(issueList =>
                                        issueList.Value.Task.Result
                                        .Where(
                                            issue =>
                                            !IsExcludedMilestone(issue.Milestone?.Title) &&
                                            issue.PullRequest == null &&
                                            IsFilteredIssue(issue, repos) &&
                                            ItemIncludedByInclusionLevel(issue.Assignee?.Login, issueList.Key, peopleInPersonSet))
                                        .Select(
                                            issue => new IssueWithRepo
            {
                Issue                   = issue,
                Repo                    = issueList.Key,
                WorkingStartTime        = GetWorkingStartTime(issueList.Key, issue, workingLabels, gitHubClient).Result,
                IsInAssociatedPersonSet = IsInAssociatedPersonSet(issue.Assignee?.Login, personSet),
            }))
                            .OrderBy(issueWithRepo => issueWithRepo.WorkingStartTime)
                            .ToList();

            var workingIssues = allIssues
                                .Where(issue =>
                                       issue.Issue.Labels
                                       .Any(label => workingLabels.Contains(label.Name, StringComparer.OrdinalIgnoreCase)))
                                .ToList();

            var untriagedIssues = allIssues
                                  .Where(issue => issue.Issue.Milestone == null).ToList();

            var unassignedIssues = allIssues
                                   .Where(issue => issue.Issue.Assignee == null).ToList();

            var allPullRequests = allPullRequestsByRepo
                                  .Where(repoTask => !repoTask.Value.Task.IsFaulted && !repoTask.Value.Task.IsCanceled)
                                  .SelectMany(pullRequestList =>
                                              pullRequestList.Value.Task.Result
                                              .Where(
                                                  pullRequest => !IsExcludedMilestone(pullRequest.Milestone?.Title) &&
                                                  (ItemIncludedByInclusionLevel(pullRequest.Assignee?.Login, pullRequestList.Key, peopleInPersonSet) ||
                                                   ItemIncludedByInclusionLevel(pullRequest.User.Login, pullRequestList.Key, peopleInPersonSet)))
                                              .Select(pullRequest =>
                                                      new PullRequestWithRepo
            {
                PullRequest             = pullRequest,
                Repo                    = pullRequestList.Key,
                IsInAssociatedPersonSet = IsInAssociatedPersonSet(pullRequest.User?.Login, personSet),
            }))
                                  .OrderBy(pullRequestWithRepo => pullRequestWithRepo.PullRequest.CreatedAt)
                                  .ToList();


            var milestoneData = distinctRepos
                                .OrderBy(repo => repo.Owner + "/" + repo.Name, StringComparer.OrdinalIgnoreCase)
                                .Select(repo =>
                                        new MilestoneSummary()
            {
                Repo          = repo,
                MilestoneData = allIssues
                                .Where(issue => issue.Repo == repo)
                                .GroupBy(issue => issue.Issue.Milestone?.Title)
                                .Select(issueMilestoneGroup => new MilestoneData
                {
                    Milestone  = issueMilestoneGroup.Key,
                    OpenIssues = issueMilestoneGroup.Count(),
                })
                                .ToList(),
            });
            var fullSortedMilestoneList = milestoneData
                                          .SelectMany(milestone => milestone.MilestoneData)
                                          .Select(milestone => milestone.Milestone)
                                          .Distinct()
                                          .OrderBy(milestone => new PossibleSemanticVersion(milestone));


            var issueListViewModel = new IssueListViewModel
            {
                RepoFailures = repoFailures,

                GitHubUserName = gitHubName,
                LastUpdated    = DateTimeOffset.Now.ToPacificTime().ToString(),

                ExtraLinks = repos.RepoExtraLinks,

                RepoSetName  = repoSet,
                RepoSetNames = RepoSetProvider.GetRepoSetLists().Select(repoSetList => repoSetList.Key).ToArray(),

                TotalIssues       = allIssues.Count,
                WorkingIssues     = workingIssues.Count,
                UntriagedIssues   = untriagedIssues.Count,
                UnassignedIssues  = unassignedIssues.Count,
                OpenPullRequests  = allPullRequests.Count,
                StalePullRequests = allPullRequests.Where(pr => pr.PullRequest.CreatedAt < DateTimeOffset.Now.AddDays(-14)).Count(),

                ReposIncluded = distinctRepos
                                .OrderBy(repo => repo.Owner.ToLowerInvariant())
                                .ThenBy(repo => repo.Name.ToLowerInvariant())
                                .Select(repo => new RepoSummary
                {
                    Repo                     = repo,
                    OpenIssues               = allIssues.Where(issue => issue.Repo == repo).Count(),
                    OpenIssuesQueryUrl       = GetOpenIssuesQuery(GetExcludedMilestonesQuery(), labelQuery, repo),
                    UnassignedIssues         = allIssues.Where(issue => issue.Repo == repo && issue.Issue.Assignee == null).Count(),
                    UnassignedIssuesQueryUrl = GetUnassignedIssuesQuery(GetExcludedMilestonesQuery(), labelQuery, repo),
                    UntriagedIssues          = allIssues.Where(issue => issue.Repo == repo && issue.Issue.Milestone == null).Count(),
                    UntriagedIssuesQueryUrl  = GetUntriagedIssuesQuery(labelQuery, repo),
                    WorkingIssues            = allIssues.Where(issue => issue.Repo == repo && workingIssues.Contains(issue)).Count(),
                    WorkingIssuesQueryUrl    = GetWorkingIssuesQuery(labelQuery, workingLabels, repo),
                    OpenPRs                  = allPullRequests.Where(pullRequest => pullRequest.Repo == repo).Count(),
                    OpenPRsQueryUrl          = GetOpenPRsQuery(repo),
                    StalePRs                 = allPullRequests.Where(pullRequest => pullRequest.Repo == repo && pullRequest.PullRequest.CreatedAt < DateTimeOffset.Now.AddDays(-14)).Count(),
                    StalePRsQueryUrl         = GetStalePRsQuery(repo),
                })
                                .ToList(),

                MilestoneSummary    = milestoneData.ToList(),
                MilestonesAvailable = fullSortedMilestoneList.ToList(),

                OpenIssuesQuery       = openIssuesQuery,
                WorkingIssuesQuery    = workingIssuesQuery,
                UntriagedIssuesQuery  = untriagedIssuesQuery,
                UnassignedIssuesQuery = unassignedIssuesQuery,
                OpenPRsQuery          = openPRsQuery,
                StalePRsQuery         = stalePRsQuery,

                GroupByAssignee = new GroupByAssigneeViewModel
                {
                    Assignees =
                        peopleInPersonSet
                        .OrderBy(person => person, StringComparer.OrdinalIgnoreCase)
                        .Select(person =>
                                new GroupByAssigneeAssignee
                    {
                        Assignee = person,
                        IsInAssociatedPersonSet = IsInAssociatedPersonSet(person, personSet),
                        Issues = workingIssues
                                 .Where(workingIssue =>
                                        workingIssue.Issue.Assignee?.Login == person)
                                 .ToList(),
                        PullRequests = allPullRequests
                                       .Where(
                            pr =>
                            pr.PullRequest.User.Login == person ||
                            pr.PullRequest.Assignee?.Login == person)
                                       .OrderBy(pr => pr.PullRequest.CreatedAt)
                                       .ToList(),
                        OtherIssues = allIssues
                                      .Where(issue =>
                                             issue.Issue.Assignee?.Login == person)
                                      .Except(workingIssues)
                                      .OrderBy(issueWithRepo => new PossibleSemanticVersion(issueWithRepo.Issue.Milestone?.Title))
                                      .ThenBy(issueWithRepo => issueWithRepo.Repo.Name, StringComparer.OrdinalIgnoreCase)
                                      .ThenBy(issueWithRepo => issueWithRepo.Issue.Number)
                                      .ToList(),
                    })
                        .Concat(new[]
                    {
                        new GroupByAssigneeAssignee
                        {
                            Assignee                = "<other assignees>",
                            IsMetaAssignee          = true,
                            IsInAssociatedPersonSet = false,
                            Issues = workingIssues
                                     .Where(workingIssue =>
                                            workingIssue.Issue.Assignee != null &&
                                            !peopleInPersonSet.Contains(workingIssue.Issue.Assignee.Login, StringComparer.OrdinalIgnoreCase))
                                     .ToList(),
                            PullRequests = allPullRequests
                                           .Where(
                                pr =>
                                pr.PullRequest.Assignee != null &&
                                !peopleInPersonSet.Contains(pr.PullRequest.User.Login, StringComparer.OrdinalIgnoreCase) &&
                                !peopleInPersonSet.Contains(pr.PullRequest.Assignee.Login, StringComparer.OrdinalIgnoreCase))
                                           .OrderBy(pr => pr.PullRequest.CreatedAt)
                                           .ToList(),
                            OtherIssues = allIssues
                                          .Where(issue =>
                                                 issue.Issue.Assignee != null &&
                                                 !peopleInPersonSet.Contains(issue.Issue.Assignee?.Login, StringComparer.OrdinalIgnoreCase))
                                          .Except(workingIssues)
                                          .OrderBy(issueWithRepo => issueWithRepo.Issue.Assignee.Login, StringComparer.OrdinalIgnoreCase)
                                          .ThenBy(issueWithRepo => new PossibleSemanticVersion(issueWithRepo.Issue.Milestone?.Title))
                                          .ThenBy(issueWithRepo => issueWithRepo.Repo.Name, StringComparer.OrdinalIgnoreCase)
                                          .ThenBy(issueWithRepo => issueWithRepo.Issue.Number)
                                          .ToList(),
                        },
                        new GroupByAssigneeAssignee
                        {
                            Assignee                = "<unassigned>",
                            IsMetaAssignee          = true,
                            IsInAssociatedPersonSet = false,
                            Issues = workingIssues
                                     .Where(workingIssue =>
                                            workingIssue.Issue.Assignee == null)
                                     .ToList(),
                            PullRequests = allPullRequests
                                           .Where(
                                pr =>
                                pr.PullRequest.Assignee == null &&
                                !peopleInPersonSet.Contains(pr.PullRequest.User.Login, StringComparer.OrdinalIgnoreCase))
                                           .OrderBy(pr => pr.PullRequest.CreatedAt)
                                           .ToList(),
                            OtherIssues = allIssues
                                          .Where(issue => issue.Issue.Assignee == null)
                                          .Except(workingIssues)
                                          .OrderBy(issueWithRepo => new PossibleSemanticVersion(issueWithRepo.Issue.Milestone?.Title))
                                          .ThenBy(issueWithRepo => issueWithRepo.Repo.Name, StringComparer.OrdinalIgnoreCase)
                                          .ThenBy(issueWithRepo => issueWithRepo.Issue.Number)
                                          .ToList(),
                        },
                    })
                        .ToList()
                        .AsReadOnly(),
                },

                GroupByMilestone = new GroupByMilestoneViewModel
                {
                    Milestones =
                        workingIssues
                        .Select(issue => issue.Issue.Milestone?.Title)
                        .Concat(new string[] { null })
                        .Distinct()
                        .OrderBy(milestone => new PossibleSemanticVersion(milestone))
                        .Select(milestone =>
                                new GroupByMilestoneMilestone
                    {
                        Milestone = milestone,
                        Issues    = workingIssues
                                    .Where(issue => issue.Issue.Milestone?.Title == milestone)
                                    .OrderBy(issue => issue.WorkingStartTime)
                                    .ToList(),
                        PullRequests = allPullRequests
                                       .Where(pullRequest => pullRequest.PullRequest.Milestone?.Title == milestone)
                                       .OrderBy(pullRequest => pullRequest.PullRequest.CreatedAt)
                                       .ToList(),
                    })
                        .OrderBy(group => new PossibleSemanticVersion(group.Milestone))
                        .ToList()
                },

                GroupByRepo = new GroupByRepoViewModel
                {
                    Repos =
                        workingIssues
                        .Select(issue => issue.Repo)
                        .Concat(allPullRequests.Select(pullRequest => pullRequest.Repo))
                        .Distinct()
                        .OrderBy(repo => repo)
                        .Select(repo =>
                                new GroupByRepoRepo
                    {
                        Repo   = repo,
                        Issues = workingIssues
                                 .Where(issue => issue.Repo == repo)
                                 .OrderBy(issue => issue.WorkingStartTime)
                                 .ToList(),
                        PullRequests = allPullRequests
                                       .Where(pullRequest => pullRequest.Repo == repo)
                                       .OrderBy(pullRequest => pullRequest.PullRequest.Assignee?.Login)
                                       .ThenBy(pullRequest => pullRequest.PullRequest.Number)
                                       .ToList(),
                    })
                        .ToList()
                },
            };

            requestStopwatch.Stop();
            issueListViewModel.PageRequestTime = requestStopwatch.Elapsed;

            return(View(issueListViewModel));
        }
Пример #2
0
        public async Task <IActionResult> Index(string repoSet)
        {
            var gitHubName        = HttpContext.User.Identity.Name;
            var gitHubAccessToken = await HttpContext.Authentication.GetTokenAsync("access_token");

            // Authenticated and all claims have been read

            var repoDataSet = await RepoSetProvider.GetRepoDataSet();

            if (!repoDataSet.RepoSetExists(repoSet))
            {
                var invalidRepoSetPageViewTelemetry = new PageViewTelemetry("RepoSet")
                {
                    Url = new Uri(Request.GetDisplayUrl()),
                };
                invalidRepoSetPageViewTelemetry.Properties.Add("GitHubUser", gitHubName);
                invalidRepoSetPageViewTelemetry.Properties.Add("repoSet", repoSet);
                invalidRepoSetPageViewTelemetry.Properties.Add("repoSetValid", "false");
                TelemetryClient.TrackPageView(invalidRepoSetPageViewTelemetry);
                return(NotFound());
            }

            var requestStopwatch = new Stopwatch();

            requestStopwatch.Start();

            var repos         = repoDataSet.GetRepoSet(repoSet);
            var distinctRepos =
                repos.Repos
                .Distinct()
                .Where(repo => repo.RepoInclusionLevel != RepoInclusionLevel.None)
                .ToArray();
            var personSetName     = repos.AssociatedPersonSetName;
            var personSet         = PersonSetProvider.GetPersonSet(personSetName);
            var peopleInPersonSet = personSet?.People ?? new string[0];
            var workingLabels     = repos.WorkingLabels ?? new string[0];

            var allIssuesByRepo       = new ConcurrentDictionary <RepoDefinition, RepoTask <IReadOnlyList <Issue> > >();
            var allPullRequestsByRepo = new ConcurrentDictionary <RepoDefinition, RepoTask <IReadOnlyList <PullRequest> > >();

            var gitHubClient = GitHubUtils.GetGitHubClient(gitHubAccessToken);


            // Get missing repos
            var distinctOrgs =
                distinctRepos
                .Select(
                    repoDefinition => repoDefinition.Owner)
                .Distinct(StringComparer.OrdinalIgnoreCase)
                .OrderBy(org => org)
                .ToList();

            var allOrgRepos = new ConcurrentDictionary <string, string[]>(StringComparer.OrdinalIgnoreCase);

            var getAllOrgReposTask = AsyncParallelUtils.ForEachAsync(distinctOrgs, 5, async org =>
            {
                var reposInOrg   = await gitHubClient.Repository.GetAllForOrg(org);
                allOrgRepos[org] = reposInOrg.Where(repo => !repo.Fork).Select(repo => repo.Name).ToArray();
            });
            await getAllOrgReposTask;

            var missingOrgRepos = allOrgRepos.Select(org =>
                                                     new MissingRepoSet
            {
                Org          = org.Key,
                MissingRepos =
                    org.Value
                    .Except(
                        distinctRepos
                        .Select(repoDefinition => repoDefinition.Name), StringComparer.OrdinalIgnoreCase)
                    .OrderBy(repo => repo, StringComparer.OrdinalIgnoreCase)
                    .ToList(),
            })
                                  .OrderBy(missingRepoSet => missingRepoSet.Org, StringComparer.OrdinalIgnoreCase)
                                  .ToList();


            // Get bugs/PR data
            Parallel.ForEach(distinctRepos, repo => allIssuesByRepo[repo]       = GetIssuesForRepo(repo, gitHubClient));
            Parallel.ForEach(distinctRepos, repo => allPullRequestsByRepo[repo] = GetPullRequestsForRepo(repo, gitHubClient));

            // while waiting for queries to run, do some other work...

            var distinctMainRepos  = distinctRepos.Where(repo => repo.RepoInclusionLevel == RepoInclusionLevel.AllItems).ToArray();
            var distinctExtraRepos = distinctRepos.Where(repo => repo.RepoInclusionLevel == RepoInclusionLevel.ItemsAssignedToPersonSet).ToArray();

            var labelQuery = GetLabelQuery(repos.LabelFilter);

            var openIssuesQuery       = GetOpenIssuesQuery(GetExcludedMilestonesQuery(), labelQuery, distinctMainRepos);
            var workingIssuesQuery    = GetWorkingIssuesQuery(labelQuery, workingLabels, distinctMainRepos);
            var unassignedIssuesQuery = GetUnassignedIssuesQuery(GetExcludedMilestonesQuery(), labelQuery, distinctMainRepos);
            var untriagedIssuesQuery  = GetUntriagedIssuesQuery(labelQuery, distinctMainRepos);
            var openPRsQuery          = GetOpenPRsQuery(distinctMainRepos);
            var stalePRsQuery         = GetStalePRsQuery(distinctMainRepos);

            // now wait for queries to finish executing

            try
            {
                Task.WaitAll(allIssuesByRepo.Select(x => x.Value.Task).ToArray());
            }
            catch (AggregateException)
            {
                // Just hide the exceptions here - faulted tasks will be aggregated later
            }

            try
            {
                Task.WaitAll(allPullRequestsByRepo.Select(x => x.Value.Task).ToArray());
            }
            catch (AggregateException)
            {
                // Just hide the exceptions here - faulted tasks will be aggregated later
            }

            var repoFailures = new List <RepoFailure>();

            repoFailures.AddRange(
                allIssuesByRepo
                .Where(repoTask => repoTask.Value.Task.IsFaulted || repoTask.Value.Task.IsCanceled)
                .Select(repoTask =>
                        new RepoFailure
            {
                Repo           = repoTask.Key,
                FailureMessage = string.Format("Issues couldn't be retrieved for the {0}/{1} repo", repoTask.Key.Owner, repoTask.Key.Name),
                Exception      = repoTask.Value.Task.Exception,
            }));
            repoFailures.AddRange(
                allPullRequestsByRepo
                .Where(repoTask => repoTask.Value.Task.IsFaulted || repoTask.Value.Task.IsCanceled)
                .Select(repoTask =>
                        new RepoFailure
            {
                Repo           = repoTask.Key,
                FailureMessage = string.Format("Pull requests couldn't be retrieved for the {0}/{1} repo", repoTask.Key.Owner, repoTask.Key.Name),
                Exception      = repoTask.Value.Task.Exception,
            }));

            foreach (var repoFailure in repoFailures)
            {
                TelemetryClient.TrackException(new ExceptionTelemetry
                {
                    Exception     = repoFailure.Exception,
                    Message       = repoFailure.FailureMessage,
                    SeverityLevel = SeverityLevel.Error,
                });
            }

            var allIssues = allIssuesByRepo
                            .Where(repoTask => !repoTask.Value.Task.IsFaulted && !repoTask.Value.Task.IsCanceled)
                            .SelectMany(issueList =>
                                        issueList.Value.Task.Result
                                        .Where(
                                            issue =>
                                            !IsExcludedMilestone(issue.Milestone?.Title) &&
                                            issue.PullRequest == null &&
                                            IsFilteredIssue(issue, repos) &&
                                            ItemIncludedByInclusionLevel(issue.Assignee?.Login, issueList.Key, peopleInPersonSet))
                                        .Select(
                                            issue => new IssueWithRepo
            {
                Issue                   = issue,
                Repo                    = issueList.Key,
                WorkingStartTime        = GetWorkingStartTime(issueList.Key, issue, workingLabels, gitHubClient).Result,
                IsInAssociatedPersonSet = IsInAssociatedPersonSet(issue.Assignee?.Login, personSet),
            }))
                            .OrderBy(issueWithRepo => issueWithRepo.WorkingStartTime)
                            .ToList();

            var workingIssues = allIssues
                                .Where(issue =>
                                       issue.Issue.Labels
                                       .Any(label => workingLabels.Contains(label.Name, StringComparer.OrdinalIgnoreCase)))
                                .ToList();

            var untriagedIssues = allIssues
                                  .Where(issue => issue.Issue.Milestone == null).ToList();

            var unassignedIssues = allIssues
                                   .Where(issue => issue.Issue.Assignee == null).ToList();

            var allPullRequests = allPullRequestsByRepo
                                  .Where(repoTask => !repoTask.Value.Task.IsFaulted && !repoTask.Value.Task.IsCanceled)
                                  .SelectMany(pullRequestList =>
                                              pullRequestList.Value.Task.Result
                                              .Where(
                                                  pullRequest => !IsExcludedMilestone(pullRequest.Milestone?.Title) &&
                                                  (ItemIncludedByInclusionLevel(pullRequest.Assignee?.Login, pullRequestList.Key, peopleInPersonSet) ||
                                                   ItemIncludedByInclusionLevel(pullRequest.User.Login, pullRequestList.Key, peopleInPersonSet)))
                                              .Select(pullRequest =>
                                                      new PullRequestWithRepo
            {
                PullRequest             = pullRequest,
                Repo                    = pullRequestList.Key,
                IsInAssociatedPersonSet = IsInAssociatedPersonSet(pullRequest.User?.Login, personSet),
            }))
                                  .OrderBy(pullRequestWithRepo => pullRequestWithRepo.PullRequest.CreatedAt)
                                  .ToList();


            var allIssuesInMainRepos  = allIssues.Where(issue => distinctMainRepos.Contains(issue.Repo)).ToList();
            var allIssuesInExtraRepos = allIssues.Where(issue => distinctExtraRepos.Contains(issue.Repo)).ToList();


            var mainMilestoneData = distinctMainRepos
                                    .OrderBy(repo => repo.Owner + "/" + repo.Name, StringComparer.OrdinalIgnoreCase)
                                    .Select(repo =>
                                            new MilestoneSummary()
            {
                Repo          = repo,
                MilestoneData = allIssuesInMainRepos
                                .Where(issue => issue.Repo == repo)
                                .GroupBy(issue => issue.Issue.Milestone?.Title)
                                .Select(issueMilestoneGroup => new MilestoneData
                {
                    Milestone  = issueMilestoneGroup.Key,
                    OpenIssues = issueMilestoneGroup.Count(),
                })
                                .ToList(),
            });
            var fullSortedMainMilestoneList = mainMilestoneData
                                              .SelectMany(milestone => milestone.MilestoneData)
                                              .Select(milestone => milestone.Milestone)
                                              .Distinct()
                                              .OrderBy(milestone => new PossibleSemanticVersion(milestone));

            var extraMilestoneData = distinctExtraRepos
                                     .OrderBy(repo => repo.Owner + "/" + repo.Name, StringComparer.OrdinalIgnoreCase)
                                     .Select(repo =>
                                             new MilestoneSummary()
            {
                Repo          = repo,
                MilestoneData = allIssuesInExtraRepos
                                .Where(issue => issue.Repo == repo)
                                .GroupBy(issue => issue.Issue.Milestone?.Title)
                                .Select(issueMilestoneGroup => new MilestoneData
                {
                    Milestone  = issueMilestoneGroup.Key,
                    OpenIssues = issueMilestoneGroup.Count(),
                })
                                .ToList(),
            });
            var fullSortedExtraMilestoneList = extraMilestoneData
                                               .SelectMany(milestone => milestone.MilestoneData)
                                               .Select(milestone => milestone.Milestone)
                                               .Distinct()
                                               .OrderBy(milestone => new PossibleSemanticVersion(milestone));

            var lastApiInfo = gitHubClient.GetLastApiInfo();

            var issueListViewModel = new IssueListViewModel
            {
                LastApiInfo = lastApiInfo,

                RepoFailures = repoFailures,

                GitHubUserName = gitHubName,
                LastUpdated    = DateTimeOffset.Now.ToPacificTime().ToString(),

                ExtraLinks = repos.RepoExtraLinks,

                RepoSetName  = repoSet,
                RepoSetNames = repoDataSet.GetRepoSetLists().Select(repoSetList => repoSetList.Key).ToArray(),

                TotalIssues       = allIssues.Where(issue => issue.Repo.RepoInclusionLevel == RepoInclusionLevel.AllItems).Count(),
                WorkingIssues     = workingIssues.Count,
                UntriagedIssues   = untriagedIssues.Where(issue => issue.Repo.RepoInclusionLevel == RepoInclusionLevel.AllItems).Count(),
                UnassignedIssues  = unassignedIssues.Count,
                OpenPullRequests  = allPullRequests.Where(pr => pr.Repo.RepoInclusionLevel == RepoInclusionLevel.AllItems).Count(),
                StalePullRequests = allPullRequests.Where(pr => pr.Repo.RepoInclusionLevel == RepoInclusionLevel.AllItems && pr.PullRequest.CreatedAt < DateTimeOffset.Now.AddDays(-14)).Count(),

                MainReposIncluded  = distinctMainRepos.GetRepoSummary(allIssues, workingIssues, allPullRequests, labelQuery, workingLabels, this),
                ExtraReposIncluded = distinctExtraRepos.GetRepoSummary(allIssues, workingIssues, allPullRequests, labelQuery, workingLabels, this),
                MissingRepos       = missingOrgRepos,

                MainMilestoneSummary = new MilestoneSummaryData
                {
                    MilestoneData       = mainMilestoneData.ToList(),
                    MilestonesAvailable = fullSortedMainMilestoneList.ToList(),
                },
                ExtraMilestoneSummary = new MilestoneSummaryData
                {
                    MilestoneData       = extraMilestoneData.ToList(),
                    MilestonesAvailable = fullSortedExtraMilestoneList.ToList(),
                },

                OpenIssuesQuery       = openIssuesQuery,
                WorkingIssuesQuery    = workingIssuesQuery,
                UntriagedIssuesQuery  = untriagedIssuesQuery,
                UnassignedIssuesQuery = unassignedIssuesQuery,
                OpenPRsQuery          = openPRsQuery,
                StalePRsQuery         = stalePRsQuery,

                GroupByAssignee = new GroupByAssigneeViewModel
                {
                    Assignees =
                        peopleInPersonSet
                        .OrderBy(person => person, StringComparer.OrdinalIgnoreCase)
                        .Select(person =>
                                new GroupByAssigneeAssignee
                    {
                        Assignee = person,
                        IsInAssociatedPersonSet = IsInAssociatedPersonSet(person, personSet),
                        Issues = workingIssues
                                 .Where(workingIssue =>
                                        workingIssue.Issue.Assignee?.Login == person)
                                 .ToList(),
                        PullRequests = allPullRequests
                                       .Where(
                            pr =>
                            pr.PullRequest.User.Login == person ||
                            pr.PullRequest.Assignee?.Login == person)
                                       .OrderBy(pr => pr.PullRequest.CreatedAt)
                                       .ToList(),
                        OtherIssues = allIssues
                                      .Where(issue =>
                                             issue.Issue.Assignee?.Login == person)
                                      .Except(workingIssues)
                                      .OrderBy(issueWithRepo => new PossibleSemanticVersion(issueWithRepo.Issue.Milestone?.Title))
                                      .ThenBy(issueWithRepo => issueWithRepo.Repo.Name, StringComparer.OrdinalIgnoreCase)
                                      .ThenBy(issueWithRepo => issueWithRepo.Issue.Number)
                                      .ToList(),
                    })
                        .Concat(new[]
                    {
                        new GroupByAssigneeAssignee
                        {
                            Assignee                = "<other assignees>",
                            IsMetaAssignee          = true,
                            IsInAssociatedPersonSet = false,
                            Issues = workingIssues
                                     .Where(workingIssue =>
                                            workingIssue.Issue.Assignee != null &&
                                            !peopleInPersonSet.Contains(workingIssue.Issue.Assignee.Login, StringComparer.OrdinalIgnoreCase))
                                     .ToList(),
                            PullRequests = allPullRequests
                                           .Where(
                                pr =>
                                pr.PullRequest.Assignee != null &&
                                !peopleInPersonSet.Contains(pr.PullRequest.User.Login, StringComparer.OrdinalIgnoreCase) &&
                                !peopleInPersonSet.Contains(pr.PullRequest.Assignee.Login, StringComparer.OrdinalIgnoreCase))
                                           .OrderBy(pr => pr.PullRequest.CreatedAt)
                                           .ToList(),
                            OtherIssues = allIssues
                                          .Where(issue =>
                                                 issue.Issue.Assignee != null &&
                                                 !peopleInPersonSet.Contains(issue.Issue.Assignee?.Login, StringComparer.OrdinalIgnoreCase))
                                          .Except(workingIssues)
                                          .OrderBy(issueWithRepo => issueWithRepo.Issue.Assignee.Login, StringComparer.OrdinalIgnoreCase)
                                          .ThenBy(issueWithRepo => new PossibleSemanticVersion(issueWithRepo.Issue.Milestone?.Title))
                                          .ThenBy(issueWithRepo => issueWithRepo.Repo.Name, StringComparer.OrdinalIgnoreCase)
                                          .ThenBy(issueWithRepo => issueWithRepo.Issue.Number)
                                          .ToList(),
                        },
                        new GroupByAssigneeAssignee
                        {
                            Assignee                = "<unassigned>",
                            IsMetaAssignee          = true,
                            IsInAssociatedPersonSet = false,
                            Issues = workingIssues
                                     .Where(workingIssue =>
                                            workingIssue.Issue.Assignee == null)
                                     .ToList(),
                            PullRequests = allPullRequests
                                           .Where(
                                pr =>
                                pr.PullRequest.Assignee == null &&
                                !peopleInPersonSet.Contains(pr.PullRequest.User.Login, StringComparer.OrdinalIgnoreCase))
                                           .OrderBy(pr => pr.PullRequest.CreatedAt)
                                           .ToList(),
                            OtherIssues = allIssues
                                          .Where(issue => issue.Issue.Assignee == null)
                                          .Except(workingIssues)
                                          .OrderBy(issueWithRepo => new PossibleSemanticVersion(issueWithRepo.Issue.Milestone?.Title))
                                          .ThenBy(issueWithRepo => issueWithRepo.Repo.Name, StringComparer.OrdinalIgnoreCase)
                                          .ThenBy(issueWithRepo => issueWithRepo.Issue.Number)
                                          .ToList(),
                        },
                    })
                        .ToList()
                        .AsReadOnly(),
                },

                GroupByMilestone = new GroupByMilestoneViewModel
                {
                    Milestones =
                        workingIssues
                        .Select(issue => issue.Issue.Milestone?.Title)
                        .Concat(new string[] { null })
                        .Distinct()
                        .OrderBy(milestone => new PossibleSemanticVersion(milestone))
                        .Select(milestone =>
                                new GroupByMilestoneMilestone
                    {
                        Milestone = milestone,
                        Issues    = workingIssues
                                    .Where(issue => issue.Issue.Milestone?.Title == milestone)
                                    .OrderBy(issue => issue.WorkingStartTime)
                                    .ToList(),
                        PullRequests = allPullRequests
                                       .Where(pullRequest => pullRequest.PullRequest.Milestone?.Title == milestone)
                                       .OrderBy(pullRequest => pullRequest.PullRequest.CreatedAt)
                                       .ToList(),
                    })
                        .OrderBy(group => new PossibleSemanticVersion(group.Milestone))
                        .ToList()
                },

                GroupByRepo = new GroupByRepoViewModel
                {
                    Repos =
                        workingIssues
                        .Select(issue => issue.Repo)
                        .Concat(allPullRequests.Select(pullRequest => pullRequest.Repo))
                        .Distinct()
                        .OrderBy(repo => repo)
                        .Select(repo =>
                                new GroupByRepoRepo
                    {
                        Repo   = repo,
                        Issues = workingIssues
                                 .Where(issue => issue.Repo == repo)
                                 .OrderBy(issue => issue.WorkingStartTime)
                                 .ToList(),
                        PullRequests = allPullRequests
                                       .Where(pullRequest => pullRequest.Repo == repo)
                                       .OrderBy(pullRequest => pullRequest.PullRequest.Assignee?.Login)
                                       .ThenBy(pullRequest => pullRequest.PullRequest.Number)
                                       .ToList(),
                    })
                        .ToList()
                },
            };

            requestStopwatch.Stop();
            issueListViewModel.PageRequestTime = requestStopwatch.Elapsed;

            var pageViewTelemetry = new PageViewTelemetry("RepoSet")
            {
                Duration = requestStopwatch.Elapsed,
                Url      = new Uri(Request.GetDisplayUrl()),
            };

            pageViewTelemetry.Properties.Add("GitHubUser", gitHubName);
            pageViewTelemetry.Properties.Add("repoSet", repoSet);
            pageViewTelemetry.Properties.Add("repoSetValid", "true");
            TelemetryClient.TrackPageView(pageViewTelemetry);

            return(View(issueListViewModel));
        }