Exemplo n.º 1
0
        static async Task Main(string[] args)
        {
            Console.WriteLine(Environment.CurrentDirectory);

            // There's probably an idiomatic way to tuck these into the DI container as referenceable values...
            var dosBuffer = TimeSpan.FromSeconds(0.1);
            var loopDelay = TimeSpan.FromHours(24);
            // Also include: cache path, scratch dir, etc. All the static readonlys above except the CTS, probably

            var configuration = new ConfigurationBuilder()
                                .AddEnvironmentVariables()
                                .AddJsonFile(_configPath, optional: false, reloadOnChange: true)
                                .Build();

            var serviceCollection = new ServiceCollection()
                                    .Configure <PullRequestConstants>(RepositoryKind.GitHub.ToString(),
                                                                      configuration.GetSection("PRConstants:GitHub"))
                                    .Configure <PullRequestConstants>(RepositoryKind.BitBucketCloud.ToString(),
                                                                      configuration.GetSection("PRConstants:BitBucketCloud"))
                                    .AddTransient(sp =>
            {
                var prConstantsAccessor = sp.GetRequiredService <IOptionsSnapshot <PullRequestConstants> >();
                var prConstants         = prConstantsAccessor.Get(RepositoryKind.GitHub.ToString());
                return(new GitHubApprovalAnalyzer(
                           prConstants.ExplicitApprovals,
                           prConstants.ExplicitNonApprovals,
                           prConstants.ImplicitApprovals));
            }).AddTransient(sp =>
            {
                var prConstantsAccessor = sp.GetRequiredService <IOptionsSnapshot <PullRequestConstants> >();
                var prConstants         = prConstantsAccessor.Get(RepositoryKind.BitBucketServer.ToString());
                return(new BitBucketApprovalAnalyzer(
                           prConstants.ExplicitApprovals,
                           prConstants.ExplicitNonApprovals,
                           prConstants.ImplicitApprovals));
            })
                                    // Reusable building blocks
                                    .AddSingleton <IFilesystem>(sp => new Filesystem())
                                    .AddSingleton <IClock, Clock>()
                                    .AddSingleton <IWordCounter, WordCounter>()
                                    .AddSingleton <INormalizer, HtmlCommentStripper>()
                                    .AddSingleton(sp => GetKnownScorers(
                                                      approvalAnalyzer: sp.GetRequiredService <GitHubApprovalAnalyzer>(),
                                                      wc: sp.GetRequiredService <IWordCounter>()))
                                    .AddSingleton(sp => new ScorerConverter(sp.GetRequiredService <IScorerFactory>()))
                                    .AddSingleton(sp => GetDebugJsonSerializerSettings(sp.GetRequiredService <IScorerFactory>()))
                                    .AddSingleton(sp => new FilesystemDataProvider(sp.GetRequiredService <IFilesystem>(), _scratchDir, sp.GetRequiredService <JsonSerializerSettings>()))
                                    .AddSingleton <IPullRequestCacheManager>(sp => sp.GetRequiredService <FilesystemDataProvider>())
                                    // Do this so that we *can* modify our Markdown pipeline later on if we need to.
                                    .AddSingleton(new MarkdownPipelineBuilder().Build())
                                    .AddSingleton <IHistoricalAnalysisManager>(sp => sp.GetRequiredService <FilesystemDataProvider>())
                                    // CommentScorers
                                    .AddSingleton <UrlScorer>()
                                    .AddSingleton <CodeFenceScorer>()
                                    .AddSingleton <CodeFragmentScorer>()
                                    .AddSingleton <GitHubIssueLinkScorer>()
                                    .AddSingleton <Scorer>(sp => sp.GetRequiredService <UrlScorer>())
                                    .AddSingleton <Scorer>(sp => sp.GetRequiredService <CodeFenceScorer>())
                                    .AddSingleton <Scorer>(sp => sp.GetRequiredService <CodeFragmentScorer>())
                                    .AddSingleton <Scorer>(sp => sp.GetRequiredService <GitHubIssueLinkScorer>())
                                    // PullRequestScorers
                                    .AddSingleton <WordCountScorer>()
                                    .AddSingleton <BusinessDaysScorer>()
                                    .AddSingleton <UniqueCommenterScorer>()
                                    .AddSingleton(sp => new CommentCountScorer(sp.GetRequiredService <IWordCounter>()))
                                    .AddSingleton(sp => new ApprovalScorer(sp.GetRequiredService <GitHubApprovalAnalyzer>()))
                                    .AddSingleton(sp => new CommentCountScorer(sp.GetRequiredService <IWordCounter>()))
                                    .AddSingleton <Scorer>(sp => sp.GetRequiredService <ApprovalScorer>())
                                    .AddSingleton <Scorer>(sp => sp.GetRequiredService <BusinessDaysScorer>())
                                    .AddSingleton <Scorer>(sp => sp.GetRequiredService <CommentCountScorer>())
                                    .AddSingleton <Scorer>(sp => sp.GetRequiredService <UniqueCommenterScorer>())
                                    .AddSingleton <Scorer>(sp => sp.GetRequiredService <WordCountScorer>())
                                    // Roll it all up into the orchestrators and factories...
                                    .AddSingleton <IPullRequestAnalyzer>(sp => new PullRequestAnalyzer(sp.GetServices <Scorer>()))
                                    .AddSingleton <IRepositoryAnalyzer>(sp => new RepositoryAnalyzer(sp.GetRequiredService <IClock>()))
                                    .AddSingleton(sp => new GitHubPullRequestReaderFactory("repoman-health-metrics", sp.GetRequiredService <INormalizer>()))
                                    .AddSingleton(sp => new BitBucketCloudPullRequestReaderFactory(
                                                      sp.GetRequiredService <IClock>(),
                                                      sp.GetRequiredService <JsonSerializerSettings>(),
                                                      httpConnectionLifespan: TimeSpan.FromSeconds(120),
                                                      GetLogger <BitBucketCloudPullRequestReaderFactory>()))
                                    .AddSingleton <IPullRequestReaderFactory, PullRequestReaderFactory>(sp => new PullRequestReaderFactory(
                                                                                                            sp.GetRequiredService <GitHubPullRequestReaderFactory>(),
                                                                                                            sp.GetRequiredService <BitBucketCloudPullRequestReaderFactory>(),
                                                                                                            GetLogger <PullRequestReaderFactory>()))
                                    .AddSingleton <IRepoManagerFactory>(sp => new RepoManagerFactory(
                                                                            sp.GetRequiredService <IPullRequestReaderFactory>(),
                                                                            sp.GetRequiredService <IPullRequestCacheManager>(),
                                                                            dosBuffer,
                                                                            GetLogger <RepoManagerFactory>()));

            var serviceProvider = serviceCollection.BuildServiceProvider();

            // FUTURE: Consider implementing an UpgradeAsync method that can do one-time data transformations/updates on cached data

            var repos        = configuration.GetSection("WatchedRepositories").Get <List <WatchedRepository> >();
            var repoManagers = repos
                               .Select(r => serviceProvider.GetRequiredService <IRepoManagerFactory>().GetManagerAsync(r, refreshFromUpstream: false))
                               .ToList();
            await Task.WhenAll(repoManagers);

            var repoWorkerInitialization = repoManagers
                                           .Select(t => t.Result)
                                           .Select(async repoManager => await RepoWorker.InitializeAsync(
                                                       repoManager,
                                                       serviceProvider.GetRequiredService <IPullRequestAnalyzer>(),
                                                       serviceProvider.GetRequiredService <IRepositoryAnalyzer>(),
                                                       serviceProvider.GetRequiredService <IHistoricalAnalysisManager>(),
                                                       serviceProvider.GetRequiredService <IClock>(),
                                                       GetLogger <RepoWorker>()))
                                           .ToList();
            await Task.WhenAll(repoWorkerInitialization);

            var loopServices = repoWorkerInitialization
                               .Select(rwi => rwi.Result)
                               .Select(rw => new LoopService(rw, loopDelay, _cts, _logger))
                               .Select(l => l.LoopAsync())
                               .ToList();
            await Task.WhenAll(loopServices);
        }
Exemplo n.º 2
0
 public AppService(ApplicationContext context)
 {
     Repo = new RepoWorker(context);
 }