コード例 #1
0
        private static void PopulateGitHubIssues(PerformContext context, List <Release> releases)
        {
            var repository      = new OurUmbraco.Community.Models.Repository("umbraco-cms", "umbraco", "Umbraco-CMS", "Umbraco CMS");
            var issuesDirectory = HostingEnvironment.MapPath($"{repository.IssuesStorageDirectory()}/");
            var pullsDirectory  = HostingEnvironment.MapPath($"{repository.IssuesStorageDirectory()}/pulls/");

            AddItemsToReleases(context, releases, issuesDirectory, "issue");
            AddItemsToReleases(context, releases, pullsDirectory, "pull");
        }
コード例 #2
0
        private GithubPullRequestModel GetPullRequest(OurUmbraco.Community.Models.Repository repository, string pullRequestNumber)
        {
            GithubPullRequestModel prModel = null;

            var store         = repository.IssuesStorageDirectory() + "/pulls/";
            var issueFile     = store + pullRequestNumber + ".pull.combined.json";
            var issueFilePath = HostingEnvironment.MapPath(issueFile);

            if (File.Exists(issueFilePath))
            {
                var content = File.ReadAllText(issueFilePath);
                prModel = JsonConvert.DeserializeObject <GithubPullRequestModel>(content);
            }

            return(prModel);
        }
コード例 #3
0
        public GithubPullRequestComment GetFirstTeamComment(OurUmbraco.Community.Models.Repository repository, string pullRequestNumber)
        {
            GithubPullRequestComment firstTeamCommment = null;
            var pr = GetPullRequest(repository, pullRequestNumber);

            if (pr != null)
            {
                var users        = GetTeam(repository.Slug).Members.Select(x => x.ToLower());
                var foundComment = pr.Comments.OrderBy(x => x.created_at).FirstOrDefault(x => users.Contains(x.user.Login.ToLower()));
                if (foundComment != null)
                {
                    firstTeamCommment = foundComment;
                }
            }

            return(firstTeamCommment);
        }
コード例 #4
0
        public List <PullRequestsInPeriod> GetGroupedPullRequestData(DateTime fromDate, DateTime toDate, string repository = "Umbraco-CMS")
        {
            var pullRequestService = new PullRequestService();
            var pullsNonHq         = pullRequestService.GetPullsNonHq(repository);

            var mergedPullsInPeriod = pullsNonHq
                                      .Where(x => x.MergedAt != null &&
                                             x.MergedAt > fromDate &&
                                             x.MergedAt <= toDate)
                                      .OrderBy(x => x.MergedAt)
                                      .GroupBy(x => new { x.MergedAt.Value.Year, x.MergedAt.Value.Month })
                                      .ToDictionary(x => x.Key, x => x.ToList());

            var closedPullsInPeriod = pullsNonHq
                                      .Where(x => x.ClosedAt != null &&
                                             x.ClosedAt > fromDate &&
                                             x.ClosedAt <= toDate)
                                      .OrderBy(x => x.ClosedAt)
                                      .GroupBy(x => new { x.ClosedAt.Value.Year, x.ClosedAt.Value.Month })
                                      .ToDictionary(x => x.Key, x => x.ToList());

            var createdPullsInPeriod = pullsNonHq
                                       .Where(x => x.CreatedAt != null &&
                                              x.CreatedAt > fromDate &&
                                              x.CreatedAt <= toDate)
                                       .OrderBy(x => x.CreatedAt)
                                       .GroupBy(x => new { x.CreatedAt.Value.Year, x.CreatedAt.Value.Month })
                                       .ToDictionary(x => x.Key, x => x.ToList());

            var firstPrs = new List <FirstPullRequest>();

            foreach (var pr in pullsNonHq)
            {
                if (pr.MergedAt != null && firstPrs.Any(x => x.Username == pr.User.Login) == false)
                {
                    firstPrs.Add(new FirstPullRequest {
                        Username = pr.User.Login, Year = pr.MergedAt.Value.Year, Month = pr.MergedAt.Value.Month
                    });
                }
            }

            var groupedPrs = new List <PullRequestsInPeriod>();

            var prService    = new PullRequestService();
            var prRepository = new OurUmbraco.Community.Models.Repository(
                repository.ToLower(), "umbraco", repository, repository.Replace("-", " "));

            foreach (var prInPeriod in mergedPullsInPeriod)
            {
                var mergeTimes            = new List <int>();
                var firstTeamCommentTimes = new List <int>();

                var recentPrsMerged       = 0;
                var totalMergeTimeInHours = 0;
                var totalMergedOnTime     = 0;
                var totalMergedNotOnTime  = 0;

                foreach (var pr in prInPeriod.Value)
                {
                    var mergeTimeInHours = Convert.ToInt32(pr.MergedAt.Value.Subtract(pr.CreatedAt.Value).TotalHours);
                    var mergeTimeInDays  = Convert.ToInt32(pr.MergedAt.Value.Subtract(pr.CreatedAt.Value).TotalDays);

                    recentPrsMerged       = recentPrsMerged + 1;
                    totalMergeTimeInHours = totalMergeTimeInHours + mergeTimeInHours;
                    if (mergeTimeInHours > 0)
                    {
                        mergeTimes.Add(mergeTimeInHours);
                    }

                    if (mergeTimeInDays <= 30)
                    {
                        totalMergedOnTime = totalMergedOnTime + 1;
                    }
                    else
                    {
                        totalMergedNotOnTime = totalMergedNotOnTime + 1;
                    }

                    var firstTeamComment = prService.GetFirstTeamComment(prRepository, pr.Number.ToString());
                    var timeSpan         = Convert.ToInt32(firstTeamComment?.created_at.Subtract(pr.CreatedAt.Value).TotalHours);
                    if (firstTeamComment != null)
                    {
                        pr.FirstTeamCommentTimeInHours = timeSpan;
                        firstTeamCommentTimes.Add(timeSpan);
                    }
                }

                var period    = $"{prInPeriod.Key.Year}{prInPeriod.Key.Month:00}";
                var groupName = $"{DateTimeFormatInfo.CurrentInfo.GetAbbreviatedMonthName(prInPeriod.Key.Month)} {prInPeriod.Key.Year}";
                var mergedPrs = new PullRequestsInPeriod
                {
                    GroupName    = groupName,
                    MonthYear    = period,
                    NumberMerged = prInPeriod.Value.Count,
                };

                var firstPrsUsernames = new List <string>();
                foreach (var firstPr in firstPrs)
                {
                    if (firstPr.Year == prInPeriod.Key.Year && firstPr.Month == prInPeriod.Key.Month)
                    {
                        firstPrsUsernames.Add(firstPr.Username);
                    }
                }

                mergedPrs.NewContributors             = firstPrsUsernames;
                mergedPrs.NumberOfNewContributors     = firstPrsUsernames.Count;
                mergedPrs.NumberMergedInThirtyDays    = totalMergedOnTime;
                mergedPrs.NumberNotMergedInThirtyDays = totalMergedNotOnTime;
                mergedPrs.NumberMergedRecent          = recentPrsMerged;

                mergedPrs.TotalMergeTimeInHours = totalMergeTimeInHours;
                var averageMergeTime = 0;
                if (recentPrsMerged > 0)
                {
                    averageMergeTime = Convert.ToInt32(mergedPrs.TotalMergeTimeInHours / recentPrsMerged);
                }
                mergedPrs.AveragePullRequestClosingTimeInHours = averageMergeTime;

                if (mergeTimes.Any())
                {
                    var medianMergeTime = mergeTimes.Median();
                    mergedPrs.MedianPullRequestClosingTimeInHours = medianMergeTime;
                }

                mergedPrs.AllPullRequestClosingTimesInHours = string.Join(",", mergeTimes);

                if (firstTeamCommentTimes.Any())
                {
                    var averageCommentTime = 0;
                    var totalCommentTime   = 0;
                    foreach (var time in firstTeamCommentTimes)
                    {
                        totalCommentTime = totalCommentTime + time;
                    }

                    if (totalCommentTime > 0)
                    {
                        averageCommentTime = Convert.ToInt32(totalCommentTime / recentPrsMerged);
                    }

                    mergedPrs.AverageFirstTeamCommentTimeInHours = averageCommentTime;

                    var medianFirstComment = firstTeamCommentTimes.Median();
                    mergedPrs.MedianFirstTeamCommentTimeInHours = medianFirstComment;
                }

                mergedPrs.AllFirstTeamCommentTimesInHours = string.Join(",", firstTeamCommentTimes);
                groupedPrs.Add(mergedPrs);
            }

            foreach (var prInPeriod in closedPullsInPeriod)
            {
                var period = $"{prInPeriod.Key.Year}{prInPeriod.Key.Month:00}";
                var prs    = new PullRequestsInPeriod();
                if (groupedPrs.Any(x => x.MonthYear == period))
                {
                    prs = groupedPrs.First(x => x.MonthYear == period);
                }
                else
                {
                    prs.MonthYear = period;
                }

                prs.NumberClosed = prInPeriod.Value.Count - prs.NumberMerged;
            }

            foreach (var prInPeriod in createdPullsInPeriod)
            {
                var period = $"{prInPeriod.Key.Year}{prInPeriod.Key.Month:00}";
                var prs    = new PullRequestsInPeriod();
                if (groupedPrs.Any(x => x.MonthYear == period))
                {
                    prs = groupedPrs.First(x => x.MonthYear == period);
                }
                else
                {
                    prs.MonthYear = period;
                }

                prs.NumberCreated = prInPeriod.Value.Count;
            }

            foreach (var pullRequestsInPeriod in groupedPrs)
            {
                var currentYear     = int.Parse(pullRequestsInPeriod.MonthYear.Substring(0, 4));
                var currentMonth    = int.Parse(pullRequestsInPeriod.MonthYear.Substring(4));
                var lastDayInMonth  = DateTime.DaysInMonth(currentYear, currentMonth);
                var maxDateInPeriod = new DateTime(currentYear, currentMonth, lastDayInMonth, 23, 59, 59);

                var openPrsForPeriod = new List <GithubPullRequestModel>();

                // if the PR was created in or before this period and is not closed or merged IN this period then it counts as open for this period
                var pullsCreatedBeforePeriod = pullsNonHq.Where(x => x.CreatedAt.Value <= maxDateInPeriod).OrderBy(x => x.CreatedAt);
                foreach (var pr in pullsCreatedBeforePeriod)
                {
                    if (pr.ClosedAt == null)
                    {
                        openPrsForPeriod.Add(pr);
                    }
                    else
                    // Was it closed (merged items also get set as closed) after the current period? Then it's stil open for this period.
                    if (pr.ClosedAt != null && pr.ClosedAt > maxDateInPeriod)
                    {
                        openPrsForPeriod.Add(pr);
                    }
                }
                pullRequestsInPeriod.TotalNumberOpen = openPrsForPeriod.Count;
                foreach (var githubPullRequestModel in openPrsForPeriod)
                {
                    if (githubPullRequestModel.CreatedAt > DateTime.Parse("2018-05-25") && githubPullRequestModel.MergedAt == null || githubPullRequestModel.MergedAt == DateTime.MinValue)
                    {
                        pullRequestsInPeriod.TotalNumberOpenAfterCodeGarden18 = pullRequestsInPeriod.TotalNumberOpenAfterCodeGarden18 + 1;
                    }
                }

                var activeContributors             = new List <string>();
                var activeContributorsAfterCg18    = new List <string>();
                var newActiveContributorsAfterCg18 = new List <string>();
                var firstPrsUsernamesAfterCg18     = new List <string>();

                foreach (var pr in pullsNonHq)
                {
                    var startDate = maxDateInPeriod.AddYears(-1).AddMonths(-1).AddDays(1);
                    if (pr.CreatedAt <= maxDateInPeriod && pr.CreatedAt >= startDate)
                    {
                        if (activeContributors.Any(x => x == pr.User.Login) == false)
                        {
                            activeContributors.Add(pr.User.Login);
                        }
                    }

                    var cg18StartDate = new DateTime(2018, 05, 20);
                    if (pr.CreatedAt <= maxDateInPeriod && pr.CreatedAt >= cg18StartDate)
                    {
                        if (activeContributorsAfterCg18.Any(x => x == pr.User.Login) == false)
                        {
                            activeContributorsAfterCg18.Add(pr.User.Login);
                        }
                    }
                }

                pullRequestsInPeriod.NumberOfActiveContributorsInPastYear = activeContributors.Count;
                pullRequestsInPeriod.NumberOfActiveContributorsAfterCg18  = activeContributorsAfterCg18.Count;

                pullRequestsInPeriod.TotalNumberOfContributors = firstPrs.Count;
            }

            groupedPrs = groupedPrs.OrderBy(x => x.MonthYear).ToList();
            if (groupedPrs.Any())
            {
                var firstPrDate = groupedPrs.First().MonthYear.DateFromMonthYear();
                var lastPrDate  = groupedPrs.Last().MonthYear.DateFromMonthYear();

                var numberOfMonths = firstPrDate.MonthsBetween(lastPrDate);
                var periodRange    = new List <string>();
                var periodDate     = firstPrDate;
                for (var i = 0; i < numberOfMonths; i++)
                {
                    var period = $"{periodDate.Year}{periodDate.Month:00}";
                    periodRange.Add(period);
                    periodDate = periodDate.AddMonths(1);
                }

                foreach (var period in periodRange)
                {
                    if (groupedPrs.Any(x => x.MonthYear == period))
                    {
                        continue;
                    }

                    var dateTime = period.DateFromMonthYear();

                    PullRequestsInPeriod previousPrStats = null;

                    var previousMonth = dateTime.AddMonths(-1);
                    if (previousMonth >= fromDate)
                    {
                        previousPrStats = GetPreviousPrStatsInPeriod(previousMonth, groupedPrs);
                    }

                    if (previousPrStats == null)
                    {
                        var groupName =
                            $"{DateTimeFormatInfo.CurrentInfo.GetAbbreviatedMonthName(dateTime.Month)} {dateTime.Year}";
                        groupedPrs.Add(new PullRequestsInPeriod
                        {
                            GroupName = groupName,
                            MonthYear = period
                        });
                    }
                    else
                    {
                        var groupName =
                            $"{DateTimeFormatInfo.CurrentInfo.GetAbbreviatedMonthName(dateTime.Month)} {dateTime.Year}";
                        groupedPrs.Add(new PullRequestsInPeriod
                        {
                            GroupName = groupName,
                            MonthYear = period,
                            NumberOfActiveContributorsInPastYear = previousPrStats.NumberOfActiveContributorsInPastYear,
                            TotalNumberOfContributors            = previousPrStats.TotalNumberOfContributors,
                            TotalNumberOpen = previousPrStats.TotalNumberOpen,
                            TotalNumberOpenAfterCodeGarden18 = previousPrStats.TotalNumberOpenAfterCodeGarden18
                        });
                    }
                }
            }

            return(groupedPrs.OrderBy(x => x.MonthYear).ToList());
        }
コード例 #5
0
ファイル: ReleasesService.cs プロジェクト: y1026/OurUmbraco
        private static void PopulateGitHubIssues(PerformContext context, List <Release> releases)
        {
            var repository      = new OurUmbraco.Community.Models.Repository("umbraco-cms", "umbraco", "Umbraco-CMS", "Umbraco CMS");
            var issuesDirectory = HostingEnvironment.MapPath($"{repository.IssuesStorageDirectory()}/");
            var files           = Directory.EnumerateFiles(issuesDirectory, "*.issue.combined.json").ToArray();

            context.WriteLine($"Found {files.Length} issues");

            foreach (var file in files)
            {
                var fileContent = File.ReadAllText(file);
                var issue       = JsonConvert.DeserializeObject <GitHubIssueModel>(fileContent);

                foreach (var label in issue.labels)
                {
                    if (label.name.StartsWith("release/") == false)
                    {
                        continue;
                    }

                    var version = label.name.Replace("release/", string.Empty);
                    var release = releases.FirstOrDefault(x => x.Version == version);
                    if (release == null)
                    {
                        context.WriteLine(
                            $"Issue {issue.number} is tagged with release version {version} but this release has no corresponding node in Our");
                        continue;
                    }

                    var breaking = issue.labels.Any(x => x.name == "compatibility/breaking");

                    var stateLabel = issue.labels.FirstOrDefault(x => x.name.StartsWith("state/"));

                    // default state
                    var state = "new";

                    if (stateLabel != null)
                    {
                        // if there's a label with a state then use that as the state
                        state = stateLabel.name.Replace("state/", string.Empty);
                    }
                    else if (issue.state == "closed" && issue.labels.Any(x => x.name.StartsWith("release")))
                    {
                        // there is no state label applied
                        // if the issue is closed and has a release label on it then we set it to fixed
                        state = "fixed";
                    }

                    var typeLabel = issue.labels.FirstOrDefault(x => x.name.StartsWith("type/"));
                    var type      = string.Empty;
                    if (typeLabel != null)
                    {
                        type = typeLabel.name.Replace("type/", string.Empty);
                    }

                    release.Issues.Add(new Release.Issue
                    {
                        Id       = issue.number.ToString(),
                        Breaking = breaking,
                        State    = state,
                        Title    = issue.title,
                        Type     = type,
                        Source   = "GitHub"
                    });
                }
            }
        }