public async Task <ActionResult <CommentMoveResult> > MoveComment(
            string toOwnerName, string toRepoName,
            [FromBody] CommentMoveRequest commentMoveRequest)
        {
            var accessToken = await HttpContext.GetTokenAsync("access_token");

            var gitHub = GitHubUtils.GetGitHubClient(accessToken);

            try
            {
                await gitHub.Issue.Comment.Create(toOwnerName, toRepoName, commentMoveRequest.IssueNumber, commentMoveRequest.Text);

                return(Ok(
                           new CommentMoveResult
                {
                }));
            }
            catch (Exception ex)
            {
                return(BadRequest(
                           new CommentMoveResult
                {
                    Exception = ex,
                }));
            }
        }
        public async Task <IActionResult> GetMoveData(string fromOwnerName, string fromRepoName, string fromIssueNumber)
        {
            var accessToken = await HttpContext.GetTokenAsync("access_token");

            var gitHub = GitHubUtils.GetGitHubClient(accessToken);

            if (!int.TryParse(fromIssueNumber, out var fromIssueNumberInt))
            {
                return(BadRequest(
                           new IssueMoveData
                {
                    ErrorMessage = $"Issue number is invalid: {fromIssueNumber}",
                }));
            }

            var fromIssue = await gitHub.Issue.Get(fromOwnerName, fromRepoName, fromIssueNumberInt);

            var comments =
                (await gitHub.Issue.Comment.GetAllForIssue(fromOwnerName, fromRepoName, fromIssueNumberInt))
                .Select(issueComment =>
                        new CommentData
            {
                Author = issueComment.User.Login,
                Text   = issueComment.Body,
                Date   = issueComment.CreatedAt,
            })
                .ToList();

            try
            {
                return(Ok(
                           new IssueMoveData
                {
                    RepoOwner = fromOwnerName,
                    RepoName = fromRepoName,
                    State = GetIssueState(fromIssue.State.Value),
                    HtmlUrl = fromIssue.HtmlUrl,
                    IsPullRequest = fromIssue.PullRequest != null,
                    Title = fromIssue.Title,
                    Number = fromIssue.Number,
                    Author = fromIssue.User.Login,
                    Body = fromIssue.Body,
                    Assignees = fromIssue.Assignees.Select(a => a.Login).ToArray(),
                    CreatedDate = fromIssue.CreatedAt,
                    Milestone = fromIssue.Milestone?.Title,
                    Labels = fromIssue.Labels.Select(l => new LabelData {
                        Text = l.Name, Color = l.Color,
                    }).ToList(),
                    Comments = comments,
                }));
            }
            catch (Exception ex)
            {
                return(BadRequest(
                           new IssueMoveData
                {
                    Exception = ex,
                }));
            }
        }
Exemple #3
0
        /// <summary>
        /// Commits pre-release to GitHub converting it to Latest Release.
        /// </summary>
        /// <param name="settings">Zombie Settings.</param>
        public async void PushReleaseToGitHub(ZombieSettings settings)
        {
            try
            {
                var client    = new GitHubClient(new ProductHeaderValue("Zombie"));
                var tokenAuth = new Credentials(settings.AccessToken);
                client.Credentials = tokenAuth;

                var segments = GitHubUtils.ParseUrl(settings.Address);
                var unused   = await client.Repository.Release.Edit(segments["owner"], segments["repo"], settings.LatestRelease.Id,
                                                                    new ReleaseUpdate
                {
                    Body            = settings.LatestRelease.Body,
                    Draft           = false,
                    Name            = settings.LatestRelease.Name,
                    Prerelease      = false,
                    TagName         = settings.LatestRelease.TagName,
                    TargetCommitish = "master"
                });

                Messenger.Default.Send(new UpdateStatus {
                    Message = "Zombie changed your Release!"
                });
            }
            catch (Exception e)
            {
                _logger.Fatal(e.Message);
                Messenger.Default.Send(new UpdateStatus {
                    Message = "Failed to push updates to your release!"
                });
            }
        }
        public async Task <ActionResult <IssueCloseResult> > CloseIssue(
            string fromOwnerName, string fromRepoName,
            [FromBody] IssueCloseRequest issueCloseRequest)
        {
            var accessToken = await HttpContext.GetTokenAsync("access_token");

            var gitHub = GitHubUtils.GetGitHubClient(accessToken);

            try
            {
                await gitHub.Issue.Update(fromOwnerName,
                                          fromRepoName,
                                          issueCloseRequest.IssueNumber,
                                          new IssueUpdate
                {
                    State = ItemState.Closed,
                });

                return(Ok(
                           new IssueCloseResult
                {
                }));
            }
            catch (Exception ex)
            {
                return(BadRequest(
                           new IssueCloseResult
                {
                    Exception = ex,
                }));
            }
        }
        public async Task <IActionResult> GetRepoData(string toOwnerName, string toRepoName)
        {
            var accessToken = await HttpContext.GetTokenAsync("access_token");

            var gitHub = GitHubUtils.GetGitHubClient(accessToken);

            var repo = await gitHub.Repository.Get(toOwnerName, toRepoName);

            try
            {
                return(Ok(
                           new RepoMoveData
                {
                    Owner = repo.Owner?.Login,
                    Repo = repo.Name,
                    OpenIssueCount = repo.OpenIssuesCount,
                }));
            }
            catch (Exception ex)
            {
                return(BadRequest(
                           new RepoMoveData
                {
                    Exception = ex,
                }));
            }
        }
Exemple #6
0
        public async Task <IActionResult> ApplyLabel(string owner, string repo, int issueNumber, string prediction)
        {
            var accessToken = await HttpContext.GetTokenAsync("access_token");

            var gitHub = GitHubUtils.GetGitHubClient(accessToken);

            var issue = await gitHub.Issue.Get(owner, repo, issueNumber);

            var issueUpdate = new IssueUpdate
            {
                Milestone = issue.Milestone?.Number // Have to re-set milestone because otherwise it gets cleared out. See https://github.com/octokit/octokit.net/issues/1927
            };

            issueUpdate.AddLabel(prediction);
            // Add all existing labels to the update so that they don't get removed
            foreach (var label in issue.Labels)
            {
                issueUpdate.AddLabel(label.Name);
            }

            await gitHub.Issue.Update(owner, repo, issueNumber, issueUpdate);

            // Because GitHub search queries can show stale data, add a cache entry to
            // indicate this issue should be hidden for a while because it was just labeled.
            _memoryCache.Set(
                GetIssueHiderCacheKey(owner, repo, issueNumber),
                0, // no data is needed; the existence of the cache key is what counts
                new MemoryCacheEntryOptions
            {
                AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(30),
            });

            return(RedirectToPage("/MikLabel"));
        }
        public static async Task <string> updateStack([ActivityTrigger] UpdateBaseImageRequest request, ILogger log)
        {
            SecretsUtils _secretsUtils = new SecretsUtils();
            await _secretsUtils.GetSecrets();

            GitHubUtils _githubUtils = new GitHubUtils(_secretsUtils._gitToken);

            String timeStamp = DateTime.Now.ToString("yyyyMMddHHmmss");
            String random    = new Random().Next(0, 9999).ToString();
            String prname    = String.Format("blimp{0}{1}", timeStamp, random);
            String parent    = String.Format("D:\\local\\Temp\\blimp{0}{1}", timeStamp, random);

            String repoUrl  = String.Format("https://github.com/Azure-App-Service/{0}-template.git", request.stack);
            String repoName = String.Format("{0}-template", request.stack);

            _githubUtils.CreateDir(parent);

            String localTemplateRepoPath = String.Format("{0}\\{1}", parent, repoName);

            _githubUtils.Clone(repoUrl, localTemplateRepoPath, "dev");
            _githubUtils.Checkout(localTemplateRepoPath, prname);

            // edit the configs
            await updateConfig(String.Format("{0}\\{1}", localTemplateRepoPath, "blessedImageConfig-dev.json"), request.NewBaseImage);
            await updateConfig(String.Format("{0}\\{1}", localTemplateRepoPath, "blessedImageConfig-master.json"), request.NewBaseImage);
            await updateConfig(String.Format("{0}\\{1}", localTemplateRepoPath, "blessedImageConfig-temp.json"), request.NewBaseImage);
            await updateConfig(String.Format("{0}\\{1}", localTemplateRepoPath, "blessedImageConfig-save.json"), request.NewBaseImage);

            _githubUtils.Stage(localTemplateRepoPath, "*");
            _githubUtils.CommitAndPush(localTemplateRepoPath, prname, String.Format("[blimp] new base image {0}", request.NewBaseImage));
            String pullRequestURL = String.Format("https://api.github.com/repos/{0}/{1}-template/pulls?access_token={2}", "azure-app-service", request.stack, _secretsUtils._gitToken);
            String body           =
                "{ " +
                "\"title\": " + JsonConvert.SerializeObject("[blimp] Update Base Image") + ", " +
                "\"body\": " + JsonConvert.SerializeObject("[blimp] auto generated Update Base Image") + ", " +
                "\"head\": " + JsonConvert.SerializeObject("azure-app-service:" + prname) + ", " +
                "\"base\": " + JsonConvert.SerializeObject("dev") +
                "}";
            HttpClient httpClient = new HttpClient();

            httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("patricklee2");
            HttpResponseMessage response = null;

            response = await httpClient.PostAsync(pullRequestURL, new StringContent(body)); // fails on empty commits

            String result = await response.Content.ReadAsStringAsync();

            System.Console.WriteLine(response.ToString());
            System.Console.WriteLine(result);
            //if (response.StatusCode == HttpStatusCode.UnprocessableEntity)
            //{
            //    System.Console.WriteLine("Unable to make PR due to no differnce");
            //}

            _githubUtils.gitDispose(localTemplateRepoPath);
            _githubUtils.Delete(parent);

            return("");
        }
        public async Task <ActionResult <IssueMoveResult> > MoveIssue(
            string toOwnerName, string toRepoName,
            [FromBody] IssueMoveRequest issueMoveRequest)
        {
            var accessToken = await HttpContext.GetTokenAsync("access_token");

            var gitHub = GitHubUtils.GetGitHubClient(accessToken);

            var destinationMilestones = await gitHub.Issue.Milestone.GetAllForRepository(toOwnerName, toRepoName);

            try
            {
                // Create new issue
                var newIssueDetails = new NewIssue(issueMoveRequest.Title)
                {
                    Body = issueMoveRequest.Body,
                };
                if (issueMoveRequest.Milestone != null)
                {
                    // Set the milestone to the ID that matches the one in the destination repo, if it exists
                    var destinationMilestone = destinationMilestones.SingleOrDefault(m => string.Equals(m.Title, issueMoveRequest.Milestone, StringComparison.OrdinalIgnoreCase));
                    newIssueDetails.Milestone = destinationMilestone?.Number;
                }
                if (issueMoveRequest.Assignees != null)
                {
                    foreach (var assignee in issueMoveRequest.Assignees)
                    {
                        newIssueDetails.Assignees.Add(assignee);
                    }
                }
                if (issueMoveRequest.Labels != null)
                {
                    foreach (var label in issueMoveRequest.Labels)
                    {
                        newIssueDetails.Labels.Add(label);
                    }
                }

                var newIssueCreated = await gitHub.Issue.Create(toOwnerName, toRepoName, newIssueDetails);

                return(Ok(
                           new IssueMoveResult
                {
                    IssueNumber = newIssueCreated.Number,
                    HtmlUrl = newIssueCreated.HtmlUrl,
                }));
            }
            catch (Exception ex)
            {
                return(BadRequest(
                           new IssueMoveResult
                {
                    Exception = ex,
                }));
            }
        }
Exemple #9
0
        public async Task <IActionResult> ApplyLabel(string owner, string repo, int issueNumber, string prediction, string repoSetName)
        {
            var accessToken = await HttpContext.GetTokenAsync("access_token");

            var gitHub = GitHubUtils.GetGitHubClient(accessToken);

            await ApplyLabel(gitHub, owner, repo, issueNumber, prediction);

            return(RedirectToPage("/MikLabel", routeValues: new { repoSetName = repoSetName }));
        }
Exemple #10
0
        private async Task CheckDownloads(bool forceCheck)
        {
            var lastCheck = forceCheck ? DateTime.MinValue : Repo.LastChecked;

            var(newData, entries) = await GitHubUtils.GetAsync <GithubReleaseEntry[]>(Repo.RepoApiReleasesUrl,
                                                                                      UserSettingsManager.Instance.GitHubToken, lastCheck);

            if (!newData)
            {
                return;
            }

            var downloads = entries.OrderByDescending(r => r.Published).SelectMany(entry => entry.Assets).Sum(a => a.Downloads);

            if (Repo.LastTotalDownloads != downloads)
            {
                int change = downloads - Repo.LastTotalDownloads;
                lblDownloads.BackColor = change > 0 ? Color.LightGreen : Color.LightPink;
                PopupMessage msg = new PopupMessage
                {
                    Caption = Repo.DisplayName,
                    Text    = $"Downloads: {downloads} ({(change > 0 ? "+" : string.Empty)}{change})",
                    Image   = Properties.Resources.Download_32x32
                };
                using (var popupNotifier = new NotificationWindow.PopupNotifier
                {
                    TitleText = msg.Caption,
                    ContentText = msg.Text,
                    IsRightToLeft = false,
                    Image = msg.Image,
                    AutoContentHeight = true,
                    IgnoreWhenFullScreen = true
                })
                {
                    popupNotifier.TitleFont    = new Font(popupNotifier.TitleFont.FontFamily, 16.0f);
                    popupNotifier.ContentColor = change > 0 ? Color.ForestGreen : Color.Red;
                    popupNotifier.ContentFont  = new Font(popupNotifier.ContentFont.FontFamily, 14.0f);
                    if (change > 0 || !UserSettingsManager.Instance.DoNotShowDecrementPopups)
                    {
                        popupNotifier.Popup();
                    }
                }
            }
            else
            {
                lblDownloads.BackColor = SystemColors.Control;
            }


            lblDownloads.Text       = "Downloads: " + downloads;
            Repo.LastTotalDownloads = downloads;
        }
Exemple #11
0
        private async Task CheckAPILimits()
        {
            try
            {
                var result = await GitHubUtils.GetRateLimit(Settings.GitHubToken);

                tsslblAPILimit.Text = "API Limits:" + result?.Rate;
            }
            catch (Exception e)
            {
                tsslblAPILimit.Text = $"API Limits: Check Error: {e.Message}";
            }
        }
Exemple #12
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="settings"></param>
        /// <param name="asset"></param>
        /// <param name="destinationDir"></param>
        /// <param name="type"></param>
        /// <param name="streams"></param>
        /// <returns></returns>
        private static bool LockAllContents(ZombieSettings settings, AssetObject asset, string destinationDir, LocationType type, out Dictionary <string, FileStream> streams)
        {
            streams = new Dictionary <string, FileStream>();
            var    dir = FileUtils.GetZombieDownloadsDirectory();
            string filePath;

            if (type == LocationType.Trash)
            {
                filePath = Path.Combine(dir,
                                        Path.GetFileNameWithoutExtension(asset.Name) + "_old" + Path.GetExtension(asset.Name));

                if (!File.Exists(filePath))
                {
                    if (!GitHubUtils.DownloadAssets(settings, asset.Url, filePath))
                    {
                        return(false);
                    }
                }
            }
            else
            {
                filePath = Path.Combine(dir, asset.Name);
            }

            try
            {
                using (var zip = ZipFile.Open(filePath, ZipArchiveMode.Read))
                {
                    foreach (var file in zip.Entries)
                    {
                        var completeFileName = Path.Combine(destinationDir, file.FullName);
                        if (file.Name == string.Empty ||
                            !Directory.Exists(Path.GetDirectoryName(completeFileName)) ||
                            !File.Exists(completeFileName))
                        {
                            continue;
                        }

                        var fs = new FileStream(completeFileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
                        streams.Add(completeFileName, fs);
                    }
                }
            }
            catch (Exception e)
            {
                _logger.Fatal(e.Message);
                return(false);
            }

            return(true);
        }
Exemple #13
0
        private async Task CheckTrafficViews(bool forceCheck)
        {
            var lastCheck = forceCheck ? DateTime.MinValue : Repo.LastChecked;

            var(newData, views) = await GitHubUtils.GetAsync <GithubTrafficViews>(Repo.RepoApiTrafficViewsUrl,
                                                                                  UserSettingsManager.Instance.GitHubToken, lastCheck);

            if (!newData)
            {
                return;
            }

            if (Repo.LastTotalViews != views.Total)
            {
                int change = views.Total - Repo.LastTotalViews;
                lblViews.BackColor = change > 0 ? Color.LightGreen : Color.LightPink;
                PopupMessage msg = new PopupMessage
                {
                    Caption = Repo.DisplayName,
                    Text    = $"Views: {views.Total} ({(change > 0 ? "+" : string.Empty)}{change})",
                    Image   = Properties.Resources.Show_32x32
                };
                using (var popupNotifier = new NotificationWindow.PopupNotifier())
                {
                    {
                        popupNotifier.TitleText            = msg.Caption;
                        popupNotifier.ContentText          = msg.Text;
                        popupNotifier.IsRightToLeft        = false;
                        popupNotifier.Image                = msg.Image;
                        popupNotifier.TitleFont            = new Font(popupNotifier.TitleFont.FontFamily, 16.0f);
                        popupNotifier.ContentColor         = change > 0 ? Color.ForestGreen : Color.Red;
                        popupNotifier.IgnoreWhenFullScreen = true;
                        popupNotifier.ContentFont          = new Font(popupNotifier.ContentFont.FontFamily, 14.0f);
                        popupNotifier.AutoContentHeight    = true;
                    }
                    if (change > 0 || !UserSettingsManager.Instance.DoNotShowDecrementPopups)
                    {
                        popupNotifier.Popup();
                    }
                }
            }
            else
            {
                lblViews.BackColor = SystemColors.Control;
            }

            lblViews.Text             = $"Views: {views.Total}. U:{views.Views.Sum(v => v.Uniques)}";
            Repo.LastTotalViews       = views.Total;
            Repo.LastTotalUniqueViews = views.Views.Sum(v => v.Uniques);
        }
        public async Task <IActionResult> MissingRepos()
        {
            var gitHubName        = HttpContext.User.Identity.Name;
            var gitHubAccessToken = await HttpContext.Authentication.GetTokenAsync("access_token");

            var gitHubClient = GitHubUtils.GetGitHubClient(gitHubAccessToken);

            var repoDataSet = await RepoSetProvider.GetRepoDataSet();

            var repoSetLists = repoDataSet.GetRepoSetLists();
            var distinctOrgs =
                repoSetLists
                .SelectMany(
                    repoSet => repoSet.Value.Repos.Select(repoDefinition => repoDefinition.Owner))
                .Distinct(StringComparer.OrdinalIgnoreCase)
                .OrderBy(org => org).ToList();

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

            var result = 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 result;

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

            return(View(new MissingReposViewModel
            {
                GitHubUserName = gitHubName,
                RepoSetNames = repoDataSet.GetRepoSetLists().Select(repoSetList => repoSetList.Key).ToArray(),
                MissingRepos = missingOrgRepos,
            }));
        }
Exemple #15
0
        private void OnShowContents()
        {
            IsContentVisible = !IsContentVisible;

            if (Contents.Any())
            {
                return;
            }

            var dir = Path.Combine(Directory.GetCurrentDirectory(), "downloads");

            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }

            try
            {
                var filePath = Path.Combine(dir, Asset.Name);

                // download
                GitHubUtils.DownloadAssets(App.Settings, Asset.Url, filePath);

                // verify
                if (!File.Exists(filePath))
                {
                    StatusBarManager.StatusLabel.Text = "Could not retrieve contents of the Asset!";
                    return;
                }

                using (var zip = ZipFile.Open(filePath, ZipArchiveMode.Read))
                {
                    foreach (var asset in zip.Entries)
                    {
                        Contents.Add(new AssetViewModel(new AssetObject {
                            Name = asset.Name
                        })
                        {
                            IsContent = true
                        });
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }
Exemple #16
0
        public async Task <IActionResult> GetIssuesToDispatch(string ownerName, string repoName)
        {
            var accessToken = await HttpContext.GetTokenAsync("access_token");

            var gitHub = GitHubUtils.GetGitHubClient(accessToken);

            // Issue the three queries simultaneously and wait for results
            var allRepoIssuesTask = gitHub.Issue.GetAllForRepository(ownerName, repoName);
            var allLabelsTask     = gitHub.Issue.Labels.GetAllForRepository(ownerName, repoName);
            await Task.WhenAll(allRepoIssuesTask, allLabelsTask);

            var allRepoIssues = await allRepoIssuesTask;
            var allLabels     = await allLabelsTask;

            var sortedRepoLabelNames =
                allLabels
                .Where(label => label.Name.StartsWith("repo:", StringComparison.OrdinalIgnoreCase))
                .Select(label => label.Name)
                .OrderBy(labelName => labelName, StringComparer.OrdinalIgnoreCase)
                .ToList();

            // TODO: Ignore Backlog/Discussion(s) milestones?

            // TODO: Project the issues to a simpler item that also includes action links for dispatching, etc.
            var repoRef = new RepositoryReference
            {
                Owner = new UserReference
                {
                    Login = ownerName,
                },
                Name = repoName,
            };
            var allIssuesWithoutRepoLabels =
                allRepoIssues
                .Where(issue =>
                       issue.Labels.All(label => !sortedRepoLabelNames.Contains(label.Name, StringComparer.OrdinalIgnoreCase)) &&
                       !IsExcludedMilestone(issue.Milestone?.Title))
                .Select(issue => GetIssueDataFromIssue(issue, repoRef))
                .ToList();

            return(Json(new
            {
                issuesWithoutRepoLabels = allIssuesWithoutRepoLabels,
                repoLabels = sortedRepoLabelNames,
            }));
        }
Exemple #17
0
        public async Task <IActionResult> ApplyLabels([FromForm] List <string> applyDefault, string repoSetName)
        {
            var accessToken = await HttpContext.GetTokenAsync("access_token");

            var gitHub = GitHubUtils.GetGitHubClient(accessToken);

            var tasks = new Task[applyDefault.Count];

            for (var i = 0; i < applyDefault.Count; i++)
            {
                var(owner, repo, number, prediction) = ParsePrediction(applyDefault[i]);
                tasks[i] = ApplyLabel(gitHub, owner, repo, number, prediction);
            }

            await Task.WhenAll(tasks);

            return(RedirectToPage("/MikLabel", routeValues: new { repoSetName = repoSetName }));
        }
Exemple #18
0
        /// <summary>
        /// Downloads latest pre-release from GitHub.
        /// </summary>
        /// <param name="settings">Zombie Settings.</param>
        public async void DownloadPreRelease(ZombieSettings settings)
        {
            var segments  = GitHubUtils.ParseUrl(settings.Address);
            var client    = new GitHubClient(new ProductHeaderValue("Zombie"));
            var tokenAuth = new Credentials(settings.AccessToken);

            client.Credentials = tokenAuth;

            Release prerelease = null;

            try
            {
                var releases = await client.Repository.Release.GetAll(segments["owner"], segments["repo"], ApiOptions.None);

                if (releases.Any())
                {
                    prerelease = releases.OrderBy(x => x.PublishedAt).FirstOrDefault(x => x.Prerelease);
                }
                if (prerelease == null)
                {
                    Messenger.Default.Send(new PrereleaseDownloaded
                    {
                        Status   = PrereleaseStatus.Failed,
                        Settings = null
                    });
                    return;
                }
            }
            catch (Exception e)
            {
                _logger.Fatal("Failed to retrieve Pre-Release from GitHub. " + e.Message);
                return;
            }

            settings.LatestRelease = new ReleaseObject(prerelease);

            Messenger.Default.Send(new PrereleaseDownloaded
            {
                Status   = PrereleaseStatus.Found,
                Settings = settings
            });
        }
        public async Task <ActionResult <LabelCreateResult> > CreateLabels(
            string toOwnerName, string toRepoName,
            [FromBody] LabelCreateRequest labelCreateRequest)
        {
            var accessToken = await HttpContext.GetTokenAsync("access_token");

            var gitHub = GitHubUtils.GetGitHubClient(accessToken);

            var destinationLabels = await gitHub.Issue.Labels.GetAllForRepository(toOwnerName, toRepoName);

            var listOfLabelsToCreate = labelCreateRequest.Labels
                                       .Where(labelNeeded =>
                                              !destinationLabels
                                              .Any(destinationLabel =>
                                                   string.Equals(
                                                       labelNeeded.Text,
                                                       destinationLabel.Name,
                                                       StringComparison.OrdinalIgnoreCase)))
                                       .ToList();

            try
            {
                foreach (var labelToCreate in listOfLabelsToCreate)
                {
                    await gitHub.Issue.Labels.Create(toOwnerName, toRepoName, new NewLabel(labelToCreate.Text, labelToCreate.Color));
                }

                return(Ok(
                           new LabelCreateResult
                {
                    LabelsCreated = listOfLabelsToCreate,
                }));
            }
            catch (Exception ex)
            {
                return(BadRequest(
                           new LabelCreateResult
                {
                    Exception = ex,
                }));
            }
        }
Exemple #20
0
        private static async void cleanupGithub()
        {
            String _gitToken = File.ReadAllText("../../../gitToken.txt");

            // list temp repos
            HttpClient httpClient = new HttpClient();

            httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("patricklee2");
            HttpResponseMessage response   = null;
            List <Repo>         resultList = new List <Repo>();
            List <Repo>         stackRepos = null;
            int run = 0;

            while (true)
            {
                String generatedReposURL = String.Format("https://api.github.com/orgs/{0}/repos?page={1}&per_page=30&sort=full_name&direction=asc", "blessedimagepipeline", run);
                response = await httpClient.GetAsync(generatedReposURL);

                response.EnsureSuccessStatusCode();
                string contentString = await response.Content.ReadAsStringAsync();

                List <Repo> l = JsonConvert.DeserializeObject <List <Repo> >(contentString);
                resultList.AddRange(l);
                run++;
                if (l.Count < 30)
                {
                    break;
                }
            }

            stackRepos = resultList.FindAll(isTemp);
            GitHubUtils gitHubUtils = new GitHubUtils(_gitToken);

            foreach (Repo r in stackRepos)
            {
                Console.WriteLine(r.full_name);
                gitHubUtils.DeleteGithubAsync("blessedimagepipeline", r.name);
                // delete image

                //delete webapp
            }
        }
Exemple #21
0
        public async Task <IActionResult> DispatchIssueTo(string ownerName, string repoName, int issueNumber, string destinationLabel)
        {
            var accessToken = await HttpContext.GetTokenAsync("access_token");

            var gitHub = GitHubUtils.GetGitHubClient(accessToken);

            var issueUpdate = new IssueUpdate();

            issueUpdate.AddLabel(destinationLabel);
            try
            {
                await gitHub.Issue.Update(ownerName, repoName, issueNumber, issueUpdate);

                return(Ok());
            }
            catch (Exception ex)
            {
                return(BadRequest(ex.Message));
            }
        }
Exemple #22
0
        private async Task CheckNotifications(bool forceCheck = false)
        {
            if (forceCheck || DateTime.Now >=
                Settings.LastReadUserNotification.AddMinutes(Settings.NotificationsIntervalCheck))
            {
                var(newData, notifications) = await GitHubUtils.GetAsync <GitHubUserNotification[]>(
                    "https://api.github.com/notifications", UserSettingsManager.Instance.GitHubToken,
                    UserSettingsManager.Instance.LastReadUserNotification);

                Settings.LastReadUserNotification = DateTime.Now;
                if (newData)
                {
                    Settings.LastReadUserNotification    = DateTime.Now;
                    Settings.LastUnReadUserNotifications = notifications.Where(n => n.Unread).ToList();
                    foreach (var notification in notifications)
                    {
                        using (var popupNotifier = new NotificationWindow.PopupNotifier())
                        {
                            {
                                popupNotifier.TitleText            = notification.Repository.FullName;
                                popupNotifier.ContentText          = notification.Subject.Title;
                                popupNotifier.IsRightToLeft        = false;
                                popupNotifier.Image                = Properties.Resources.Question_32x32;
                                popupNotifier.IgnoreWhenFullScreen = true;
                                popupNotifier.AutoContentHeight    = true;
                            }
                            popupNotifier.Popup();
                        }
                    }
                }
            }


            if (Settings.LastUnReadUserNotifications.Any())
            {
                lstNotifications.Items.Clear();
                lstNotifications.Items.AddRange(Settings.LastUnReadUserNotifications.Select(n => $"{n.Repository.FullName}:  {n.Subject.Title}").ToArray());
            }

            tsslblNotifications.Text = $"Notification: {Settings.LastUnReadUserNotifications.Count}. Last Update: {Settings.LastReadUserNotification}";
        }
        public async Task <ActionResult <LabelCreateResult> > CreateMilestone(
            string toOwnerName, string toRepoName,
            [FromBody] MilestoneCreateRequest milestoneCreateRequest)
        {
            var accessToken = await HttpContext.GetTokenAsync("access_token");

            var gitHub = GitHubUtils.GetGitHubClient(accessToken);

            var destinationMilestones = await gitHub.Issue.Milestone.GetAllForRepository(toOwnerName, toRepoName);

            if (destinationMilestones.Any(m => string.Equals(m.Title, milestoneCreateRequest.Milestone, StringComparison.OrdinalIgnoreCase)))
            {
                // Milestone already exists, so do nothing
                return(Ok(new MilestoneCreateResult
                {
                    MilestoneCreated = null,
                }));
            }

            try
            {
                await gitHub.Issue.Milestone.Create(toOwnerName, toRepoName, new NewMilestone(milestoneCreateRequest.Milestone));

                return(Ok(
                           new MilestoneCreateResult
                {
                    MilestoneCreated = milestoneCreateRequest.Milestone,
                }));
            }
            catch (Exception ex)
            {
                return(BadRequest(
                           new MilestoneCreateResult
                {
                    Exception = ex,
                }));
            }
        }
Exemple #24
0
        public static void rubyBase(List <Repo> repos, String root, String upstream)
        {
            Repository repo = new Repository(upstream);

            foreach (Repo r in repos)
            {
                // pull temps
                String dest = root + "\\" + r.name;
                Repository.Clone(r.clone_url, dest, new CloneOptions {
                    BranchName = "master"
                });

                // move
                String version = r.name.ToLower().Replace("rubybase-", "");

                GitHubUtils githubUtils = new GitHubUtils("fake");
                githubUtils.Delete(upstream + "\\base_images\\" + version, skipGit: true);
                githubUtils.DeepCopy(dest, upstream + "\\base_images\\" + version);

                // stage
                Commands.Stage(repo, upstream + "\\base_images\\" + version);
            }
        }
Exemple #25
0
        public async Task <IActionResult> GetIssuesByUserAsync(string repoSetName, string userName)
        {
            var repoSet     = _dataSource.GetRepoDataSet().GetRepoSet(repoSetName);
            var accessToken = await HttpContext.GetTokenAsync("access_token");

            var gitHub = GitHubUtils.GetGitHubClient(accessToken);

            // Issue the three queries simultaneously and wait for results
            var assignedIssuesQuery = repoSet.GenerateQuery("is:open", "is:issue", $"assignee:{userName}");
            var assignedPrsQuery    = repoSet.GenerateQuery("is:open", "is:pr", $"assignee:{userName}");
            var createdPrsQuery     = repoSet.GenerateQuery("is:open", "is:pr", $"author:{userName}");
            var assignedIssuesTask  = _github.SearchIssuesAsync(assignedIssuesQuery, accessToken);
            var assignedPrsTask     = _github.SearchIssuesAsync(assignedPrsQuery, accessToken);
            var createdPrsTask      = _github.SearchIssuesAsync(createdPrsQuery, accessToken);
            await Task.WhenAll(assignedIssuesTask, assignedPrsTask, createdPrsTask);

            var assignedIssues = await assignedIssuesTask;
            var assignedPrs    = await assignedPrsTask;
            var createdPrs     = await createdPrsTask;

            // Identify issues being worked on
            var workingIssues = new List <IssueData>();
            var otherIssues   = new List <IssueData>();

            foreach (var result in assignedIssues.Search)
            {
                if (result.Labels.Any(l => repoSet.WorkingLabels.Contains(l.Name)))
                {
                    // We need to grab additional data about Working issues
                    result.Working          = true;
                    result.WorkingStartedAt = await GetWorkingStartTime(result, repoSet.WorkingLabels, gitHub);

                    workingIssues.Add(result);
                }
                else
                {
                    otherIssues.Add(result);
                }
            }

            // Update rate limit information
            var rateLimitCost = RateLimitInfo.Add(RateLimitInfo.Add(assignedIssues.RateLimit, assignedPrs.RateLimit), createdPrs.RateLimit);

            _logger.LogDebug("Fetched issues for {User} in repo group {Group}. Total Rate Limit Cost: {Cost}", userName, repoSetName, rateLimitCost.Cost);

            return(Json(new
            {
                working = SortWorkingIssues(workingIssues),
                other = SortOtherAssignedIssues(otherIssues),
                prs = SortPRs(Enumerable.Concat(assignedPrs.Search, createdPrs.Search)),
                graphQlRateLimit = rateLimitCost,
                restRateLimit = gitHub.GetLastApiInfo()?.RateLimit,
                pages = assignedIssues.Pages + assignedPrs.Pages + createdPrs.Pages,
                queries = new string[]
                {
                    assignedIssuesQuery,
                    assignedPrsQuery,
                    createdPrsQuery
                }
            }));
        }
Exemple #26
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="settings"></param>
        public async void GetLatestRelease(ZombieSettings settings)
        {
            if (string.IsNullOrEmpty(settings?.AccessToken) || string.IsNullOrEmpty(settings.Address))
            {
                UpdateUI("Connection failed!", ConnectionResult.Failure);
                return;
            }

            var response = await GetLatestReleaseFromGitHub(settings);

            if (response.StatusCode != HttpStatusCode.OK)
            {
                UpdateUI("Connection failed!", ConnectionResult.Failure);
                return;
            }

            var release        = response.Data;
            var currentVersion = Properties.Settings.Default["CurrentVersion"].ToString();

            if (!release.Assets.Any() || new Version(release.TagName).CompareTo(new Version(currentVersion)) <= 0)
            {
                UpdateUI("Your release is up to date!", ConnectionResult.UpToDate, release);
                return;
            }

            var dir        = FileUtils.GetZombieDownloadsDirectory();
            var downloaded = 0;

            foreach (var asset in release.Assets)
            {
                var filePath = Path.Combine(dir, asset.Name);
                if (GitHubUtils.DownloadAssets(settings, asset.Url, filePath))
                {
                    downloaded++;
                }
            }

            if (downloaded != release.Assets.Count)
            {
                UpdateUI("Failed to download assets!", ConnectionResult.Failure);
                return;
            }

            // (Konrad) Let's get updated settings, they might be local, or remote.
            // We need latest settings since there might be changes to the target locations.
            ZombieSettings newSettings;

            if (File.Exists(settings.SettingsLocation))
            {
                if (!SettingsUtils.TryGetStoredSettings(settings.SettingsLocation, out newSettings))
                {
                    UpdateUI("Could not get latest local Zombie Settings!", ConnectionResult.Failure);
                    return;
                }
            }
            else
            {
                if (!SettingsUtils.TryGetRemoteSettings(settings.SettingsLocation, out newSettings))
                {
                    UpdateUI("Could not get latest remote Zombie Settings!", ConnectionResult.Failure);
                    return;
                }
            }

            // (Konrad) Let's make sure that we own the files that we are trying to override
            var fileStreams = new Dictionary <string, FileStream>();

            foreach (var loc in newSettings.DestinationAssets)
            {
                foreach (var asset in loc.Assets)
                {
                    if (asset.IsArchive())
                    {
                        if (LockAllContents(settings, asset, loc.DirectoryPath, out var zippedStreams))
                        {
                            fileStreams = fileStreams.Concat(zippedStreams).GroupBy(x => x.Key)
                                          .ToDictionary(x => x.Key, x => x.First().Value);
                            continue;
                        }

                        UpdateUI("Could not get access to all ZIP contents!", ConnectionResult.Failure);
                        return;
                    }

                    var to = Path.Combine(FilePathUtils.CreateUserSpecificPath(loc.DirectoryPath), asset.Name);
                    try
                    {
                        var fs = new FileStream(to, FileMode.OpenOrCreate, FileAccess.ReadWrite,
                                                FileShare.None);
                        fileStreams.Add(to, fs);
                    }
                    catch (Exception e)
                    {
                        UpdateUI(e.Message, ConnectionResult.Failure);
                        return;
                    }
                }
            }

            // (Konrad) Move assets to target locations
            foreach (var loc in newSettings.DestinationAssets)
            {
                foreach (var asset in loc.Assets)
                {
                    if (asset.IsArchive())
                    {
                        if (ExtractToDirectory(asset, loc.DirectoryPath, fileStreams))
                        {
                            continue;
                        }

                        UpdateUI("Could not override existing ZIP contents!", ConnectionResult.Failure);
                        return;
                    }

                    var from = Path.Combine(dir, asset.Name);
                    var to   = Path.Combine(FilePathUtils.CreateUserSpecificPath(loc.DirectoryPath), asset.Name);

                    // make sure that file is not locked
                    var stream = fileStreams[to];
                    stream?.Close();

                    if (FileUtils.Copy(@from, @to))
                    {
                        continue;
                    }

                    UpdateUI("Could not override existing file!", ConnectionResult.Failure);
                    return;
                }
            }

            // (Konrad) Remove temporary assets
            if (!FileUtils.DeleteDirectory(dir))
            {
                UpdateUI("Could not remove temporary download assets!", ConnectionResult.Failure);
                return;
            }

            // (Konrad) Update UI and save current version
            Properties.Settings.Default.CurrentVersion = release.TagName;
            Properties.Settings.Default.Save();

            _logger.Info("Successfully updated to version: " + release.TagName);
            Messenger.Default.Send(new UpdateStatus {
                Status = "Successfully updated to version: " + release.TagName
            });
            Messenger.Default.Send(new ReleaseDownloaded
            {
                Release = release,
                Result  = ConnectionResult.Success
            });
        }
Exemple #27
0
        public async Task <IGitHubClient> GetGitHubClient()
        {
            var accessToken = await _jsRuntime.InvokeAsync <string>("GetGitHubAccessToken");

            return(GitHubUtils.GetGitHubClient(accessToken));
        }
Exemple #28
0
        public static async void createPR(String stack)
        {
            String _gitToken = File.ReadAllText("../../../gitToken.txt");
            // clone master
            String timeStamp   = DateTime.Now.ToString("yyyyMMddHHmmss");
            String root        = String.Format("D:\\local\\temp\\blimpPR{0}", timeStamp);
            String upstream    = root + "\\" + stack;
            String upstreamURL = String.Format("https://github.com/Azure-App-Service/{0}.git", stack);
            String branch      = String.Format("blimp{0}", timeStamp);

            Repository.Clone(upstreamURL, upstream, new CloneOptions {
                BranchName = "dev"
            });

            // branch
            Repository repo = new Repository(upstream);

            repo.CreateBranch(branch);
            Commands.Checkout(repo, branch);

            // list temp repos
            HttpClient httpClient = new HttpClient();

            httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("patricklee2");
            HttpResponseMessage response   = null;
            List <Repo>         resultList = new List <Repo>();
            List <Repo>         stackRepos = null;
            int run = 0;

            while (true)
            {
                String generatedReposURL = String.Format("https://api.github.com/orgs/{0}/repos?page={1}&per_page=30&sort=full_name&direction=asc", "blessedimagepipeline", run);
                response = await httpClient.GetAsync(generatedReposURL);

                response.EnsureSuccessStatusCode();
                string contentString = await response.Content.ReadAsStringAsync();

                List <Repo> l = JsonConvert.DeserializeObject <List <Repo> >(contentString);
                resultList.AddRange(l);
                run++;
                if (l.Count < 30)
                {
                    break;
                }
            }
            switch (stack)
            {
            case "dotnetcore":
                stackRepos = resultList.FindAll(isDotnetcoreRepo);
                break;

            case "node":
                stackRepos = resultList.FindAll(isNodeRepo);
                break;

            case "php":
                stackRepos = resultList.FindAll(isPhpRepo);
                break;

            case "python":
                stackRepos = resultList.FindAll(isPythonRepo);
                break;

            case "ruby":
                stackRepos = resultList.FindAll(isRubyRepo);
                rubyBase(resultList.FindAll(isRubyBaseRepo), root, upstream);
                break;
            }
            // List<Repo> stackRepos = resultList.FindAll(isStackRepo(stack));

            foreach (Repo r in stackRepos)
            {
                try
                {
                    Console.WriteLine("copying " + r.full_name);
                    // pull temps
                    String dest = root + "\\" + r.name;
                    Repository.Clone(r.clone_url, dest, new CloneOptions {
                        BranchName = "dev"
                    });

                    // move
                    String version = r.name.ToLower().Replace(stack + "-", "");
                    String suffix  = "";
                    if (stack.Equals("php"))
                    {
                        suffix = "-apache";
                    }
                    GitHubUtils githubUtils = new GitHubUtils("fake");
                    githubUtils.Delete(upstream + "\\" + version + suffix, skipGit: true);
                    githubUtils.DeepCopy(dest, upstream + "\\" + version + suffix);

                    // stage
                    Commands.Stage(repo, upstream + "\\" + version + suffix);
                }
                catch (LibGit2Sharp.NameConflictException e)
                {
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
            }


            // git commit
            // Create the committer's signature and commit
            //_log.Info("git commit");
            Signature author    = new Signature("blimp", "*****@*****.**", DateTime.Now);
            Signature committer = author;

            // Commit to the repository
            try
            {
                Commit commit = repo.Commit("blimp", author, committer);
            }
            catch (Exception e)
            {
                //_log.info("Empty commit");
            }

            Remote remote = repo.Network.Remotes.Add("upstream", upstreamURL);

            repo.Branches.Update(repo.Head, b => b.Remote = remote.Name, b => b.UpstreamBranch = repo.Head.CanonicalName);

            // git push
            //_log.Info("git push");
            LibGit2Sharp.PushOptions options = new LibGit2Sharp.PushOptions();
            options.CredentialsProvider = new CredentialsHandler(
                (url, usernameFromUrl, types) =>
                new UsernamePasswordCredentials()
            {
                Username = _gitToken.Trim(),
                Password = String.Empty
            });
            repo.Network.Push(repo.Branches[branch], options); // fails if branch already exists

            //create PR

            String pullRequestURL = String.Format("https://api.github.com/repos/{0}/{1}/pulls?access_token={2}", "azure-app-service", stack, _gitToken);
            String body           =
                "{ " +
                "\"title\": " + JsonConvert.SerializeObject("sync from templates") + ", " +
                "\"body\": " + JsonConvert.SerializeObject("sync from templates") + ", " +
                "\"head\": " + JsonConvert.SerializeObject("azure-app-service:" + branch) + ", " +
                "\"base\": " + JsonConvert.SerializeObject("dev") +

                "}";

            response = await httpClient.PostAsync(pullRequestURL, new StringContent(body)); // fails on empty commits

            String result = await response.Content.ReadAsStringAsync();

            System.Console.WriteLine(response.ToString());
            System.Console.WriteLine(result);
            if (response.StatusCode == HttpStatusCode.UnprocessableEntity)
            {
                System.Console.WriteLine("Unable to make PR due to no differnce");
            }

            //cleanup
            //new DirectoryInfo(root).Delete(true);
        }
Exemple #29
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));
        }
Exemple #30
0
        public async Task <IActionResult> Index(string repoSet)
        {
            using (_logger.BeginScope("Requesting Triage Data for {RepoSet}", repoSet))
            {
                HttpContext.AddTelemetryProperty("RepoSet", repoSet);
                HttpContext.AddTelemetryProperty("RepoSetView", "Triage");
                var metricsPrefix = $"TriageController:RepoSet({repoSet})";

                var gitHubName = HttpContext.User.Identity.Name;
                HttpContext.AddTelemetryProperty("GitHubUser", gitHubName);

                var gitHubAccessToken = await HttpContext.GetTokenAsync("access_token");

                // Authenticated and all claims have been read

                var repoDataSet = _dataSource.GetRepoDataSet();

                if (!repoDataSet.RepoSetExists(repoSet))
                {
                    var invalidRepoSetPageViewTelemetry = new PageViewTelemetry("RepoSet")
                    {
                        Url = new Uri(Request.GetDisplayUrl()),
                    };
                    HttpContext.AddTelemetryProperty("RepoSetValid", false);
                    return(NotFound());
                }

                var requestStopwatch = new Stopwatch();
                requestStopwatch.Start();

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

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

                using (_metricsService.Time($"{metricsPrefix}:GetAllRepositories"))
                {
                    var getAllOrgReposTask = AsyncParallelUtils.ForEachAsync(distinctOrgs, 5, async org =>
                    {
                        IReadOnlyList <Repository> reposInOrg;
                        using (_metricsService.Time($"{metricsPrefix}:Org({org}):GetRepositories"))
                        {
                            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(
                            repos.Repos
                            .Distinct()
                            .Where(repo =>
                                   repo.RepoInclusionLevel != RepoInclusionLevel.NotInRepoSet)
                            .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, metricsPrefix));
                Parallel.ForEach(distinctRepos, repo => allPullRequestsByRepo[repo] = GetPullRequestsForRepo(repo, gitHubClient, metricsPrefix));

                // 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

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

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

                using (_metricsService.Time($"{metricsPrefix}:PostQueryProcessingTime"))
                {
                    // Log failures
                    var repoFailures = new List <RepoFailure>();
                    if (failuresOccurred)
                    {
                        repoFailures.AddRange(
                            allIssuesByRepo
                            .Where(repoTask => repoTask.Value.Task.IsFaulted || repoTask.Value.Task.IsCanceled)
                            .Select(repoTask =>
                                    new RepoFailure
                        {
                            Repo           = repoTask.Key,
                            IssueType      = IssueType.Issue,
                            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,
                            IssueType      = IssueType.PullRequest,
                            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 failure in repoFailures)
                        {
                            _logger.LogError(
                                failure.Exception,
                                "Error retrieving {IssueType} data for {RepositoryOwner}/{RepositoryName}",
                                failure.IssueType,
                                failure.Repo.Owner,
                                failure.Repo.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,
                        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();
                    _metricsService.Record("TriageController:RateLimitRemaining", lastApiInfo.RateLimit.Remaining);

                    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,
                        IgnoredRepos       = repos.Repos
                                             .Where(repo => repo.RepoInclusionLevel == RepoInclusionLevel.Ignored)
                                             .GroupBy(repo => repo.Owner, StringComparer.OrdinalIgnoreCase)
                                             .Select(ignoredRepoGroup => new MissingRepoSet
                        {
                            Org          = ignoredRepoGroup.Key,
                            MissingRepos = ignoredRepoGroup
                                           .Select(repo => repo.Name)
                                           .OrderBy(repoName => repoName, StringComparer.OrdinalIgnoreCase)
                                           .ToArray()
                        })
                                             .OrderBy(missingRepoSet => missingRepoSet.Org, StringComparer.OrdinalIgnoreCase)
                                             .ToArray(),

                        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 =
                                new[]
                            {
                                new GroupByAssigneeAssignee
                                {
                                    Assignee                = "<assigned outside this person set>",
                                    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(),
                        },
                    };

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

                    HttpContext.AddTelemetryProperty("RepoSetValid", true);

                    return(View(issueListViewModel));
                }
            }
        }