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)); }
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)); }