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