public static async Task <List <Model.Issue> > GetIssues(DataAccess.Repository selectedrepo, ReportType reportype)
        {
            List <Model.Issue> issues = new List <Model.Issue>();

            var recently = new RepositoryIssueRequest
            {
                Filter = IssueFilter.All,
                Since  = DateTimeOffset.Now.Subtract(TimeSpan.FromDays((int)reportype))
            };

            if (selectedrepo.Name.CompareTo("ALL REPOSITORIES") == 0)
            {
                foreach (DataAccess.Repository repo in _repolist)
                {
                    var issuesForAnet = await GithubClient.Issue.GetAllForRepository("AuthorizeNet", repo.Name, recently);

                    //var issuesForAnet = await GithubClient.PullRequest.GetAllForRepository("AuthorizeNet", repo.Name, recently);

                    foreach (Octokit.Issue issue in issuesForAnet)
                    {
                        Model.Issue iss = new Model.Issue();

                        iss.Assignee      = issue.Assignee != null ? issue.Assignee.Name : "";
                        iss.Comments      = issue.Comments;
                        iss.IsPullRequest = (issue.PullRequest != null);

                        if (iss.Comments > 0)
                        {
                            var commentsforissue = await GithubClient.Issue.Comment.GetAllForIssue(repo.owner, repo.Name, issue.Number);

                            DateTime lasttime = DateTime.Now;
                            foreach (IssueComment cmnt in commentsforissue)
                            {
                                iss.CommentedBy += cmnt.User.Login + ",";
                                lasttime         = cmnt.UpdatedAt.Value.DateTime;

                                iss.AllComments += cmnt.User.Login + "\t\t\t\t" + lasttime.ToString() + "\n\n" + cmnt.Body + "\n\n";
                            }
                            iss.LastCommentedAt  = lasttime;
                            iss.LastCommentedAge = (int)(DateTime.Now - iss.LastCommentedAt).TotalDays;
                        }
                        iss.Number      = issue.Number;
                        iss.IDLink      = issue.HtmlUrl;
                        iss.Repository  = repo.Name;// issue.Repository!=null? issue.Repository.Name:"";
                        iss.Title       = issue.Title;
                        iss.Description = issue.Body;
                        iss.CreatedAt   = issue.CreatedAt.DateTime;
                        iss.User        = issue.User.Login;
                        iss.CreationAge = (int)(DateTime.Now - issue.CreatedAt).TotalDays;
                        issues.Add(iss);
                    }
                }
            }
            else
            {
                var issuesForAnet = await GithubClient.Issue.GetAllForRepository("AuthorizeNet", selectedrepo.Name, recently);

                foreach (Octokit.Issue issue in issuesForAnet)
                {
                    Model.Issue iss = new Model.Issue();

                    iss.Assignee      = issue.Assignee != null ? issue.Assignee.Name : "";
                    iss.Comments      = issue.Comments;
                    iss.IsPullRequest = (issue.PullRequest != null);
                    if (iss.Comments > 0)
                    {
                        var commentsforissue = await GithubClient.Issue.Comment.GetAllForIssue(selectedrepo.owner, selectedrepo.Name, issue.Number);

                        DateTime lasttime = DateTime.Now;
                        foreach (IssueComment cmnt in commentsforissue)
                        {
                            iss.CommentedBy += cmnt.User.Login + ",";
                            lasttime         = cmnt.UpdatedAt.Value.DateTime;

                            iss.AllComments += cmnt.User.Login + "\t\t\t\t" + lasttime.ToString() + "\n\n" + cmnt.Body + "\n\n";
                        }
                        iss.LastCommentedAt  = lasttime;
                        iss.LastCommentedAge = (int)(DateTime.Now - iss.LastCommentedAt).TotalDays;
                    }

                    iss.Number      = issue.Number;
                    iss.IDLink      = issue.HtmlUrl;
                    iss.Repository  = selectedrepo.Name;// issue.Repository!=null? issue.Repository.Name:"";
                    iss.Title       = issue.Title;
                    iss.Description = issue.Body;
                    iss.CreatedAt   = issue.CreatedAt.DateTime;
                    iss.User        = issue.User.Login;
                    iss.CreationAge = (int)(DateTime.Now - issue.CreatedAt).TotalDays;
                    issues.Add(iss);
                }
            }

            return(issues);
        }
示例#2
0
        private static async void GetChangelog()
        {
            RepositoryIssueRequest shouldPrioritize;

            try
            {
                if (options.IncludeOpen == "Y")
                {
                    shouldPrioritize = new RepositoryIssueRequest
                    {
                        Filter = IssueFilter.All,
                        State  = ItemStateFilter.All,
                    };
                }
                else
                {
                    shouldPrioritize = new RepositoryIssueRequest
                    {
                        Filter = IssueFilter.All,
                        State  = ItemStateFilter.Closed,
                    };
                };



                List <Issue> problemIssues = new List <Issue>();

                var issues = await client.Issue.GetAllForRepository(options.Organization, options.Repo, shouldPrioritize);

                Dictionary <IssueType, List <Issue> > labelSet = new Dictionary <IssueType, List <Issue> >();
                foreach (var issue in issues)
                {
                    if (issue.Milestone != null && issue.Milestone.Title == options.Milestone)
                    {
                        issuesList.Add(issue);

                        bool      issueFixed = true;
                        bool      hidden     = false;
                        IssueType issueType  = IssueType.None;
                        bool      epicLabel  = false;
                        bool      regressionDuringThisVersion = false;
                        bool      engineeringImprovement      = false;

                        foreach (var label in issue.Labels)
                        {
                            if (label.Name.Contains("ClosedAs:"))
                            {
                                issueFixed = false;
                            }

                            if (label.Name == "RegressionDuringThisVersion")
                            {
                                regressionDuringThisVersion = true;
                                hidden = true;
                            }

                            if (label.Name == "Area: Engineering Improvements")
                            {
                                engineeringImprovement = true;
                                hidden = true;
                            }

                            switch (label.Name)
                            {
                            case "Epic":
                                epicLabel = true;
                                break;

                            case "Type:Feature":
                                issueType = IssueType.Feature;
                                break;

                            case "Type:DCR":
                                issueType = IssueType.DCR;
                                break;

                            case "Type:Bug":
                                issueType = IssueType.Bug;
                                break;

                            case "Type:Spec":
                                issueType = IssueType.Spec;
                                break;

                            default:
                                break;
                            }
                        }

                        // if an issue is an epicLabel and has a real IssueType (feature/bug/dcr),
                        // then hide it... we want to show the primary epic issue only.
                        if (epicLabel)
                        {
                            if (issueType == IssueType.None)
                            {
                                issueType = IssueType.Feature;
                            }
                            else
                            {
                                hidden = true;
                            }
                        }
                        else if (issueType == IssueType.None)
                        {
                            if (issueFixed && !regressionDuringThisVersion && !engineeringImprovement)
                            {
                                // PROBLEM : if this is fixed...was it a feature/bug or dcr???
                                problemIssues.Add(issue);
                            }
                            else
                            {
                                hidden = true;
                            }
                        }


                        if (!hidden && issueFixed)
                        {
                            List <Issue> issueCollection = null;
                            if (!labelSet.ContainsKey(issueType))
                            {
                                issueCollection = new List <Issue>();
                                labelSet.Add(issueType, issueCollection);
                            }
                            else
                            {
                                issueCollection = labelSet[issueType];
                            }

                            issueCollection.Add(issue);
                        }
                    }
                }

                GenerateMarkdown(labelSet, problemIssues);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        /// <summary>
        /// Gets issues for a repository.
        /// </summary>
        /// <remarks>
        /// http://developer.github.com/v3/issues/#list-issues-for-a-repository
        /// </remarks>
        /// <param name="repositoryId">The ID of the repository</param>
        /// <param name="request">Used to filter and sort the list of issues returned</param>
        public IObservable<Issue> GetAllForRepository(int repositoryId, RepositoryIssueRequest request)
        {
            Ensure.ArgumentNotNull(request, "request");

            return GetAllForRepository(repositoryId, request, ApiOptions.None);
        }
        /// <summary>
        /// Gets issues for a repository.
        /// </summary>
        /// <remarks>
        /// http://developer.github.com/v3/issues/#list-issues-for-a-repository
        /// </remarks>
        /// <param name="repositoryId">The ID of the repository</param>
        /// <param name="request">Used to filter and sort the list of issues returned</param>
        /// <param name="options">Options for changing the API response</param>
        public IObservable<Issue> GetAllForRepository(int repositoryId, RepositoryIssueRequest request, ApiOptions options)
        {
            Ensure.ArgumentNotNull(request, "request");
            Ensure.ArgumentNotNull(options, "options");

            return _connection.GetAndFlattenAllPages<Issue>(ApiUrls.Issues(repositoryId), request.ToParametersDictionary(), options);
        }
        private static void GetRandomIssue(Project project, bool open)
        {
            Spinner.Start($"Getting random issue for {project.name}", spinner =>
            {
                if (project.site.EndsWith("/"))
                {
                    project.site = project.site.TrimEnd(Convert.ToChar("/"));
                }

                var parts    = project.site.Split(Convert.ToChar("/"));
                var owner    = parts[parts.Length - 2];
                var repoName = parts[parts.Length - 1];

                var client        = new GitHubClient(new ProductHeaderValue("dotnet-upforgrabs"));
                var requestIssues = new RepositoryIssueRequest
                {
                    State = ItemStateFilter.Open,
                };
                requestIssues.Labels.Add(project.upforgrabs.name);
                try
                {
                    var issues = client.Issue.GetAllForRepository(owner, repoName, requestIssues).GetAwaiter().GetResult();

                    if (issues.Count == 0)
                    {
                        spinner.Fail($"{project.name} currently has 0 open issues for {project.upforgrabs.name}");
                    }
                    else
                    {
                        spinner.Succeed();

                        var rand = new Random(issues.Count);
                        var item = issues.OrderBy(s => rand.NextDouble()).First();

                        Console.WriteLine();
                        Console.Write("UpForGrabs Issue for ");
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        Console.WriteLine($"{project.name}");
                        Console.ResetColor();
                        Console.WriteLine();

                        Console.Write("   - Title: ");
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        Console.WriteLine($"{item.Title}");
                        Console.Write("");
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        Console.ResetColor();

                        Console.Write("   - Repository: ");
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        Console.WriteLine($"{owner}/{repoName}");
                        Console.ResetColor();

                        Console.Write("   - Issue: #");
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        Console.WriteLine($"{item.Number.ToString()}");
                        Console.ResetColor();

                        Console.Write("   - Status: ");
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        Console.WriteLine($"{item.State.StringValue}");
                        Console.ResetColor();
                        Console.WriteLine();

                        var url = $"https://github.com/{owner}/{repoName}/issues/{item.Number.ToString()}";
                        Console.Write("Start now: ");
                        Console.ForegroundColor = ConsoleColor.DarkCyan;
                        Console.WriteLine(url);
                        Console.WriteLine();
                        Console.ResetColor();

                        if (open)
                        {
                            OpenResult(url);
                        }
                        else
                        {
                            string test = string.Empty;
                            Console.WriteLine($"{Environment.NewLine}Open issue to get started? (Y/N)");
                            ConsoleKeyInfo answer = new ConsoleKeyInfo();
                            while (string.IsNullOrEmpty(test))
                            {
                                answer = Console.ReadKey();

                                if (answer.Key == ConsoleKey.Y)
                                {
                                    OpenResult(url);
                                    test = "yes";
                                }

                                if (answer.Key == ConsoleKey.N)
                                {
                                    test = "no";
                                }
                            }
                        }
                    }
                }
                catch (Exception)
                {
                    spinner.Fail($"Something went wrong trying to get issues for repo:{project.site}. {Environment.NewLine}[DebugInfo: site:{project.site} {Environment.NewLine}owner:{owner} {Environment.NewLine}repoName:{repoName}]");
                }
            });
        }
        private void Normal()
        {
            ReceiveAsync <Messages.Messages.RetrieveRepos>(async msg =>
            {
                _logger.Info("Retrieving repos for {OrgName} org", msg.OrgName);

                var repos = await _apiClient.Repository.GetAllForOrg(msg.OrgName);

                _logger.Info("Retrieved {TotalRepoCount} total repos for {OrgName} org on page", repos.Count, msg.OrgName);
                var eligibleRepos = repos.Where(x =>
                                                !x.Private &&
                                                !x.Archived &&
                                                x.HasIssues &&
                                                RepositoryIsUpdatedWithin90Days(x)
                                                ).Select(x => new BasicRepoInfo(x.FullName, x.Name, x.Id, x.StargazersCount, x.ForksCount, x.OpenIssuesCount, x.UpdatedAt)).ToList();

                _logger.Info("After filtering, there are {EligibleRepoCount} eligible repos for {OrgName} on page", eligibleRepos.Count, msg.OrgName);
                CheckApiLimits(_apiClient.GetLastApiInfo());
                Sender.Tell(new Messages.Messages.ReposForOrganization(eligibleRepos));
            });

            ReceiveAsync <Messages.Messages.RetrieveLabels>(async msg =>
            {
                var labels            = await _apiClient.Issue.Labels.GetAllForRepository(msg.RepoId);
                var selectedLabelInfo = labels.Select(x => x.Name).ToList();

                CheckApiLimits(_apiClient.GetLastApiInfo());
                Sender.Tell(new Messages.Messages.LabelsForRepo(selectedLabelInfo));
            });

            ReceiveAsync <Messages.Messages.GetIssueCountPerLabel>(async msg =>
            {
                var req = new RepositoryIssueRequest();
                msg.LabelsToCheck.ForEach(label => req.Labels.Add(label));
                req.Filter = IssueFilter.All;
                req.State  = ItemStateFilter.All;

                var issuesForLabels = await _apiClient.Issue.GetAllForRepository(msg.RepoId, req);

                var result = new Dictionary <string, List <IssueInfo> >();

                foreach (var label in msg.LabelsToCheck)
                {
                    var issueInfos = issuesForLabels
                                     .Where(issue => issue.Labels.Any(labelItem => labelItem.Name.Equals(label, StringComparison.InvariantCultureIgnoreCase)))
                                     .Select(issue => new IssueInfo(issue.Id, issue.UpdatedAt, issue.Url, issue.ClosedAt, issue.CreatedAt)).ToList();

                    if (issueInfos.Any())
                    {
                        result.Add(label, issueInfos);
                    }
                }

                var totalCount = result.Sum(x => x.Value.Count);

                CheckApiLimits(_apiClient.GetLastApiInfo());

                if (result.Any())
                {
                    Sender.Tell(new Messages.Messages.LabelsAndIssuesResponse(result));
                }
                else
                {
                    _logger.Info("No relevant issues found for  {RepoId} / {RepoFullName}. Ends here.", msg.RepoId, msg.RepoFullName);
                }
            });
        }
示例#7
0
        private async Task <string> Build()
        {
            var(repoOwner, repoName, milestone, previousMilestone, lastCommit) = config;

            var client    = new GitHubClient(new ProductHeaderValue(config.ProductHeader));
            var tokenAuth = new Credentials(config.Token);

            client.Credentials = tokenAuth;

            if (milestone == "_")
            {
                var allContributors = await client.Repository.GetAllContributors(repoOwner, repoName);

                builder.AppendLine("# All contributors");
                builder.AppendLine();
                foreach (var contributor in allContributors)
                {
                    var user = await client.User.Get(contributor.Login);

                    var name = user?.Name;
                    builder.AppendLine("* " + (string.IsNullOrEmpty(name)
                        ? contributor.ToLink()
                        : contributor.ToLinkWithName(name)));
                }

                return(builder.ToString());
            }

            var issueRequest = new RepositoryIssueRequest
            {
                State = ItemStateFilter.Closed
            };
            var pullRequestRequest = new PullRequestRequest
            {
                State = ItemStateFilter.Closed
            };

            var issues = (await client.Issue.GetAllForRepository(repoOwner, repoName, issueRequest))
                         .Where(issue => issue.Milestone != null && issue.Milestone.Title == milestone)
                         .Where(issue => issue.PullRequest == null)
                         .OrderBy(issue => issue.Number)
                         .ToList();

            var pullRequests =
                (await client.PullRequest.GetAllForRepository(repoOwner, repoName, pullRequestRequest))
                .Where(issue => issue.Milestone != null && issue.Milestone.Title == milestone)
                .OrderBy(issue => issue.Number)
                .ToList();

            var compare = await client.Repository.Commit.Compare(repoOwner, repoName, previousMilestone, lastCommit);

            var commits = compare.Commits;

            var authorNames = new Dictionary <string, string>();

            foreach (var contributor in commits.Select(commit => commit.Author))
            {
                if (contributor != null && !authorNames.ContainsKey(contributor.Login))
                {
                    var user = await client.User.Get(contributor.Login);

                    var name = user?.Name;
                    authorNames[contributor.Login] = string.IsNullOrWhiteSpace(name) ? contributor.Login : name;
                }
            }
            var contributors = compare.Commits
                               .Select(commit => commit.Author)
                               .Where(author => author != null)
                               .Distinct(AuthorEqualityComparer.Default)
                               .OrderBy(author => authorNames[author.Login])
                               .ToImmutableList();

            var milestoneHtmlUlr = $"https://github.com/{repoOwner}/{repoName}/issues?q=milestone:{milestone}";

            builder.AppendLine("## Milestone details");
            builder.AppendLine();
            builder.AppendLine($"In the [{milestone}]({milestoneHtmlUlr}) scope, ");
            builder.Append(issues.Count + " issues were resolved and ");
            builder.AppendLine(pullRequests.Count + " pull requests where merged.");
            builder.AppendLine($"This release includes {commits.Count} commits by {contributors.Count} contributors.");
            builder.AppendLine();

            AppendList("Resolved issues", issues, issue =>
                       $"[#{issue.Number}]({issue.HtmlUrl}) {issue.Title.Trim()}{issue.Assignee.ToStr("assignee:")}");
            AppendList("Merged pull requests", pullRequests, pr =>
                       $"[#{pr.Number}]({pr.HtmlUrl}) {pr.Title.Trim()}{pr.User.ToStr("by")}");
            AppendList("Commits", commits, commit =>
                       $"{commit.ToLink()} {commit.Commit.ToCommitMessage()}{commit.ToByStr()}");
            AppendList("Contributors", contributors, contributor =>
                       $"{authorNames[contributor.Login]} ({contributor.ToLink()})".Trim(),
                       "Thank you very much!");

            return(builder.ToString());
        }
        /// <summary>
        /// issue検索
        /// </summary>
        /// <returns></returns>
        public async Task IssueSearch(IDialogContext context, IAwaitable <IMessageActivity> argument)
        {
            //入力メッセージを格納
            var message = await argument;
            var text    = message.Text;

            //検索issue格納用リスト
            List <Issue> issueListTemp = new List <Issue>();

            //issue一覧表示の引数用リスト
            IReadOnlyList <Issue> issueList = null;

            //操作キャンセル確認メソッド

            #region 操作一覧選択
            switch (search)
            {
            case "番号":
            {
                //現在のリポジトリからopen済みissueを全取得
                IReadOnlyList <Issue> issues = await GitHubDialog.github.Issue.GetAllForRepository(repository.Split('/')[0], repository.Split('/')[1]);

                //入力されたメッセージを数値化
                int num = Convert.ToInt32(text);

                //入力されたメッセージの数値と同じissueを取得
                issueListTemp = issues.ToList().Where(x => x.Number == num) as List <Issue>;

                //issue一覧表示をするためにリストの形式をreadonlyに変化
                issueList = issueListTemp;

                break;
            }

            case "作成ユーザ":
            {
                //issue検索用変数を用意し、メンバ変数「作成者」に入力メッセージを格納する
                var recently = new RepositoryIssueRequest
                {
                    Creator = text
                };

                //現在のリポジトリからissue検索用変数に添ったissueを全取得
                issueList = await GitHubDialog.github.Issue.GetAllForRepository(repository.Split('/')[0], repository.Split('/')[1], recently);

                break;
            }

            case "タイトル":
            {
                //現在のリポジトリからopen済みissueを全取得
                IReadOnlyList <Issue> issues = await GitHubDialog.github.Issue.GetAllForRepository(repository.Split('/')[0], repository.Split('/')[1]);

                //入力メッセージがタイトルと部分一致するissueを取得
                issueListTemp = issues.ToList().Where(x => x.Title.Contains(text)) as List <Issue>;

                //issue一覧表示をするためにリストの形式をreadonlyに変化
                issueList = issueListTemp;

                break;
            }

            case "ラベル":
            {
                List <string> labels = new List <string> {
                    text
                };
                issueList = await GitHubDialog.convinient.GetIssuesForLabel(labels);

                break;
            }
            }
            #endregion

            //issueの一覧を表示する旨をメッセージでbot送信
            await context.PostAsync("issueの一覧を表示します");

            //issue一覧表示処理待ち
            await IssueDisplay(context, issueList);

            //issue検索操作を終了する
            context.Done <object>(context);
        }
示例#9
0
        /// <summary>
        /// Creates the report in markdown and returns it as a string
        /// </summary>
        /// <returns>The Markdown string</returns>
        public async Task <string> CreateReport()
        {
            Console.WriteLine($"{Resources.AppTitle}");
            Console.WriteLine($"{Resources.Copyright}");
            Console.WriteLine($"{Resources.PlsWait}");

            Console.WriteLine($"{Resources.Step} 1 {Resources.of} 3 - {Resources.Headers}");
            StringBuilder sb = new StringBuilder();

            sb.AppendLine($"# {Resources.ReportTitle}");
            sb.AppendLine("");
            sb.AppendLine($"## {Resources.StatusReportFor} {_repository} {Resources.CreatedOn} {DateTime.Now}");
            sb.AppendLine("");
            sb.AppendLine($"## {Resources.OverallInfo}");
            sb.AppendLine("");

            var client    = new GitHubClient(new ProductHeaderValue("project-documentor"));
            var tokenAuth = new Credentials(_token);

            client.Credentials = tokenAuth;
            var user = await client.User.Current().ConfigureAwait(true);

            var repo = await client.Repository.Get(_owner, _repository).ConfigureAwait(true);

            sb.AppendLine($"| {Resources.Item} | {Resources.Value} |");
            sb.AppendLine($"| -- | -- |");
            sb.AppendLine($"| {Resources.DateCreated} | {repo.CreatedAt} |");
            sb.AppendLine($"| {Resources.DefaultBranch} | {repo.DefaultBranch} |");
            sb.AppendLine($"| {Resources.Description} | {repo.Description} |");
            sb.AppendLine($"| {Resources.FullName} | {repo.FullName} |");
            sb.AppendLine($"| {Resources.URL} | {repo.GitUrl} |");
            sb.AppendLine($"| {Resources.Name} | {repo.Name} |");
            sb.AppendLine($"| {Resources.CurrentOpenIssues} | {repo.OpenIssuesCount} |");
            sb.AppendLine($"| {Resources.LastCodeUpdate} | {repo.PushedAt} |");
            sb.AppendLine($"| {Resources.Subscribers} | {repo.WatchersCount} |");
            sb.AppendLine($"| {Resources.Last_Update} | {repo.UpdatedAt} |");

            sb.AppendLine("");
            sb.AppendLine($"## {Resources.Issues}");
            Console.WriteLine($"{Resources.Step} 2 {Resources.of} 3 - {Resources.IssuesModified30}");
            sb.AppendLine("");
            sb.AppendLine($"### {Resources.IssuesModified30}");
            var issuefilter = new RepositoryIssueRequest
            {
                Filter        = IssueFilter.All,
                State         = ItemStateFilter.All,
                Since         = DateTimeOffset.Now.Subtract(TimeSpan.FromDays(30)),
                SortProperty  = IssueSort.Updated,
                SortDirection = SortDirection.Descending
            };
            var issues = await client.Issue.GetAllForRepository(_owner, _repository, issuefilter).ConfigureAwait(true);

            sb.AppendLine("");
            sb.AppendLine($"| {Resources.IssueId} | {Resources.Modified} | {Resources.Status} | {Resources.Title} |");
            sb.AppendLine("| -------- | -------- | ------ | ----- |");
            foreach (var issue in issues)
            {
                sb.AppendLine($"| [{issue.Number}]({issue.Url}) | {issue.UpdatedAt.Value.ToLocalTime().ToString("dd-MM-yyyy HH:mm", CultureInfo.CurrentCulture)} | {issue.State} | {issue.Title} |");
            }

            sb.AppendLine("");
            sb.AppendLine($"### {Resources.Open_Issues}");
            sb.AppendLine("");
            sb.AppendLine($"| {Resources.IssueId} | {Resources.Modified} | {Resources.Status} | {Resources.Title} |");
            sb.AppendLine("| -------- | -------- | ------ | ----- |");
            issuefilter = new RepositoryIssueRequest
            {
                Filter        = IssueFilter.All,
                State         = ItemStateFilter.Open,
                Since         = DateTimeOffset.Now.Subtract(TimeSpan.FromDays(30)),
                SortProperty  = IssueSort.Updated,
                SortDirection = SortDirection.Descending
            };

            issues = await client.Issue.GetAllForRepository(_owner, _repository, issuefilter).ConfigureAwait(true);

            foreach (var issue in issues)
            {
                sb.AppendLine($"| [{issue.Number}]({issue.Url}) | {issue.UpdatedAt.Value.ToLocalTime().ToString("dd-MM-yyyy HH:mm", CultureInfo.CurrentCulture)} | {issue.State} | {issue.Title} |");
            }

            Console.WriteLine($"{Resources.Step} 3 {Resources.of} 3, {Resources.Projects}");
            sb.AppendLine("");
            sb.AppendLine($"## {Resources.Projects}");
            //Projects
            var projects = await client.Repository.Project.GetAllForRepository(_owner, _repository).ConfigureAwait(true);

            int projectid = 1;

            foreach (var project in projects)
            {
                Console.WriteLine($" Working on Project {projectid} of {projects.Count}: {project.Name}");
                projectid++;
                sb.AppendLine("");
                sb.AppendLine($"### {project.Name}");
                sb.AppendLine("");

                sb.AppendLine($"| {Resources.Item} | {Resources.Value} |");
                sb.AppendLine("| -----| ----- |");
                sb.AppendLine($"| {Resources.DateCreated} | {project.CreatedAt.ToLocalTime().ToString("dd-MM-yyyy HH:mm", CultureInfo.CurrentCulture)} |");
                sb.AppendLine($"| {Resources.Project_Number} | {project.Number}");
                sb.AppendLine($"| {Resources.Status} | {project.State}");
                sb.AppendLine($"| {Resources.Modified} | {project.UpdatedAt.ToLocalTime().ToString("dd-MM-yyyy HH:mm", CultureInfo.CurrentCulture)} |");
                sb.AppendLine("");

                sb.AppendLine($"#### {Resources.Project_Status}");
                sb.AppendLine("");
                var columns = await client.Repository.Project.Column.GetAll(project.Id).ConfigureAwait(true);

                List <string> lines = new List <string>();

                int colcount = 0;
                foreach (var column in columns)
                {
                    colcount++;
                    sb.AppendLine($"##### {column.Name}");
                    sb.AppendLine("");
                    Console.WriteLine($"  Column {colcount} of {columns.Count} - {column.Name}");
                    var cards = await client.Repository.Project.Card.GetAll(column.Id).ConfigureAwait(true);

                    int cardcount = 0;

                    //Handle no cards, produce nice message
                    if (cards.Count == 0)
                    {
                        sb.AppendLine($"     *{Resources.ThereAreNoIssuesinThisStatus}*");
                        sb.AppendLine();
                    }
                    foreach (var card in cards)
                    {
                        cardcount++;
                        Console.WriteLine($"         {Resources.Working_on_card}: {cardcount} {Resources.of} {cards.Count}");
                        if (column.Name != "Done" && column.Name != "Closed")
                        {
                            if (string.IsNullOrEmpty(card.Note))
                            {
                                string issueId   = card.ContentUrl.Split("/")[card.ContentUrl.Split("/").Length - 1];
                                var    cardissue = await client.Issue.Get(_owner, _repository, Convert.ToInt32(issueId, CultureInfo.CurrentCulture)).ConfigureAwait(true);

                                sb.AppendLine($"**[{issueId}]({cardissue.Url})** - *{cardissue.Title}*");
                                sb.AppendLine("");
                                sb.AppendLine($"{cardissue.Body}");
                                sb.AppendLine("");
                            }
                            else
                            {
                                sb.AppendLine(card.Note);
                                sb.AppendLine("");
                            }
                        }
                        else
                        {
                            if (string.IsNullOrEmpty(card.Note))
                            {
                                string issueId   = card.ContentUrl.Split("/")[card.ContentUrl.Split("/").Length - 1];
                                var    cardissue = await client.Issue.Get(_owner, _repository, Convert.ToInt32(issueId, CultureInfo.CurrentCulture)).ConfigureAwait(true);

                                sb.AppendLine($"- [{issueId}]({cardissue.Url}) - {cardissue.Title}");
                            }
                            else
                            {
                            }
                        }
                    }
                }
            }
            return(sb.ToString());
        }
            public async Task EnsuresArgumentsNotNull()
            {
                var client = new IssuesClient(Substitute.For<IApiConnection>());

                var options = new ApiOptions();
                var request = new RepositoryIssueRequest();

                await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllForRepository(null, "name"));
                await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllForRepository(null, "name", options));
                await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllForRepository(null, "name", request));
                await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllForRepository(null, "name", request, options));

                await Assert.ThrowsAsync<ArgumentException>(() => client.GetAllForRepository("", "name"));
                await Assert.ThrowsAsync<ArgumentException>(() => client.GetAllForRepository("", "name", options));
                await Assert.ThrowsAsync<ArgumentException>(() => client.GetAllForRepository("", "name", request));
                await Assert.ThrowsAsync<ArgumentException>(() => client.GetAllForRepository("", "name", request, options));

                await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllForRepository("owner", null));
                await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllForRepository("owner", null, options));
                await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllForRepository("owner", null, request));
                await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllForRepository("owner", null, request, options));

                await Assert.ThrowsAsync<ArgumentException>(() => client.GetAllForRepository("owner", ""));
                await Assert.ThrowsAsync<ArgumentException>(() => client.GetAllForRepository("owner", "", options));
                await Assert.ThrowsAsync<ArgumentException>(() => client.GetAllForRepository("owner", "", request));
                await Assert.ThrowsAsync<ArgumentException>(() => client.GetAllForRepository("owner", "", request, options));

                await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllForRepository("owner", "name", (ApiOptions)null));
                await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllForRepository("owner", "name", (RepositoryIssueRequest)null));

                await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllForRepository("owner", "name", null, options));
                await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllForRepository("owner", "name", request, null));
            }
示例#11
0
            public async Task EnsuresNonNullArguments()
            {
                var client = new IssuesClient(Substitute.For<IApiConnection>());

                var options = new ApiOptions();
                var request = new RepositoryIssueRequest();

                await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllForOrganization(null));
                await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllForOrganization(null, options));
                await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllForOrganization(null, request));
                await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllForOrganization(null, request, options));

                await Assert.ThrowsAsync<ArgumentException>(() => client.GetAllForOrganization(""));
                await Assert.ThrowsAsync<ArgumentException>(() => client.GetAllForOrganization("", options));
                await Assert.ThrowsAsync<ArgumentException>(() => client.GetAllForOrganization("", request));
                await Assert.ThrowsAsync<ArgumentException>(() => client.GetAllForOrganization("", request, options));

                await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllForOrganization("org", (ApiOptions)null));
                await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllForOrganization("org", (IssueRequest)null));

                await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllForOrganization("org", null, options));
                await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllForOrganization("org", request, null));
            }
示例#12
0
        private async Task ProcessBuildNotificationsAsync(Build build)
        {
            const string fullBranchPrefix = "refs/heads/";

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

### Details

{timelineMessage}

### Changes

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                    _logger.LogInformation("Logged issue {owner}/{repo}#{issueNumber} for build failure", repo.Owner, repo.Name, issue.Number);
                }
        public async Task Handle(EventContext eventContext)
        {
            if (!eventContext.WebHookEvent.IsMessageAuthenticated)
            {
                // message is not issued by GitHub. Possibly from a malucious attacker.
                // log it and return;
                Debug.WriteLine("ERROR: IssueEvent could not be authenticated!");
                return;
            }

            var action     = (string)eventContext.WebHookEvent.GetPayload().action;
            var title      = (string)eventContext.WebHookEvent.GetPayload().issue.title;
            var repository = (string)eventContext.WebHookEvent.GetPayload().repository.name;

            Debug.WriteLine($"Issue with title '{title}' on repository '{repository}' was '{action}'");

            if (action.Contains("opened"))
            {
                try
                {
                    var client  = eventContext.InstallationContext.Client;
                    var payload = eventContext.WebHookEvent.GetPayload();

                    var creatorName     = (string)payload.issue.user.login;
                    var respositoryName = (string)payload.repository.name;
                    var ownerName       = (string)payload.repository.owner.login;

                    var allIssuesForUser = new RepositoryIssueRequest
                    {
                        Creator = creatorName,
                        State   = ItemStateFilter.All,
                        Filter  = IssueFilter.All
                    };

                    var issues = await client.Issue.GetAllForRepository(ownerName, respositoryName, allIssuesForUser);

                    var issueCountForCreator = issues.Where(i => i.PullRequest == null).Count();
                    if (issueCountForCreator == 1)
                    {
                        var welcomeFileResponse = await client.Repository.Content.GetRawContent(ownerName, repository, ".github/welcome-first-issue.md");

                        var welcomeFileContent = Encoding.Default.GetString(welcomeFileResponse);

                        var issueNumber  = (int)payload.issue.number;
                        var repositoryId = (long)payload.repository.id;
                        _ = await client
                            .Issue.Comment
                            .Create(repositoryId, issueNumber, welcomeFileContent);

                        Debug.WriteLine("Habe einen Willkommens-Kommentar gepostet!");
                    }
                    else
                    {
                        Debug.WriteLine("Der Ersteller ist kein First-Time-Contributor!");
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine($"Exception gefangen: {ex}");
                    throw;
                }
            }
        }
        public IWithIssueOptions GetIssues()
        {
            repositoryIssueRequest = new RepositoryIssueRequest();

            return(this);
        }
示例#15
0
        private static async void GetChangelog()
        {
            try
            {
                RepositoryIssueRequest issueQuery;

                if (options.IncludeOpen == "Y")
                {
                    issueQuery = new RepositoryIssueRequest
                    {
                        Filter = IssueFilter.All,
                        State  = ItemStateFilter.All,
                    };
                }
                else
                {
                    issueQuery = new RepositoryIssueRequest
                    {
                        Filter = IssueFilter.All,
                        State  = ItemStateFilter.Closed,
                    };
                }

                var issues = await client.Issue.GetAllForRepository(options.Organization, options.Repo, issueQuery);

                Dictionary <IssueType, List <Issue> > IssuesByIssueType = new Dictionary <IssueType, List <Issue> >();
                foreach (var issue in issues)
                {
                    if (issue.Milestone != null && issue.Milestone.Title == options.Milestone)
                    {
                        bool      issueFixed = true;
                        bool      hidden     = false;
                        IssueType issueType  = IssueType.None;
                        bool      epicLabel  = false;
                        bool      regressionDuringThisVersion = false;
                        bool      engineeringImprovement      = false;
                        string    requiredLabel      = options.RequiredLabel?.ToLower();
                        bool      foundRequiredLabel = string.IsNullOrEmpty(requiredLabel);

                        foreach (var label in issue.Labels)
                        {
                            if (label.Name.Contains("ClosedAs:"))
                            {
                                issueFixed = false;
                            }

                            if (label.Name == "RegressionDuringThisVersion")
                            {
                                regressionDuringThisVersion = true;
                                hidden = true;
                            }

                            if (label.Name == "Area: Engineering Improvements")
                            {
                                engineeringImprovement = true;
                                hidden = true;
                            }

                            if (!foundRequiredLabel && label.Name.ToLower() == requiredLabel)
                            {
                                foundRequiredLabel = true;
                            }

                            switch (label.Name)
                            {
                            case "Epic":
                                epicLabel = true;
                                break;

                            case "Type:Feature":
                                issueType = IssueType.Feature;
                                break;

                            case "Type:DCR":
                                issueType = IssueType.DCR;
                                break;

                            case "Type:Bug":
                                issueType = IssueType.Bug;
                                break;

                            case "Type:Spec":
                                issueType = IssueType.Spec;
                                break;

                            default:
                                break;
                            }
                        }

                        if (!foundRequiredLabel)
                        {
                            hidden = true;
                        }

                        // if an issue is an epicLabel and has a real IssueType (feature/bug/dcr),
                        // then hide it... we want to show the primary epic issue only.
                        if (epicLabel)
                        {
                            if (issueType == IssueType.None)
                            {
                                issueType = IssueType.Feature;
                            }
                            else
                            {
                                hidden = true;
                            }
                        }
                        else if (issueType == IssueType.None)
                        {
                            if (!(issueFixed && !regressionDuringThisVersion && !engineeringImprovement))
                            {
                                hidden = true;
                            }
                        }

                        if (!hidden && issueFixed)
                        {
                            if (!IssuesByIssueType.ContainsKey(issueType))
                            {
                                IssuesByIssueType.Add(issueType, new List <Issue>());
                            }

                            IssuesByIssueType[issueType].Add(issue);
                        }
                    }
                }

                GenerateMarkdown(IssuesByIssueType);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
示例#16
0
        /// <summary>
        /// Gets issues for a repository.
        /// </summary>
        /// <remarks>
        /// http://developer.github.com/v3/issues/#list-issues-for-a-repository
        /// </remarks>
        /// <param name="repositoryId">The Id of the repository</param>
        /// <param name="request">Used to filter and sort the list of issues returned</param>
        public IObservable <Issue> GetAllForRepository(int repositoryId, RepositoryIssueRequest request)
        {
            Ensure.ArgumentNotNull(request, "request");

            return(GetAllForRepository(repositoryId, request, ApiOptions.None));
        }
        /// <summary>
        ///     Retrieves issue and security issue counts (subset) to minimize calls out.
        ///     Note: Octokit Search API was found earlier to be unreliable
        /// </summary>
        /// <returns> </returns>
        public async Task GetIssueHealth(HealthMetrics metrics)
        {
            Logger.Trace("GetIssueHealth({0}, {1})", purl.Namespace, purl.Name);

            var securityFlags = new string[] {
                "security", "insecure", "vulnerability", "cve", "valgrind", "xss",
                "sqli ", "vulnerable", "exploit", "fuzz", "injection",
                "buffer overflow", "valgrind", "sql injection", "csrf",
                "xsrf", "pwned", "akamai legacy ssl", "bad cipher ordering",
                "untrusted", "backdoor", "command injection"
            };

            var filter = new RepositoryIssueRequest
            {
                Filter = IssueFilter.All,
                State  = ItemStateFilter.All,
                Since  = DateTimeOffset.Now.Subtract(TimeSpan.FromDays(3 * 365))
            };

            int openIssues           = 0;
            int closedIssues         = 0;
            int openSecurityIssues   = 0;
            int closedSecurityIssues = 0;

            var issues = await Client.Issue.GetAllForRepository(purl.Namespace, purl.Name, filter);

            foreach (var issue in issues)
            {
                // filter out pull requests
                if (issue.Url.Contains("/pull") || issue.HtmlUrl.Contains("/pull"))
                {
                    continue;
                }

                //general issue status
                if (issue.State == ItemState.Open)
                {
                    openIssues++;
                }
                else if (issue.State == ItemState.Closed)
                {
                    closedIssues++;
                }

                // security status check within applicable fields
                var labels  = string.Join(",", issue.Labels.Select(l => l.Name));
                var content = issue.Title + issue.Body + labels;

                if (securityFlags.Any(s => content.Contains(s, StringComparison.InvariantCultureIgnoreCase)))
                {
                    if (issue.State == ItemState.Open)
                    {
                        openSecurityIssues++;
                    }
                    else if (issue.State == ItemState.Closed)
                    {
                        closedSecurityIssues++;
                    }
                }
            }
            double issueHealth = 0.0;

            if (openIssues + closedIssues > 0)
            {
                issueHealth = 30.0 * openIssues / (openIssues + closedIssues);
            }
            else
            {
                issueHealth = 50.0;
            }

            metrics.IssueHealth = issueHealth;

            double securityIssueHealth = 0.0;

            if (openSecurityIssues + closedSecurityIssues > 0)
            {
                securityIssueHealth = (double)openSecurityIssues / (double)(openSecurityIssues + closedSecurityIssues);
            }
            else
            {
                securityIssueHealth = 60.0;  // Lose a little credit if project never had a security issue
            }

            metrics.SecurityIssueHealth = securityIssueHealth;

            return;
        }
        public async Task ProcessIssueEvent(IssuesHookData issuePayload)
        {
            if (issuePayload.Action != "opened" &&
                issuePayload.Action != "reopened" &&
                issuePayload.Action != "closed")
            {
                _logger.LogInformation($"Received github action '{issuePayload.Action}', nothing to do");
                return;
            }

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

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

                return;
            }

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

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

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

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

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

                            return;
                        }
                    }
                }

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

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

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

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

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

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

            await IngestTriageItemsIntoKusto(triageItems);

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

            return;
        }
示例#19
0
        /// <summary>
        /// Gets all issues for a given repository
        /// </summary>
        /// <param name="repoId"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public static async Task <ObservableCollection <Issue> > GetAllIssuesForRepo(long repoId, RepositoryIssueRequest filter)
        {
            try
            {
                var client = await UserUtility.GetAuthenticatedClient();

                var issues = await client.Issue.GetAllForRepository(repoId, filter);

                return(new ObservableCollection <Issue>(issues));
            }
            catch
            {
                return(null);
            }
        }
示例#20
0
        /// <summary>
        /// Creates the report in markdown and returns it as a string
        /// </summary>
        /// <returns>The Markdown string</returns>
        public async Task <string> CreateReport()
        {
            Console.WriteLine($"{Resources.AppTitle}");
            Console.WriteLine($"{Resources.Copyright}");
            Console.WriteLine($"{Resources.PlsWait}");
            Console.WriteLine($"{Resources.Step} 1 {Resources.of} 3 - {Resources.Headers}");
            StringBuilder sb = new StringBuilder();

            sb.AppendLine($"# {Resources.Specification}");
            sb.AppendLine("");
            sb.AppendLine($"## {Resources.SpecificationFor} {_repository} {Resources.CreatedOn} {DateTime.Now}");
            sb.AppendLine("");
            sb.AppendLine($"## {Resources.OverallInfo}");
            sb.AppendLine("");

            var client    = new GitHubClient(new ProductHeaderValue("project-documentor"));
            var tokenAuth = new Credentials(_token);

            client.Credentials = tokenAuth;
            // var user = await client.User.Current().ConfigureAwait(true);

            var repo = await client.Repository.Get(_owner, _repository).ConfigureAwait(true);

            sb.AppendLine($"| {Resources.Item} | {Resources.Value} |");
            sb.AppendLine($"| -- | -- |");
            sb.AppendLine($"| {Resources.DateCreated} | {repo.CreatedAt} |");
            sb.AppendLine($"| {Resources.DefaultBranch} | {repo.DefaultBranch} |");
            sb.AppendLine($"| {Resources.Description} | {repo.Description} |");
            sb.AppendLine($"| {Resources.FullName} | {repo.FullName} |");
            sb.AppendLine($"| {Resources.URL} | {repo.GitUrl} |");
            sb.AppendLine($"| {Resources.Name} | {repo.Name} |");
            sb.AppendLine($"| {Resources.CurrentOpenIssues} | {repo.OpenIssuesCount} |");
            sb.AppendLine($"| {Resources.LastCodeUpdate} | {repo.PushedAt} |");
            sb.AppendLine($"| {Resources.Subscribers} | {repo.WatchersCount} |");
            sb.AppendLine($"| {Resources.Last_Update} | {repo.UpdatedAt} |");

            sb.AppendLine("");
            sb.AppendLine("## Project Information");
            sb.AppendLine("");
            var readme = await client.Repository.Content.GetReadme(_owner, _repository).ConfigureAwait(false);

            sb.Append(readme.Content);
            sb.AppendLine("");
            sb.AppendLine("## Non-Functional Requirements");
            sb.AppendLine("Non functional requirements are those which affect the environment of the running application but offer no additional value to the user");
            sb.AppendLine("");
            sb.AppendLine("### Overview");
            sb.AppendLine("");
            sb.AppendLine("| Id | Title | Priority |");
            sb.AppendLine("| --: | --- | --- |");

            var issuefilter = new RepositoryIssueRequest
            {
                Filter        = IssueFilter.All,
                State         = ItemStateFilter.All,
                SortProperty  = IssueSort.Created,
                SortDirection = SortDirection.Ascending
            };

            issuefilter.Labels.Add("Pri1");
            issuefilter.Labels.Add("NonFunctionalReq");
            var issues = await client.Issue.GetAllForRepository(_owner, _repository, issuefilter).ConfigureAwait(true);

            foreach (var item in issues)
            {
                sb.AppendLine($"| [{item.Number}]({item.HtmlUrl}) | {item.Title} | 1 |");
            }

            issuefilter = new RepositoryIssueRequest
            {
                Filter        = IssueFilter.All,
                State         = ItemStateFilter.All,
                SortProperty  = IssueSort.Created,
                SortDirection = SortDirection.Ascending
            };
            issuefilter.Labels.Add("Pri2");
            issuefilter.Labels.Add("NonFunctionalReq");
            issues = await client.Issue.GetAllForRepository(_owner, _repository, issuefilter).ConfigureAwait(true);

            foreach (var item in issues)
            {
                sb.AppendLine($"| [{item.Number}]({item.HtmlUrl}) | {item.Title} | 2 |");
            }

            issuefilter = new RepositoryIssueRequest
            {
                Filter        = IssueFilter.All,
                State         = ItemStateFilter.All,
                Since         = DateTimeOffset.Now.Subtract(TimeSpan.FromDays(120)),
                SortProperty  = IssueSort.Created,
                SortDirection = SortDirection.Ascending
            };
            issuefilter.Labels.Add("Pri3");
            issuefilter.Labels.Add("NonFunctionalReq");
            issues = await client.Issue.GetAllForRepository(_owner, _repository, issuefilter).ConfigureAwait(true);

            foreach (var item in issues)
            {
                sb.AppendLine($"| [{item.Number}]({item.HtmlUrl}) | {item.Title} | 3 |");
            }
            //Do Pri 1 NonFunc
            //Do Pri 2 NonFunc
            //Do Pri 3 NonFunc

            sb.AppendLine("");
            sb.AppendLine("### Details");
            //Do All NonFunc with details
            issuefilter = new RepositoryIssueRequest
            {
                Filter        = IssueFilter.All,
                State         = ItemStateFilter.All,
                SortProperty  = IssueSort.Created,
                SortDirection = SortDirection.Ascending
            };
            issuefilter.Labels.Add("NonFunctionalReq");
            issues = await client.Issue.GetAllForRepository(_owner, _repository, issuefilter).ConfigureAwait(true);

            foreach (var item in issues)
            {
                sb.AppendLine("");
                sb.AppendLine($"### {item.Number} - {item.Title}");
                sb.AppendLine("");


                foreach (var lbl in item.Labels)
                {
                    switch (lbl.Name)
                    {
                    case "Pri1":
                        sb.AppendLine("> **Priority One**");
                        sb.AppendLine("");
                        break;

                    case "Pri2":
                        sb.AppendLine("> ***Priority Two***");
                        sb.AppendLine("");
                        break;

                    case "Pri3":
                        sb.AppendLine("> *Priority Three*");
                        sb.AppendLine("");
                        break;

                    case "SpecRequired":
                        sb.AppendLine("**Note:** This item still requires detailed specifications");
                        break;
                    }
                }

                sb.AppendLine("");
                sb.Append(item.Body);
                sb.AppendLine("");
            }



            sb.AppendLine("");
            sb.AppendLine("## Functional Requirements");
            sb.AppendLine("");
            sb.AppendLine("### Overview");
            sb.AppendLine("");
            sb.AppendLine("| Id | Title | Priority |");
            sb.AppendLine("| --: | --- | --- |");
            //Do Pri 1 Func

            issuefilter = new RepositoryIssueRequest
            {
                Filter        = IssueFilter.All,
                State         = ItemStateFilter.All,
                SortProperty  = IssueSort.Created,
                SortDirection = SortDirection.Ascending
            };
            issuefilter.Labels.Add("Pri1");
            issuefilter.Labels.Add("FunctionalReq");
            issues = await client.Issue.GetAllForRepository(_owner, _repository, issuefilter).ConfigureAwait(true);

            foreach (var item in issues)
            {
                sb.AppendLine($"| [{item.Number}]({item.HtmlUrl}) | {item.Title} | 1 |");
            }

            issuefilter = new RepositoryIssueRequest
            {
                Filter        = IssueFilter.All,
                State         = ItemStateFilter.All,
                SortProperty  = IssueSort.Created,
                SortDirection = SortDirection.Ascending
            };
            issuefilter.Labels.Add("Pri2");
            issuefilter.Labels.Add("FunctionalReq");
            issues = await client.Issue.GetAllForRepository(_owner, _repository, issuefilter).ConfigureAwait(true);

            foreach (var item in issues)
            {
                sb.AppendLine($"| [{item.Number}]({item.HtmlUrl}) | {item.Title} | 2 |");
            }

            issuefilter = new RepositoryIssueRequest
            {
                Filter        = IssueFilter.All,
                State         = ItemStateFilter.All,
                SortProperty  = IssueSort.Created,
                SortDirection = SortDirection.Ascending
            };
            issuefilter.Labels.Add("Pri3");
            issuefilter.Labels.Add("FunctionalReq");
            issues = await client.Issue.GetAllForRepository(_owner, _repository, issuefilter).ConfigureAwait(true);

            foreach (var item in issues)
            {
                sb.AppendLine($"| [{item.Number}]({item.HtmlUrl}) | {item.Title} | 3 |");
            }
            //Do Pri 2 Func
            //Do Pri 3 Func

            sb.AppendLine("");
            sb.AppendLine("### Details");
            //Do All Func with details
            sb.AppendLine("");
            issuefilter = new RepositoryIssueRequest
            {
                Filter        = IssueFilter.All,
                State         = ItemStateFilter.All,
                SortProperty  = IssueSort.Created,
                SortDirection = SortDirection.Ascending
            };
            issuefilter.Labels.Add("FunctionalReq");
            issues = await client.Issue.GetAllForRepository(_owner, _repository, issuefilter).ConfigureAwait(true);

            foreach (var item in issues)
            {
                sb.AppendLine("");
                sb.AppendLine($"### {item.Number} - {item.Title}");
                sb.AppendLine("");


                foreach (var lbl in item.Labels)
                {
                    switch (lbl.Name)
                    {
                    case "Pri1":
                        sb.AppendLine("> **Priority One**");
                        sb.AppendLine("");
                        break;

                    case "Pri2":
                        sb.AppendLine("> ***Priority Two***");
                        sb.AppendLine("");
                        break;

                    case "Pri3":
                        sb.AppendLine("> *Priority Three*");
                        sb.AppendLine("");
                        break;

                    case "SpecRequired":
                        sb.AppendLine("**Note:** This item still requires detailed specifications");
                        break;
                    }
                }

                sb.AppendLine("");
                sb.Append(item.Body);
                sb.AppendLine("");
            }
            return(sb.ToString());
        }
示例#21
0
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "POST", Route = null)]
            HttpRequestMessage req, ILogger log)
        {
            var payloadJson = await req.Content.ReadAsStringAsync();

            SimpleJsonSerializer serializer   = new SimpleJsonSerializer();
            IssueEventPayload    issuePayload = serializer.Deserialize <IssueEventPayload>(payloadJson);

            if (issuePayload.Issue.User.Type.HasValue &&
                issuePayload.Issue.User.Type.Value == AccountType.Bot)
            {
                log.LogInformation("Comment is from DarcBot, ignoring.");
                return(new OkObjectResult($"Ignoring DarcBot comment"));
            }

            if (issuePayload.Action != "opened" &&
                issuePayload.Action != "reopened" &&
                issuePayload.Action != "closed")
            {
                log.LogInformation($"Received github action '{issuePayload.Action}', nothing to do");
                return(new OkObjectResult($"DarcBot has nothing to do with github issue action '{issuePayload.Action}'"));
            }

            // Determine identifiable information for triage item
            TriageItem triageItem = GetTriageItemProperties(issuePayload.Issue.Body);

            triageItem.Url = issuePayload.Issue.HtmlUrl;

            if (triageItem == null)
            {
                /* Item is not a triage item (does not contain identifiable information), do nothing */
                log.LogInformation($"{issuePayload.Issue.Url} is not a triage type issue.");
                return(new OkObjectResult("No identifiable information detected"));
            }

            int.TryParse(System.Environment.GetEnvironmentVariable("AppId"), out int appId);

            // Create jwt token
            // Private key is stored in Azure Key vault by downloading the private key (pem file) from GitHub, then
            // using the Azure CLI to store the value in key vault.
            // ie: az keyvault secret set --vault-name [vault name] --name GitHubApp-DarcBot-PrivateKey --encoding base64 --file [pem key file path]
            GitHubAppTokenProvider gitHubTokenProvider = new GitHubAppTokenProvider();
            var installationToken = gitHubTokenProvider.GetAppTokenFromEnvironmentVariableBase64(appId, "PrivateKey");

            // create client using jwt as a bearer token
            var          userAgent = new Octokit.ProductHeaderValue("DarcBot");
            GitHubClient appClient = new GitHubClient(userAgent)
            {
                Credentials = new Credentials(installationToken, AuthenticationType.Bearer),
            };

            // using the client, create an installation token
            AccessToken token = await appClient.GitHubApps.CreateInstallationToken(issuePayload.Installation.Id);

            // with the installation token, create a new GitHubClient that has the apps permissions
            var gitHubClient = new GitHubClient(new ProductHeaderValue("DarcBot-Installation"))
            {
                Credentials = new Credentials(token.Token)
            };

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

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

                log.LogInformation($"There are {issues.Count} open issues with the '{_darcBotLabelName}' label");
                foreach (var checkissue in issues)
                {
                    if (checkissue.Number != issuePayload.Issue.Number)
                    {
                        TriageItem issueItem = GetTriageItemProperties(checkissue.Body);
                        if (triageItem.Equals(issueItem))
                        {
                            await gitHubClient.Issue.Comment.Create(issuePayload.Repository.Id, issuePayload.Issue.Number, $"DarcBot has detected a duplicate issue.\n\nClosing as duplicate of {checkissue.HtmlUrl}\n\nFor more information see {_docLink}");

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

                            return(new OkObjectResult($"Resolved as duplicate of {checkissue.Number}"));
                        }
                    }
                }

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

                var update = issue.ToUpdate();
                update.AddLabel(_darcBotLabelName);
                await gitHubClient.Issue.Update(issuePayload.Repository.Id, issuePayload.Issue.Number, update);

                triageItem.UpdatedCategory = "InTriage";
            }

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

                foreach (var comment in comments)
                {
                    // Look for category information in comment
                    string category = GetDarcBotProperty("category", comment.Body);
                    if (!string.IsNullOrEmpty(category))
                    {
                        triageItem.UpdatedCategory = category;
                    }
                }
            }

            log.LogInformation($"buildId: {triageItem.BuildId}, recordId: {triageItem.RecordId}, index: {triageItem.Index}, category: {triageItem.UpdatedCategory}, url: {triageItem.Url}");

            await IngestTriageItemsIntoKusto(new[] { triageItem }, log);

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

            return(new OkObjectResult("Success"));
        }
        /// <summary>
        /// Gets issues for a repository.
        /// </summary>
        /// <remarks>
        /// http://developer.github.com/v3/issues/#list-issues-for-a-repository
        /// </remarks>
        /// <param name="owner">The owner of the repository</param>
        /// <param name="name">The name of the repository</param>
        /// <param name="request">Used to filter and sort the list of issues returned</param>
        public IObservable<Issue> GetAllForRepository(string owner, string name, RepositoryIssueRequest request)
        {
            Ensure.ArgumentNotNullOrEmptyString(owner, "owner");
            Ensure.ArgumentNotNullOrEmptyString(name, "name");
            Ensure.ArgumentNotNull(request, "request");

            return GetAllForRepository(owner, name, request, ApiOptions.None);
        }
示例#23
0
        /// <summary>
        /// Gets all issues for a given repository
        /// </summary>
        /// <param name="repoId"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public static async Task <ObservableCollection <Issue> > GetAllIssuesForRepo(long repoId, RepositoryIssueRequest filter, int pageIndex)
        {
            try
            {
                ApiOptions options = new ApiOptions
                {
                    PageCount = 1,
                    PageSize  = 10,
                    StartPage = pageIndex
                };
                var issues = await GlobalHelper.GithubClient.Issue.GetAllForRepository(repoId, filter, options);

                return(new ObservableCollection <Issue>(issues));
            }
            catch
            {
                return(null);
            }
        }
        /// <summary>
        /// Gets issues for a repository.
        /// </summary>
        /// <remarks>
        /// http://developer.github.com/v3/issues/#list-issues-for-a-repository
        /// </remarks>
        /// <param name="owner">The owner of the repository</param>
        /// <param name="name">The name of the repository</param>
        /// <param name="request">Used to filter and sort the list of issues returned</param>
        /// <param name="options">Options for changing the API response</param>
        public IObservable<Issue> GetAllForRepository(string owner, string name, RepositoryIssueRequest request, ApiOptions options)
        {
            Ensure.ArgumentNotNullOrEmptyString(owner, "owner");
            Ensure.ArgumentNotNullOrEmptyString(name, "name");
            Ensure.ArgumentNotNull(request, "request");
            Ensure.ArgumentNotNull(options, "options");

            return _connection.GetAndFlattenAllPages<Issue>(ApiUrls.Issues(owner, name), request.ToParametersDictionary(), AcceptHeaders.ReactionsPreview, options);
        }
        public List <UserActivityDTO> GetUserActivity(ActivityDTO activity)
        {
            List <UserActivityDTO> user_activities = new List <UserActivityDTO>();

            var user_profiles = dc.UserProfiles.Where(i => i.ProfilePropertyDefinition.PropertyName == activity.settings["Profile"].ToString()).Select(i => new { user_id = i.UserID, gitHub_login = i.PropertyValue }).ToList();

            GitHubClient gitHubClient = new GitHubClient(new ProductHeaderValue("Dnn.CommunityActivity"));

            gitHubClient.Credentials = new Credentials(activity.settings["Credentials"].ToString());

            RepositoryIssueRequest objOptions = new RepositoryIssueRequest();

            objOptions.Filter = IssueFilter.All;
            objOptions.State  = ItemStateFilter.All;

            List <Repository> repositories = new List <Repository>();

            var totalCount = int.MaxValue;
            var page       = 1;

            // get a list of all the repos matching the search criteria
            while (repositories.Count() < totalCount)
            {
                var request = new SearchRepositoriesRequest(activity.settings["Query"].ToString())
                {
                    Page = page,
                };
                var result = gitHubClient.Search.SearchRepo(request).Result;
                totalCount = result.TotalCount;
                repositories.AddRange(result.Items);
                page++;
            }

            foreach (Repository repository in repositories)
            {
                IReadOnlyList <Issue> issues = gitHubClient.Issue.GetAllForRepository(repository.Id, objOptions).Result;
                if (issues.Any())
                {
                    foreach (var user_profile in user_profiles)
                    {
                        Nullable <DateTime> last_activity_date = dc.CommunityMetrics_UserActivities.Where(i => i.user_id == user_profile.user_id && i.activity_id == activity.id).OrderByDescending(i => i.date).Select(i => i.date).FirstOrDefault();

                        var recent_issues = issues
                                            .Where(i =>
                                                   i.User != null &&
                                                   i.User.Login == user_profile.gitHub_login &&
                                                   i.CreatedAt.Date > last_activity_date.GetValueOrDefault() &&
                                                   i.CreatedAt.Date < DateTime.Now.Date
                                                   );

                        foreach (Issue issue in recent_issues)
                        {
                            if (issue.PullRequest == null) // exclude issues which are automatically generated for pull requests
                            {
                                var user_activity = user_activities.Where(i => i.user_id == user_profile.user_id && i.date == issue.CreatedAt.Date).SingleOrDefault();

                                if (user_activity == null)
                                {
                                    user_activity = new UserActivityDTO()
                                    {
                                        user_id     = user_profile.user_id,
                                        activity_id = activity.id,
                                        count       = 0,
                                        date        = issue.CreatedAt.Date
                                    };
                                    user_activities.Add(user_activity);
                                }
                                user_activity.count++;
                            }
                        }
                    }
                }
            }
            return(user_activities);
        }
        /// <summary>
        /// Gets issues for a repository.
        /// </summary>
        /// <remarks>
        /// http://developer.github.com/v3/issues/#list-issues-for-a-repository
        /// </remarks>
        /// <param name="owner">The owner of the repository</param>
        /// <param name="name">The name of the repository</param>
        /// <param name="request">Used to filter and sort the list of issues returned</param>
        /// <returns></returns>
        public IObservable<Issue> GetForRepository(string owner, string name, RepositoryIssueRequest request)
        {
            Ensure.ArgumentNotNullOrEmptyString(owner, "owner");
            Ensure.ArgumentNotNullOrEmptyString(name, "name");
            Ensure.ArgumentNotNull(request, "request");

            return _connection.GetAndFlattenAllPages<Issue>(ApiUrls.Issues(owner, name), request.ToParametersDictionary());
        }
示例#27
0
        // The incoming param values come (ultimately) come from parsing the incoming URL in QueryCountComponent in
        // count.component.ts.  The URLs could include milestones and/or labels.  Here, we have to translate the values
        // to GitHub/Octokit to get the desired result set.  There are some quirks that need clarification below...
        private async Task <IReadOnlyList <Issue> > GetIssuesAsync(string owner, string repository, string milestone, string labels, string excludedLabels)
        {
            // First, for milestone.  The URL handled by the Angular app might not have a milestone query parameter so it
            // would look something like this:
            //    https://<host>/count/nuget/home?label=VS1ES
            // In that case, the angular app will set the milestone to "undefined" before calling this service, which will
            // receive a URL like:
            //    https://<host>/api/CountByMilestone/nuget/home/undefined/VS1ES
            // Map "undefined" and null/whitespace to `null` in the Octokit issue request.  This tells Octokit "don't
            // consider milestones in this query."  Then Octokit returns issues regardless of their milestone setting -
            // including issues with _no_ milestone setting.  The URL could have "milestone='*'" - the milestone parameter
            // will pass that value.  GitHub/Octokit treats milestone = '*' as "any _set_ milestone."  So Octokit would
            // return all issues that have any milestone setting of any value - as long as the issue has one is set.
            // However, with '*' it won't return issues that have NO milestone setting.  Finally, if the URL includes a
            // valid milestone (eg "milestone=15.8"), translate that string value into the corresponding milestone ID and
            // put that in the issue request...
            if (string.IsNullOrWhiteSpace(milestone) || milestone == "undefined")
            {
                milestone = null;
            }
            else if (milestone == "any" || milestone == "*")
            {
                milestone = "*";
            }
            else if (milestone != "none")
            {
                // This throws a KeyNotFoundException if the incoming milestone value doesn't exist in the repo's collection
                // of milestone values.  Catch it in the calling function...
                var milestonesClient = new MilestonesClient(new ApiConnection(_gitHubClient.Connection));
                var milestoneRequest = new MilestoneRequest {
                    State = ItemStateFilter.Open
                };
                var milestones = await milestonesClient.GetAllForRepository(owner, repository, milestoneRequest);

                var milestonesByName = milestones.ToDictionary(m => m.Title, m => m.Number);
                milestone = milestonesByName[milestone].ToString();
            }

            var issueRequest = new RepositoryIssueRequest
            {
                Milestone = milestone,
                State     = ItemStateFilter.Open,
            };

            // Second, for labels.  In GitHub, issues can have zero or more label values, and the incoming URL could specify a
            // query for multiple values.  Those URL values are passed to this function as a string of comma separated values.
            // No values in the URL results in labels param value of "undefined" (same as above for milestone); A URL value of
            // "label=test&label=VS1ES" results in "test,VS1ES" --> split those and add each value to the issue request
            // Labels collection...
            if (!string.IsNullOrWhiteSpace(labels) && !(labels == "undefined"))
            {
                var labelvalues = labels.Split(',');
                foreach (var label in labelvalues)
                {
                    issueRequest.Labels.Add(label);
                }
            }

            // This could throw an ApiValidationException if the milestone doesn't exist in the repo.
            // Catch it in the calling function...
            var issues = await _gitHubClient.Issue.GetAllForRepository(owner, repository, issueRequest);

            issues = issues.Where(i => i.PullRequest == null).ToList();


            // We now need to exclude all the issues that have labels that should be excluded
            if (!String.IsNullOrEmpty(excludedLabels) && !(excludedLabels == "undefined"))
            {
                var filteredIssues      = new List <Issue>();
                var excludedLabelValues = excludedLabels.Split(',');

                foreach (Issue i in issues)
                {
                    bool skip = false;
                    foreach (Label l in i.Labels)
                    {
                        if (excludedLabelValues.Contains(l.Name))
                        {
                            skip = true;
                        }
                    }

                    if (!skip)
                    {
                        filteredIssues.Add(i);
                    }
                }

                issues = filteredIssues;
            }

            return(issues);
        }