Esempio n. 1
0
 private RepoWorker(
     IRepoManager repoManager,
     string workerName,
     IPullRequestAnalyzer prAnalyzer,
     IRepositoryAnalyzer repoAnalyzer,
     IHistoricalAnalysisManager analysisManager,
     IClock clock,
     ILogger logger)
 {
     _repoManager     = repoManager ?? throw new ArgumentNullException(nameof(repoManager));
     Name             = workerName;
     _prAnalyzer      = prAnalyzer ?? throw new ArgumentNullException(nameof(prAnalyzer));
     _repoAnalyzer    = repoAnalyzer ?? throw new ArgumentNullException(nameof(repoAnalyzer));
     _analysisManager = analysisManager ?? throw new ArgumentNullException(nameof(analysisManager));
     _clock           = clock ?? throw new ArgumentNullException(nameof(clock));
     _logger          = logger ?? throw new ArgumentNullException(nameof(logger));
 }
Esempio n. 2
0
        public static async Task <RepoWorker> InitializeAsync(
            IRepoManager repoManager,
            IPullRequestAnalyzer prAnalyzer,
            IRepositoryAnalyzer repoAnalyzer,
            IHistoricalAnalysisManager analysisManager,
            IClock clock,
            ILogger logger)
        {
            if (repoManager is null)
            {
                throw new ArgumentNullException(nameof(repoManager));
            }
            if (prAnalyzer is null)
            {
                throw new ArgumentNullException(nameof(prAnalyzer));
            }
            if (repoAnalyzer is null)
            {
                throw new ArgumentNullException(nameof(repoAnalyzer));
            }
            if (analysisManager is null)
            {
                throw new ArgumentNullException(nameof(analysisManager));
            }
            if (clock is null)
            {
                throw new ArgumentNullException(nameof(clock));
            }
            if (logger is null)
            {
                throw new ArgumentNullException(nameof(logger));
            }

            var name = $"{repoManager.RepoOwner}:{repoManager.RepoName}";

            // Analysis steps
            // 1a) Find metrics for where the set of analyzers has differed
            // 1b) Recompute those metrics
            // 1c) Overwrite the old metric snapshots
            // 2a) Find things known to the cache, but that haven't been analyzed
            // 2b) Analyze this new stuff
            // 2c) Write down the new snapshot

            var cachedPullRequestByNumber = (await repoManager.GetPullRequestsAsync())
                                            .ToDictionary(pr => pr.Number);

            var previousMetrics = (await analysisManager.LoadHistoryAsync(repoManager.RepoOwner, repoManager.RepoName))
                                  ?? new List <MetricSnapshot>();

            var previousPullRequestMetricsByNumber = previousMetrics
                                                     .SelectMany(m => m.PullRequestMetrics.Values)
                                                     .ToDictionary(pr => pr.Number);

            // 1a) Find metrics for where the set of analyzers has differed
            var previouslyComputedButHasChanged = previousMetrics
                                                  .Where(m => !m.Scorers.SetEquals(prAnalyzer.Scorers))
                                                  .ToList();

            // 2a) Find things known to the cache, but that haven't been analyzed
            var cachedButNotAnalyzed = cachedPullRequestByNumber
                                       .Where(pr => !previousPullRequestMetricsByNumber.ContainsKey(pr.Key))
                                       .Select(pr => pr.Key)
                                       .ToList();

            var worker = new RepoWorker(repoManager, name, prAnalyzer, repoAnalyzer, analysisManager, clock, logger);

            var analysisToBeDone = previouslyComputedButHasChanged.Any() || cachedButNotAnalyzed.Any();

            if (!analysisToBeDone)
            {
                return(worker);
            }

            // 1b) Recompute those metrics
            var toBeSaved = new List <MetricSnapshot>();

            if (previouslyComputedButHasChanged.Any())
            {
                var now = clock.DateTimeOffsetUtcNow();

                var scorers = prAnalyzer.Scorers.ToHashSet();
                foreach (var originalMetric in previouslyComputedButHasChanged)
                {
                    var prMetrics = originalMetric.PullRequestMetrics
                                    .Select(prMetric => prMetric.Value.Number)
                                    .Select(nbr => cachedPullRequestByNumber[nbr])
                                    .Select(prAnalyzer.CalculatePullRequestMetrics)
                                    .ToList();
                    var replacements = repoAnalyzer.CalculateRepositoryMetricsOverTime(prMetrics);

                    foreach (var replacement in replacements)
                    {
                        replacement.CreatedAt = originalMetric.CreatedAt;
                        replacement.UpdatedAt = now;
                        replacement.Scorers   = scorers;
                        replacement.Owner     = repoManager.RepoOwner;
                        replacement.Name      = repoManager.RepoName;
                        replacement.Url       = repoManager.RepoUrl;
                    }
                    toBeSaved.AddRange(replacements);
                }
            }

            if (cachedButNotAnalyzed.Any())
            {
                // 2b) Analyze this new stuff
                var now = clock.DateTimeOffsetUtcNow();
                var newPullRequestMetrics = cachedButNotAnalyzed
                                            .Select(nbr => cachedPullRequestByNumber[nbr])
                                            .Select(prAnalyzer.CalculatePullRequestMetrics)
                                            .ToList();
                var newRepoMetrics = repoAnalyzer.CalculateRepositoryMetricsOverTime(newPullRequestMetrics);
                var prAnalyzers    = prAnalyzer.Scorers.ToHashSet();
                foreach (var newRepoMetric in newRepoMetrics)
                {
                    newRepoMetric.CreatedAt = now;
                    newRepoMetric.UpdatedAt = now;
                    newRepoMetric.Scorers   = prAnalyzers;
                    newRepoMetric.Owner     = repoManager.RepoOwner;
                    newRepoMetric.Name      = repoManager.RepoName;
                    newRepoMetric.Url       = repoManager.RepoUrl;
                }

                toBeSaved.AddRange(newRepoMetrics);
            }

            // 1c) Overwrite the old metric snapshots
            // 2c) Write down the new snapshot
            await analysisManager.SaveAsync(toBeSaved);

            return(worker);
        }