Exemplo n.º 1
0
        private bool ShouldAddReviewer(PullRequestContext pullRequestContext, PullRequestReviewerSelectionStrategy[] strategies)
        {
            var result = false;

            if (strategies.Length == 0)
            {
                result = _pullRequestReviewerSelectionDefaultStrategy.Action == "add";
            }
            else
            {
                result = strategies.Any(q => q.Action == "add");
            }

            if (result)
            {
                if (!_addOnlyToUnsafePullrequests.HasValue || !_addOnlyToUnsafePullrequests.Value)
                {
                    return(true);
                }

                if (_addOnlyToUnsafePullrequests.Value && !pullRequestContext.PullRequestFilesAreSafe)
                {
                    return(true);
                }
            }

            return(false);
        }
Exemplo n.º 2
0
        private long GetLoadScore(PullRequestContext pullRequestContext, DeveloperKnowledge reviewer)
        {
            var reviwes   = new List <long>();
            var overitems = pullRequestContext.Overlap;

            if (overitems.Count == 0)
            {
                return(0);
            }

            foreach (var pullreq in pullRequestContext.KnowledgeMap.ReviewBasedKnowledgeMap.GetDeveloperReviews(reviewer.DeveloperName))
            {
                reviwes.Add(pullreq.Number);
            }
            var count            = overitems.Intersect(reviwes);
            var commits          = pullRequestContext.KnowledgeMap.CommitBasedKnowledgeMap.GetDeveloperCommits(reviewer.DeveloperName);
            var start            = pullRequestContext.PullRequest.CreatedAtDateTime;
            var end              = pullRequestContext.PullRequest.ClosedAtDateTime;
            var conflict_commits = commits.Where(a => a.AuthorDateTime >= start && a.AuthorDateTime <= end);

            if (conflict_commits.Count() > 1)
            {
                var i = 9;
            }
            return(count.Count() + conflict_commits.Count());
        }
        public (CommitState state, string description) GetStatus(PullRequestContext context)
        {
            var pullRequest = context.PullRequestInfo;
            var containsWip = ContainsWip(context.RepositorySettings);

            if (containsWip(pullRequest.Title))
            {
                context.Logger.LogInformation("Pull request title matches WIP regex");
                return(CommitState.Pending, "Work in progress");
            }

            if (pullRequest.CommitMessages.Any(containsWip))
            {
                context.Logger.LogInformation("Commit message matches WIP regex");
                return(CommitState.Pending, "Work in progress");
            }

            var wipLabels = context.RepositorySettings.WipLabels ?? Array.Empty <string>();

            if (pullRequest.Labels.Intersect(wipLabels, StringComparer.OrdinalIgnoreCase).Any())
            {
                context.Logger.LogInformation("Pull request has a WIP label");
                return(CommitState.Pending, "Work in progress");
            }

            if (pullRequest.CommitMessages.Any(ShouldBeSquashed))
            {
                context.Logger.LogInformation("Commit message has squash or fixup prefix");
                return(CommitState.Pending, "Needs to be squashed before merging");
            }

            return(CommitState.Success, "Ready to merge");
        }
 public PullRequestKnowledgeDistribution(
     IEnumerable <DeveloperKnowledge> reviewers,
     PullRequestContext pullRequestContext,
     Func <PullRequestContext, PullRequestKnowledgeDistributionFactors, double> scoreComputerFunc)
 {
     PullRequestKnowledgeDistributionFactors = new PullRequestKnowledgeDistributionFactors(reviewers, pullRequestContext, scoreComputerFunc);
 }
Exemplo n.º 5
0
        internal override sealed DeveloperKnowledge[] AvailablePRKnowledgeables(PullRequestContext pullRequestContext)
        {
            var availableDevs = pullRequestContext.PullRequestKnowledgeables.Where(q =>
                                                                                   q.DeveloperName != pullRequestContext.PRSubmitterNormalizedName &&
                                                                                   IsDeveloperAvailable(pullRequestContext, q.DeveloperName)).ToArray();

            ComputeAllReviewerScores(pullRequestContext, availableDevs);

            var depthToScanForReviewers = 0;

            while (availableDevs.All(q => q.Score == 0) && depthToScanForReviewers < 5)
            {
                depthToScanForReviewers++;
                var folderLevelOwners = GetFolderLevelOweners(depthToScanForReviewers, pullRequestContext)
                                        .Where(q => availableDevs.All(ad => q.DeveloperName != ad.DeveloperName));

                availableDevs = availableDevs.Concat(folderLevelOwners
                                                     .Where(q => q.DeveloperName != pullRequestContext.PRSubmitterNormalizedName &&
                                                            IsDeveloperAvailable(pullRequestContext, q.DeveloperName))).ToArray();

                ComputeAllReviewerScores(pullRequestContext, availableDevs);
            }

            return(availableDevs
                   .OrderByDescending(q => q.Score)
                   .ToArray());
        }
        public async Task <RepositorySettings> GetRepositorySettingsAsync(PullRequestContext context)
        {
            try
            {
                var baseRef      = context.Payload.PullRequest.Base.Ref;
                var repositoryId = context.Payload.Repository.Id;
                var client       = new GitHubClient(context.GithubConnection);
                var contents     = await client.Repository.Content.GetAllContentsByRef(repositoryId, "dontmergemeyet.yml", baseRef);

                var yaml     = contents.FirstOrDefault()?.Content;
                var settings = !string.IsNullOrEmpty(yaml)
                    ? YamlDeserializer.Deserialize <RepositorySettings>(yaml)
                    : DefaultSettings;
                return(settings);
            }
            catch (NotFoundException)
            {
                context.Logger.LogInformation("Configuration file not found, using defaults");
                return(DefaultSettings);
            }
            catch (Exception ex)
            {
                context.Logger.LogError(ex, "Failed to get configuration file from repo, using defaults");
                return(DefaultSettings);
            }
        }
Exemplo n.º 7
0
        internal override double ComputeReviewerScore(PullRequestContext pullRequestContext, DeveloperKnowledge reviewer)
        {
            double?commit_score          = 0.0;
            double?review_score          = 0.0;
            double?neighber_commit_score = 0.0;
            double?neighber_review_score = 0.0;

            foreach (var pullRequestFile in pullRequestContext.PullRequestFiles)
            {
                var canonicalPath = pullRequestContext.CanononicalPathMapper.GetValueOrDefault(pullRequestFile.FileName);
                if (canonicalPath == null)
                {
                    continue;
                }

                commit_score += ComputeCommitScore(pullRequestContext, canonicalPath, reviewer);

                review_score += ComputeReviewScore(pullRequestContext, canonicalPath, reviewer);
                var blameSnapshot = pullRequestContext.KnowledgeMap.BlameBasedKnowledgeMap.GetSnapshopOfPeriod(pullRequestContext.PullRequestPeriod.Id);
                var neighbors     = blameSnapshot.Trie.GetFileNeighbors(1, canonicalPath);
                for (int j = 0; j < neighbors.Length; j++)
                {
                    var neighber_file = neighbors[j];
                    neighber_commit_score += ComputeCommitScore(pullRequestContext, neighber_file, reviewer);
                    neighber_review_score += ComputeReviewScore(pullRequestContext, neighber_file, reviewer);
                }
            }
            double loadscore = GetLoadScore(pullRequestContext, reviewer);
            var    load      = Math.Pow(Math.E, (0.5 * loadscore));

            double final_score        = Convert.ToDouble(review_score + commit_score + neighber_commit_score + neighber_review_score) / load;
            double final_score_noload = Convert.ToDouble(review_score + commit_score + neighber_commit_score + neighber_review_score);

            return(final_score);
        }
        internal override double ComputeReviewerScore(PullRequestContext pullRequestContext, DeveloperKnowledge reviewer)
        {
            var probabilityOfStay = pullRequestContext.GetProbabilityOfStay(reviewer.DeveloperName, _numberOfPeriodsForCalculatingProbabilityOfStay.Value);
            var effort            = pullRequestContext.GetEffort(reviewer.DeveloperName, _numberOfPeriodsForCalculatingProbabilityOfStay.Value);

            return(effort * probabilityOfStay);
        }
Exemplo n.º 9
0
        protected override PullRequestRecommendationResult RecommendReviewers(PullRequestContext pullRequestContext)
        {
            var availableDevs = AvailablePRKnowledgeables(pullRequestContext);

            if (availableDevs.Length == 0)
            {
                return(Actual(pullRequestContext));
            }

            var simulationResults = new List <PullRequestKnowledgeDistribution>();
            var simulator         = new PullRequestReviewSimulator(pullRequestContext, availableDevs, ComputeScore);

            foreach (var candidateSet in GetPossibleCandidateSets(pullRequestContext, availableDevs))
            {
                var simulationResult = simulator.Simulate(candidateSet.Reviewers, candidateSet.SelectedCandidateKnowledge);
                simulationResults.Add(simulationResult);
            }

            if (simulationResults.Count == 0)
            {
                return(Actual(pullRequestContext));
            }

            var bestPullRequestKnowledgeDistribution = GetBestDistribution(simulationResults);

            return(Recommendation(pullRequestContext, availableDevs, bestPullRequestKnowledgeDistribution));
        }
Exemplo n.º 10
0
        private double ComputeReviewScore(PullRequestContext pullRequestContext, string filePath, DeveloperKnowledge reviewer)
        {
            double   score   = 0.0;
            DateTime nowTime = pullRequestContext.PullRequest.CreatedAtDateTime ?? DateTime.Now;
            var      data    = pullRequestContext.KnowledgeMap.ReviewBasedKnowledgeMap.GetReviowersOnFile(reviewer.DeveloperName, filePath);

            var reviewNumber = data.Keys.FirstOrDefault();

            var reviewerExpertise = pullRequestContext.KnowledgeMap.PullRequestEffortKnowledgeMap.GetReviewerExpertise(filePath, reviewer.DeveloperName);

            if (reviewNumber + reviewerExpertise.TotalComments == 0)
            {
                return(score);
            }

            var recency = data.Values.FirstOrDefault();

            if (recency < reviewerExpertise.RecentWorkDay)
            {
                recency = reviewerExpertise.RecentWorkDay ?? recency;
            }
            if (recency != DateTime.MinValue)
            {
                var diff_review = (nowTime - recency).TotalDays == 0 ? 1 : (nowTime - recency).TotalDays;
                score = reviewNumber + reviewerExpertise.TotalComments / diff_review;
            }
            return(score);
        }
Exemplo n.º 11
0
 private void ComputeAllReviewerScores(PullRequestContext pullRequestContext, DeveloperKnowledge[] availableDevs)
 {
     foreach (var candidate in availableDevs)
     {
         var score = ComputeReviewerScore(pullRequestContext, candidate);
         candidate.Score = score;
     }
 }
Exemplo n.º 12
0
 public PullRequestReviewSimulator(
     PullRequestContext pullRequestContext,
     DeveloperKnowledge[] availableDevs,
     Func <PullRequestContext, PullRequestKnowledgeDistributionFactors, double> scoreComputerFunc)
 {
     _pullRequestContext = pullRequestContext;
     _scoreComputerFunc  = scoreComputerFunc;
 }
Exemplo n.º 13
0
 public PullRequestKnowledgeDistributionFactors(
     IEnumerable <DeveloperKnowledge> reviewers,
     PullRequestContext pullRequestContext,
     Func <PullRequestContext, PullRequestKnowledgeDistributionFactors, double> scoreComputerFunc)
 {
     Reviewers          = reviewers;
     PullRequestContext = pullRequestContext;
     _scoreComputerFunc = scoreComputerFunc;
 }
Exemplo n.º 14
0
        internal override double ComputeReviewerScore(PullRequestContext pullRequestContext, DeveloperKnowledge reviewer)
        {
            var totalReviews = pullRequestContext.PullRequestKnowledgeables.Sum(q => q.NumberOfReviews);

            if (totalReviews == 0)
            {
                return(0);
            }

            return(reviewer.NumberOfReviews / (double)totalReviews);
        }
Exemplo n.º 15
0
 public async Task WriteCommitStatusAsync(PullRequestContext context, CommitState state, string description)
 {
     var client = new CommitStatusClient(new ApiConnection(context.GithubConnection));
     var status = new NewCommitStatus
     {
         State       = state,
         Description = description,
         Context     = _settingsProvider.Settings.StatusContext
     };
     await client.Create(context.Payload.Repository.Id, context.Payload.PullRequest.Head.Sha, status);
 }
Exemplo n.º 16
0
        internal override double ComputeReviewerScore(PullRequestContext pullRequestContext, DeveloperKnowledge reviewer)
        {
            var prFiles = pullRequestContext.PullRequestFiles.Select(q => pullRequestContext.CanononicalPathMapper[q.FileName])
                          .Where(q => q != null).ToArray();

            var reviewedFiles = reviewer.GetTouchedFiles().Where(q => prFiles.Contains(q));

            var specializedKnowledge = reviewedFiles.Count() / (double)pullRequestContext.PullRequestFiles.Length;

            return(1 - specializedKnowledge);
        }
        internal override double ComputeReviewerScore(PullRequestContext pullRequestContext, DeveloperKnowledge reviewer)
        {
            double spreadingScore = GetPersistSpreadingScore(pullRequestContext, reviewer);

            var expertiseScore = ComputeBirdReviewerScore(pullRequestContext, reviewer);

            var alpha = pullRequestContext.GetRiskyFiles(_riskOwenershipThreshold).Length > 0 ? 1 : 0;

            var score = (1 - alpha) * expertiseScore + alpha * spreadingScore;

            return(score);
        }
Exemplo n.º 18
0
        internal override sealed double ComputeScore(PullRequestContext pullRequestContext, PullRequestKnowledgeDistributionFactors pullRequestKnowledgeDistributionFactors)
        {
            var scores = new List <double>();

            foreach (var reviewer in pullRequestKnowledgeDistributionFactors.Reviewers)
            {
                double score = reviewer.Score == 0 ? ComputeReviewerScore(pullRequestContext, reviewer) : reviewer.Score;

                scores.Add(score);
            }

            return(scores.Aggregate((a, b) => a + b));
        }
Exemplo n.º 19
0
        public async Task HandleWebhookEventAsync(PullRequestContext context)
        {
            context.Logger.LogDebug("Getting details for pull request #{PullRequestNumber}...", context.Payload.Number);
            context.PullRequestInfo = await _prInfoProvider.GetPullRequestInfoAsync(context);

            context.Logger.LogDebug("Getting repository settings for pull request #{PullRequestNumber}", context.Payload.Number);
            context.RepositorySettings = await _repositorySettingsProvider.GetRepositorySettingsAsync(context);

            context.Logger.LogDebug("Evaluating status for pull request #{PullRequestNumber}...", context.Payload.Number);
            var(state, description) = _pullRequestPolicy.GetStatus(context);
            context.Logger.LogInformation("Status for pull request #{PullRequestNumber} is '{PullRequestState}' ({PullRequestDescription})", context.Payload.Number, state, description);

            context.Logger.LogDebug("Writing commit status for pull request #{PullRequestNumber}...", context.Payload.Number);
            await _statusWriter.WriteCommitStatusAsync(context, state, description);
        }
Exemplo n.º 20
0
        public async Task HandleWebhookEventAsync(PullRequestContext context)
        {
            context.Log.Verbose($"Getting details for pull request #{context.Payload.Number}...");
            context.PullRequestInfo = await _prInfoProvider.GetPullRequestInfoAsync(context);

            context.Log.Verbose($"Getting repository settings for pull request #{context.Payload.Number}");
            context.RepositorySettings = await _repositorySettingsProvider.GetRepositorySettingsAsync(context);

            context.Log.Verbose($"Evaluating status for pull request #{context.Payload.Number}...");
            var(state, description) = _pullRequestPolicy.GetStatus(context);
            context.Log.Info($"Status for pull request #{context.Payload.Number} is '{state}' ({description})");

            context.Log.Verbose($"Writing commit status for pull request #{context.Payload.Number}...");
            await _statusWriter.WriteCommitStatusAsync(context, state, description);
        }
Exemplo n.º 21
0
        private int GetSelectedCandidatesLength(PullRequestContext pullRequestContext, PullRequestReviewerSelectionStrategy[] strategies, string policy)
        {
            var length = _pullRequestReviewerSelectionDefaultStrategy.ActionArgument;

            if (strategies.Length > 0)
            {
                length = strategies.Single(q => q.Action.StartsWith(policy)).ActionArgument;
            }

            if (length == "all")
            {
                return(pullRequestContext.ActualReviewers.Length);
            }

            return(int.Parse(length));
        }
        public async Task <PullRequestInfo> GetPullRequestInfoAsync(PullRequestContext context)
        {
            context.Log.Verbose($"Getting commits for pull request #{context.Payload.Number}");
            var commits = await GetCommitsAsync(context);

            context.Log.Verbose($"Getting labels for pull request #{context.Payload.Number}");
            var labels = await GetLabelsAsync(context);

            return(new PullRequestInfo
            {
                Title = context.Payload.PullRequest.Title,
                Labels = labels.Select(l => l.Name),
                SourceRepositoryFullName = context.Payload.Repository.FullName,
                Head = context.Payload.PullRequest.Head.Sha,
                CommitMessages = commits.Select(c => c.Commit.Message)
            });
        }
        private double GetPersistSpreadingScore(PullRequestContext pullRequestContext, DeveloperKnowledge reviewer)
        {
            var reviewerImportance = pullRequestContext.IsHoarder(reviewer.DeveloperName) ? _hoarderRatio : 1;

            var probabilityOfStay = pullRequestContext.GetProbabilityOfStay(reviewer.DeveloperName, _numberOfPeriodsForCalculatingProbabilityOfStay.Value);
            var effort            = pullRequestContext.GetEffort(reviewer.DeveloperName, _numberOfPeriodsForCalculatingProbabilityOfStay.Value);

            var prFiles = pullRequestContext.PullRequestFiles.Select(q => pullRequestContext.CanononicalPathMapper[q.FileName])
                          .Where(q => q != null).ToArray();
            var reviewedFiles        = reviewer.GetTouchedFiles().Where(q => prFiles.Contains(q));
            var specializedKnowledge = reviewedFiles.Count() / (double)pullRequestContext.PullRequestFiles.Length;

            var spreadingScore = 0.0;

            spreadingScore = reviewerImportance * Math.Pow(probabilityOfStay * effort, _alpha) * Math.Pow(1 - specializedKnowledge, _beta);

            return(spreadingScore);
        }
        public async Task <PullRequestInfo> GetPullRequestInfoAsync(PullRequestContext context)
        {
            context.Logger.LogDebug("Getting commits for pull request {RepoName}#{PullRequestNumber}", context.RepositoryName, context.Payload.Number);
            var commits = await GetCommitsAsync(context);

            context.Logger.LogDebug("Getting labels for pull request {RepoName}#{PullRequestNumber}", context.RepositoryName, context.Payload.Number);
            var labels = await GetLabelsAsync(context);

            return(new PullRequestInfo
            {
                Title = context.Payload.PullRequest.Title,
                Labels = labels.Select(l => l.Name),
                IsDraft = context.Payload.PullRequest.Draft,
                SourceRepositoryFullName = context.RepositoryName,
                Head = context.Payload.PullRequest.Head.Sha,
                CommitMessages = commits.Select(c => c.Commit.Message)
            });
        }
Exemplo n.º 25
0
        private long GetLoadScore(PullRequestContext pullRequestContext, DeveloperKnowledge reviewer)
        {
            var reviwes   = new List <long>();
            var overitems = pullRequestContext.Overlap;

            if (overitems.Count == 0)
            {
                return(0);
            }

            foreach (var pullreq in pullRequestContext.KnowledgeMap.ReviewBasedKnowledgeMap.GetDeveloperReviews(reviewer.DeveloperName))
            {
                reviwes.Add(pullreq.Number);
            }
            var count = overitems.Intersect(reviwes);

            return(count.Count());
        }
Exemplo n.º 26
0
        internal override double ComputeReviewerScore(PullRequestContext pullRequestContext, DeveloperKnowledge reviewer)
        {
            var alpha = pullRequestContext.GetRiskyFiles(_riskOwenershipThreshold).Length > 0 ? 1 : 0;

            if (alpha == 1)
            {
                double spreadingScore = GetPersistSpreadingScore(pullRequestContext, reviewer);
                return(spreadingScore);
            }
            else
            {
                double loadscore = GetLoadScore(pullRequestContext, reviewer);
                var    load      = Math.Pow(Math.E, (0.5 * loadscore));

                var expertiseScore = ComputeBirdReviewerScore(pullRequestContext, reviewer);

                return(expertiseScore / load);
            }
        }
Exemplo n.º 27
0
        private bool IsRandomReplacement(PullRequestContext pullRequestContext, PullRequestReviewerSelectionStrategy[] strategies)
        {
            if (pullRequestContext.ActualReviewers.Length == 0)
            {
                return(false);
            }

            var result = false;

            if (strategies.Length == 0)
            {
                result = _pullRequestReviewerSelectionDefaultStrategy.Action == "replacerandom";
            }
            else
            {
                result = strategies.Any(q => q.Action == "replacerandom");
            }

            return(result);
        }
Exemplo n.º 28
0
        private bool ShouldReplaceReviewer(PullRequestContext pullRequestContext, PullRequestReviewerSelectionStrategy[] strategies)
        {
            if (pullRequestContext.ActualReviewers.Length == 0)
            {
                return(false);
            }

            var result = false;

            if (strategies.Length == 0)
            {
                result = _pullRequestReviewerSelectionDefaultStrategy.Action.StartsWith("replace");
            }
            else
            {
                result = strategies.Any(q => q.Action.StartsWith("replace"));
            }

            return(result);
        }
Exemplo n.º 29
0
        private PullRequestReviewerSelectionStrategy[] GetModificationStrategies(PullRequestContext pullRequestContext)
        {
            var strategies = _pullRequestReviewerSelectionStrategies
                             .Where(q => q.ActualReviewerCount == pullRequestContext.ActualReviewers.Length.ToString())
                             .ToArray();

            if (strategies.Length > 2)
            {
                throw new InvalidOperationException($"There are more than two modification strategies for : {pullRequestContext.ActualReviewers.Length}");
            }

            if (strategies.Length == 2)
            {
                if (strategies[0].Action == strategies[1].Action)
                {
                    throw new InvalidOperationException($"There are duplicated modification strategies for : {pullRequestContext.ActualReviewers.Length}");
                }
            }

            return(strategies);
        }
Exemplo n.º 30
0
        private double ComputeCommitScore(PullRequestContext pullRequestContext, string filePath, DeveloperKnowledge reviewer)
        {
            double score = 0.0;

            DateTime reviewer_recency = DateTime.MinValue;
            DateTime nowTime          = pullRequestContext.PullRequest.CreatedAtDateTime ?? DateTime.Now;
            var      reviewerCommits  = pullRequestContext.KnowledgeMap.CommitBasedKnowledgeMap.GetDeveloperCommitsOnFile(reviewer.DeveloperName, filePath, nowTime, reviewer_recency);

            if (reviewerCommits == 0)
            {
                return(score);
            }


            if (reviewer_recency != DateTime.MinValue)
            {
                var diff_review = (nowTime - reviewer_recency).TotalDays == 0 ? 1 : (nowTime - reviewer_recency).TotalDays;

                score = reviewerCommits / diff_review;
            }
            return(score);
        }