diff --git a/.editorconfig b/.editorconfig index 2df3d0518..d6c74b153 100644 --- a/.editorconfig +++ b/.editorconfig @@ -213,6 +213,9 @@ csharp_style_namespace_declarations = file_scoped dotnet_analyzer_diagnostic.severity = warning dotnet_analyzer_diagnostic.category-Style.severity = warning +# can be made static +dotnet_diagnostic.CA1822.severity = suggestion + # https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1848 dotnet_diagnostic.CA1848.severity = suggestion # https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2201 diff --git a/src/Elastic.ApiExplorer/OpenApiGenerator.cs b/src/Elastic.ApiExplorer/OpenApiGenerator.cs index ec68fc819..d129ee0bb 100644 --- a/src/Elastic.ApiExplorer/OpenApiGenerator.cs +++ b/src/Elastic.ApiExplorer/OpenApiGenerator.cs @@ -38,9 +38,9 @@ public record ApiEndpoint(List Operations, string? Name) : IApiGro public Task RenderAsync(FileSystemStream stream, ApiRenderContext context, CancellationToken ctx = default) => Task.CompletedTask; } -public class OpenApiGenerator(BuildContext context, IMarkdownStringRenderer markdownStringRenderer, ILoggerFactory logger) +public class OpenApiGenerator(ILoggerFactory logFactory, BuildContext context, IMarkdownStringRenderer markdownStringRenderer) { - private readonly ILogger _logger = logger.CreateLogger(); + private readonly ILogger _logger = logFactory.CreateLogger(); private readonly IFileSystem _writeFileSystem = context.WriteFileSystem; private readonly StaticFileContentHashProvider _contentHashProvider = new(new EmbeddedOrPhysicalFileProvider(context)); diff --git a/src/Elastic.Markdown/DocumentationGenerator.cs b/src/Elastic.Markdown/DocumentationGenerator.cs index e80af4519..3a9bd9eed 100644 --- a/src/Elastic.Markdown/DocumentationGenerator.cs +++ b/src/Elastic.Markdown/DocumentationGenerator.cs @@ -53,7 +53,7 @@ public class DocumentationGenerator public DocumentationGenerator( DocumentationSet docSet, - ILoggerFactory logger, + ILoggerFactory logFactory, INavigationHtmlWriter? navigationHtmlWriter = null, IDocumentationFileOutputProvider? documentationFileOutputProvider = null, IMarkdownExporter[]? markdownExporters = null, @@ -67,7 +67,7 @@ public DocumentationGenerator( _documentationFileOutputProvider = documentationFileOutputProvider; _conversionCollector = conversionCollector; _writeFileSystem = docSet.Context.WriteFileSystem; - _logger = logger.CreateLogger(nameof(DocumentationGenerator)); + _logger = logFactory.CreateLogger(nameof(DocumentationGenerator)); DocumentationSet = docSet; Context = docSet.Context; diff --git a/src/Elastic.Markdown/IO/DocumentationSet.cs b/src/Elastic.Markdown/IO/DocumentationSet.cs index 553c5cfdc..18929abde 100644 --- a/src/Elastic.Markdown/IO/DocumentationSet.cs +++ b/src/Elastic.Markdown/IO/DocumentationSet.cs @@ -134,7 +134,7 @@ public class DocumentationSet : INavigationLookups, IPositionalNavigation public DocumentationSet( BuildContext context, - ILoggerFactory logger, + ILoggerFactory logFactory, ICrossLinkResolver? linkResolver = null, TableOfContentsTreeCollector? treeCollector = null ) @@ -144,7 +144,7 @@ public DocumentationSet( SourceDirectory = context.DocumentationSourceDirectory; OutputDirectory = context.DocumentationOutputDirectory; LinkResolver = - linkResolver ?? new CrossLinkResolver(new ConfigurationCrossLinkFetcher(context.Configuration, Aws3LinkIndexReader.CreateAnonymous(), logger)); + linkResolver ?? new CrossLinkResolver(new ConfigurationCrossLinkFetcher(logFactory, context.Configuration, Aws3LinkIndexReader.CreateAnonymous())); Configuration = context.Configuration; EnabledExtensions = InstantiateExtensions(); treeCollector ??= new TableOfContentsTreeCollector(); diff --git a/src/Elastic.Markdown/Links/CrossLinks/ConfigurationCrossLinkFetcher.cs b/src/Elastic.Markdown/Links/CrossLinks/ConfigurationCrossLinkFetcher.cs index 20b3e9973..c3a64c228 100644 --- a/src/Elastic.Markdown/Links/CrossLinks/ConfigurationCrossLinkFetcher.cs +++ b/src/Elastic.Markdown/Links/CrossLinks/ConfigurationCrossLinkFetcher.cs @@ -10,7 +10,7 @@ namespace Elastic.Markdown.Links.CrossLinks; -public class ConfigurationCrossLinkFetcher(ConfigurationFile configuration, ILinkIndexReader linkIndexProvider, ILoggerFactory logger) : CrossLinkFetcher(linkIndexProvider, logger) +public class ConfigurationCrossLinkFetcher(ILoggerFactory logFactory, ConfigurationFile configuration, ILinkIndexReader linkIndexProvider) : CrossLinkFetcher(logFactory, linkIndexProvider) { public override async Task Fetch(Cancel ctx) { diff --git a/src/Elastic.Markdown/Links/CrossLinks/CrossLinkFetcher.cs b/src/Elastic.Markdown/Links/CrossLinks/CrossLinkFetcher.cs index 5afd44e7d..4392a6480 100644 --- a/src/Elastic.Markdown/Links/CrossLinks/CrossLinkFetcher.cs +++ b/src/Elastic.Markdown/Links/CrossLinks/CrossLinkFetcher.cs @@ -32,9 +32,9 @@ public record FetchedCrossLinks }; } -public abstract class CrossLinkFetcher(ILinkIndexReader linkIndexProvider, ILoggerFactory logger) : IDisposable +public abstract class CrossLinkFetcher(ILoggerFactory logFactory, ILinkIndexReader linkIndexProvider) : IDisposable { - private readonly ILogger _logger = logger.CreateLogger(nameof(CrossLinkFetcher)); + private readonly ILogger _logger = logFactory.CreateLogger(nameof(CrossLinkFetcher)); private readonly HttpClient _client = new(); private LinkRegistry? _linkIndex; @@ -151,7 +151,7 @@ private void WriteLinksJsonCachedFile(string repository, LinkRegistryEntry linkR public void Dispose() { _client.Dispose(); - logger.Dispose(); + logFactory.Dispose(); GC.SuppressFinalize(this); } } diff --git a/src/Elastic.Markdown/Links/InboundLinks/LinkIndexCrossLinkFetcher.cs b/src/Elastic.Markdown/Links/InboundLinks/LinkIndexCrossLinkFetcher.cs index 3812b9192..d6ee71686 100644 --- a/src/Elastic.Markdown/Links/InboundLinks/LinkIndexCrossLinkFetcher.cs +++ b/src/Elastic.Markdown/Links/InboundLinks/LinkIndexCrossLinkFetcher.cs @@ -10,7 +10,7 @@ namespace Elastic.Markdown.Links.InboundLinks; -public class LinksIndexCrossLinkFetcher(ILinkIndexReader linkIndexProvider, ILoggerFactory logger) : CrossLinkFetcher(linkIndexProvider, logger) +public class LinksIndexCrossLinkFetcher(ILoggerFactory logFactory, ILinkIndexReader linkIndexProvider) : CrossLinkFetcher(logFactory, linkIndexProvider) { public override async Task Fetch(Cancel ctx) { diff --git a/src/Elastic.Markdown/Links/InboundLinks/LinkIndexLinkChecker.cs b/src/Elastic.Markdown/Links/InboundLinks/LinkIndexLinkChecker.cs index b4d47f1a3..ae58eb07b 100644 --- a/src/Elastic.Markdown/Links/InboundLinks/LinkIndexLinkChecker.cs +++ b/src/Elastic.Markdown/Links/InboundLinks/LinkIndexLinkChecker.cs @@ -11,9 +11,9 @@ namespace Elastic.Markdown.Links.InboundLinks; -public class LinkIndexLinkChecker(ILoggerFactory logger) +public class LinkIndexLinkChecker(ILoggerFactory logFactory) { - private readonly ILogger _logger = logger.CreateLogger(); + private readonly ILogger _logger = logFactory.CreateLogger(); private readonly ILinkIndexReader _linkIndexProvider = Aws3LinkIndexReader.CreateAnonymous(); private sealed record RepositoryFilter { @@ -25,7 +25,7 @@ private sealed record RepositoryFilter public async Task CheckAll(IDiagnosticsCollector collector, Cancel ctx) { - var fetcher = new LinksIndexCrossLinkFetcher(_linkIndexProvider, logger); + var fetcher = new LinksIndexCrossLinkFetcher(logFactory, _linkIndexProvider); var resolver = new CrossLinkResolver(fetcher); var crossLinks = await resolver.FetchLinks(ctx); @@ -34,7 +34,7 @@ public async Task CheckAll(IDiagnosticsCollector collector, Cancel ctx) public async Task CheckRepository(IDiagnosticsCollector collector, string? toRepository, string? fromRepository, Cancel ctx) { - var fetcher = new LinksIndexCrossLinkFetcher(_linkIndexProvider, logger); + var fetcher = new LinksIndexCrossLinkFetcher(logFactory, _linkIndexProvider); var resolver = new CrossLinkResolver(fetcher); var crossLinks = await resolver.FetchLinks(ctx); var filter = new RepositoryFilter @@ -48,7 +48,7 @@ public async Task CheckRepository(IDiagnosticsCollector collector, string? toRep public async Task CheckWithLocalLinksJson(IDiagnosticsCollector collector, string repository, string localLinksJson, Cancel ctx) { - var fetcher = new LinksIndexCrossLinkFetcher(_linkIndexProvider, logger); + var fetcher = new LinksIndexCrossLinkFetcher(logFactory, _linkIndexProvider); var resolver = new CrossLinkResolver(fetcher); // ReSharper disable once RedundantAssignment var crossLinks = await resolver.FetchLinks(ctx); diff --git a/src/authoring/Elastic.Documentation.Refactor/Move.cs b/src/authoring/Elastic.Documentation.Refactor/Move.cs index 97fb0ad41..eb4b91c10 100644 --- a/src/authoring/Elastic.Documentation.Refactor/Move.cs +++ b/src/authoring/Elastic.Documentation.Refactor/Move.cs @@ -15,10 +15,10 @@ public record ChangeSet(IFileInfo From, IFileInfo To); public record Change(IFileInfo Source, string OriginalContent, string NewContent); public record LinkModification(string OldLink, string NewLink, string SourceFile, int LineNumber, int ColumnNumber); -public partial class Move(IFileSystem readFileSystem, IFileSystem writeFileSystem, DocumentationSet documentationSet, ILoggerFactory loggerFactory) +public partial class Move(ILoggerFactory logFactory, IFileSystem readFileSystem, IFileSystem writeFileSystem, DocumentationSet documentationSet) { - private readonly ILogger _logger = loggerFactory.CreateLogger(); + private readonly ILogger _logger = logFactory.CreateLogger(); private readonly Dictionary> _changes = []; private readonly Dictionary> _linkModifications = []; diff --git a/src/tooling/Elastic.Documentation.Tooling/Diagnostics/Console/ConsoleDiagnosticsCollector.cs b/src/tooling/Elastic.Documentation.Tooling/Diagnostics/Console/ConsoleDiagnosticsCollector.cs index a922a4c9d..8ef369479 100644 --- a/src/tooling/Elastic.Documentation.Tooling/Diagnostics/Console/ConsoleDiagnosticsCollector.cs +++ b/src/tooling/Elastic.Documentation.Tooling/Diagnostics/Console/ConsoleDiagnosticsCollector.cs @@ -10,8 +10,8 @@ namespace Elastic.Documentation.Tooling.Diagnostics.Console; -public class ConsoleDiagnosticsCollector(ILoggerFactory loggerFactory, ICoreService? githubActions = null) - : DiagnosticsCollector([new Log(loggerFactory.CreateLogger()), new GithubAnnotationOutput(githubActions)] +public class ConsoleDiagnosticsCollector(ILoggerFactory logFactory, ICoreService? githubActions = null) + : DiagnosticsCollector([new Log(logFactory.CreateLogger()), new GithubAnnotationOutput(githubActions)] ) { private readonly List _errors = []; diff --git a/src/tooling/docs-assembler/AssembleSources.cs b/src/tooling/docs-assembler/AssembleSources.cs index 9ffe0664d..344b841a3 100644 --- a/src/tooling/docs-assembler/AssembleSources.cs +++ b/src/tooling/docs-assembler/AssembleSources.cs @@ -51,26 +51,28 @@ public class AssembleSources public PublishEnvironmentUriResolver UriResolver { get; } - public static async Task AssembleAsync(ILoggerFactory logger, AssembleContext context, Checkout[] checkouts, VersionsConfiguration versionsConfiguration, Cancel ctx) + public static async Task AssembleAsync(ILoggerFactory logFactory, AssembleContext context, Checkout[] checkouts, VersionsConfiguration versionsConfiguration, Cancel ctx) { - var sources = new AssembleSources(logger, context, checkouts, versionsConfiguration); + var sources = new AssembleSources(logFactory, context, checkouts, versionsConfiguration); foreach (var (_, set) in sources.AssembleSets) await set.DocumentationSet.ResolveDirectoryTree(ctx); return sources; } - private AssembleSources(ILoggerFactory logger, AssembleContext assembleContext, Checkout[] checkouts, VersionsConfiguration versionsConfiguration) + private AssembleSources(ILoggerFactory logFactory, AssembleContext assembleContext, Checkout[] checkouts, VersionsConfiguration versionsConfiguration) { AssembleContext = assembleContext; NavigationTocMappings = GetTocMappings(assembleContext); HistoryMappings = GetHistoryMapping(assembleContext); var linkIndexProvider = Aws3LinkIndexReader.CreateAnonymous(); - var crossLinkFetcher = new AssemblerCrossLinkFetcher(logger, assembleContext.Configuration, assembleContext.Environment, linkIndexProvider); + + var crossLinkFetcher = new AssemblerCrossLinkFetcher(logFactory, assembleContext.Configuration, assembleContext.Environment, linkIndexProvider); UriResolver = new PublishEnvironmentUriResolver(NavigationTocMappings, assembleContext.Environment); + var crossLinkResolver = new CrossLinkResolver(crossLinkFetcher, UriResolver); AssembleSets = checkouts .Where(c => c.Repository is { Skip: false }) - .Select(c => new AssemblerDocumentationSet(logger, assembleContext, c, crossLinkResolver, TreeCollector, versionsConfiguration)) + .Select(c => new AssemblerDocumentationSet(logFactory, assembleContext, c, crossLinkResolver, TreeCollector, versionsConfiguration)) .ToDictionary(s => s.Checkout.Repository.Name, s => s) .ToFrozenDictionary(); diff --git a/src/tooling/docs-assembler/Building/AssemblerBuilder.cs b/src/tooling/docs-assembler/Building/AssemblerBuilder.cs index 393f89f65..6354e19fd 100644 --- a/src/tooling/docs-assembler/Building/AssemblerBuilder.cs +++ b/src/tooling/docs-assembler/Building/AssemblerBuilder.cs @@ -24,7 +24,7 @@ public enum ExportOption } public class AssemblerBuilder( - ILoggerFactory logger, + ILoggerFactory logFactory, AssembleContext context, GlobalNavigation navigation, GlobalNavigationHtmlWriter writer, @@ -32,7 +32,7 @@ public class AssemblerBuilder( ILegacyUrlMapper? legacyUrlMapper ) { - private readonly ILogger _logger = logger.CreateLogger(); + private readonly ILogger _logger = logFactory.CreateLogger(); private GlobalNavigationHtmlWriter HtmlWriter { get; } = writer; @@ -49,7 +49,7 @@ public async Task BuildAllAsync(FrozenDictionary(3); @@ -146,7 +146,7 @@ private async Task BuildAsync(AssemblerDocumentationSet set, b SetFeatureFlags(set); var generator = new DocumentationGenerator( set.DocumentationSet, - logger, HtmlWriter, + logFactory, HtmlWriter, pathProvider, legacyUrlMapper: LegacyUrlMapper, positionalNavigation: navigation, diff --git a/src/tooling/docs-assembler/Building/AssemblerCrossLinkFetcher.cs b/src/tooling/docs-assembler/Building/AssemblerCrossLinkFetcher.cs index 38c038654..e89d91dda 100644 --- a/src/tooling/docs-assembler/Building/AssemblerCrossLinkFetcher.cs +++ b/src/tooling/docs-assembler/Building/AssemblerCrossLinkFetcher.cs @@ -11,8 +11,8 @@ namespace Documentation.Assembler.Building; -public class AssemblerCrossLinkFetcher(ILoggerFactory logger, AssemblyConfiguration configuration, PublishEnvironment publishEnvironment, ILinkIndexReader linkIndexProvider) - : CrossLinkFetcher(linkIndexProvider, logger) +public class AssemblerCrossLinkFetcher(ILoggerFactory logFactory, AssemblyConfiguration configuration, PublishEnvironment publishEnvironment, ILinkIndexReader linkIndexProvider) + : CrossLinkFetcher(logFactory, linkIndexProvider) { public override async Task Fetch(Cancel ctx) { diff --git a/src/tooling/docs-assembler/Cli/ContentSourceCommands.cs b/src/tooling/docs-assembler/Cli/ContentSourceCommands.cs index 026bb7c78..b2e0ae9b0 100644 --- a/src/tooling/docs-assembler/Cli/ContentSourceCommands.cs +++ b/src/tooling/docs-assembler/Cli/ContentSourceCommands.cs @@ -2,7 +2,6 @@ // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information -using System.Diagnostics.CodeAnalysis; using System.IO.Abstractions; using Actions.Core.Services; using ConsoleAppFramework; @@ -16,18 +15,9 @@ namespace Documentation.Assembler.Cli; internal sealed class ContentSourceCommands(ICoreService githubActionsService, ILoggerFactory logFactory) { - [SuppressMessage("Usage", "CA2254:Template should be a static expression")] - private void AssignOutputLogger() - { - var log = logFactory.CreateLogger(); - ConsoleApp.Log = msg => log.LogInformation(msg); - ConsoleApp.LogError = msg => log.LogError(msg); - } - [Command("validate")] public async Task Validate(Cancel ctx = default) { - AssignOutputLogger(); await using var collector = new ConsoleDiagnosticsCollector(logFactory, githubActionsService) { NoHints = true @@ -80,7 +70,6 @@ public async Task Validate(Cancel ctx = default) [Command("match")] public async Task Match([Argument] string? repository = null, [Argument] string? branchOrTag = null, Cancel ctx = default) { - AssignOutputLogger(); var logger = logFactory.CreateLogger(); var repo = repository ?? githubActionsService.GetInput("repository"); diff --git a/src/tooling/docs-assembler/Cli/DeployCommands.cs b/src/tooling/docs-assembler/Cli/DeployCommands.cs index fcf96d817..335892c77 100644 --- a/src/tooling/docs-assembler/Cli/DeployCommands.cs +++ b/src/tooling/docs-assembler/Cli/DeployCommands.cs @@ -17,12 +17,12 @@ namespace Documentation.Assembler.Cli; -internal sealed class DeployCommands(ILoggerFactory logger, ICoreService githubActionsService) +internal sealed class DeployCommands(ILoggerFactory logFactory, ICoreService githubActionsService) { [SuppressMessage("Usage", "CA2254:Template should be a static expression")] private void AssignOutputLogger() { - var log = logger.CreateLogger(); + var log = logFactory.CreateLogger(); ConsoleApp.Log = msg => log.LogInformation(msg); ConsoleApp.LogError = msg => log.LogError(msg); } @@ -36,13 +36,13 @@ public async Task Plan( string environment, string s3BucketName, string @out = "", Cancel ctx = default) { AssignOutputLogger(); - await using var collector = new ConsoleDiagnosticsCollector(logger, githubActionsService) + await using var collector = new ConsoleDiagnosticsCollector(logFactory, githubActionsService) { NoHints = true }.StartAsync(ctx); var assembleContext = new AssembleContext(environment, collector, new FileSystem(), new FileSystem(), null, null); var s3Client = new AmazonS3Client(); - IDocsSyncPlanStrategy planner = new AwsS3SyncPlanStrategy(s3Client, s3BucketName, assembleContext, logger); + IDocsSyncPlanStrategy planner = new AwsS3SyncPlanStrategy(logFactory, s3Client, s3BucketName, assembleContext); var plan = await planner.Plan(ctx); ConsoleApp.Log("Total files to sync: " + plan.Count); ConsoleApp.Log("Total files to delete: " + plan.DeleteRequests.Count); @@ -73,7 +73,7 @@ public async Task Apply( Cancel ctx = default) { AssignOutputLogger(); - await using var collector = new ConsoleDiagnosticsCollector(logger, githubActionsService) + await using var collector = new ConsoleDiagnosticsCollector(logFactory, githubActionsService) { NoHints = true }.StartAsync(ctx); @@ -84,7 +84,7 @@ public async Task Apply( ConcurrentServiceRequests = Environment.ProcessorCount * 2, MinSizeBeforePartUpload = AwsS3SyncPlanStrategy.PartSize }); - IDocsSyncApplyStrategy applier = new AwsS3SyncApplyStrategy(s3Client, transferUtility, s3BucketName, assembleContext, logger, collector); + IDocsSyncApplyStrategy applier = new AwsS3SyncApplyStrategy(logFactory, s3Client, transferUtility, s3BucketName, assembleContext, collector); if (!File.Exists(planFile)) { collector.EmitError(planFile, "Plan file does not exist."); @@ -103,15 +103,13 @@ public async Task Apply( /// Path to the redirects mapping pre-generated by docs-assembler /// [Command("update-redirects")] - [ConsoleAppFilter] - [ConsoleAppFilter] public async Task UpdateRedirects( string environment, string redirectsFile = ".artifacts/assembly/redirects.json", Cancel ctx = default) { AssignOutputLogger(); - await using var collector = new ConsoleDiagnosticsCollector(logger, githubActionsService) + await using var collector = new ConsoleDiagnosticsCollector(logFactory, githubActionsService) { NoHints = true }.StartAsync(ctx); diff --git a/src/tooling/docs-assembler/Cli/InboundLinkCommands.cs b/src/tooling/docs-assembler/Cli/InboundLinkCommands.cs index 42857d8f9..e0f5c2841 100644 --- a/src/tooling/docs-assembler/Cli/InboundLinkCommands.cs +++ b/src/tooling/docs-assembler/Cli/InboundLinkCommands.cs @@ -14,25 +14,17 @@ namespace Documentation.Assembler.Cli; -internal sealed class InboundLinkCommands(ILoggerFactory logger, ICoreService githubActionsService) +internal sealed class InboundLinkCommands(ILoggerFactory logFactory, ICoreService githubActionsService) { - private readonly LinkIndexLinkChecker _linkIndexLinkChecker = new(logger); - private readonly ILogger _log = logger.CreateLogger(); - - [SuppressMessage("Usage", "CA2254:Template should be a static expression")] - private void AssignOutputLogger() - { - ConsoleApp.Log = msg => _log.LogInformation(msg); - ConsoleApp.LogError = msg => _log.LogError(msg); - } + private readonly LinkIndexLinkChecker _linkIndexLinkChecker = new(logFactory); + private readonly ILogger _log = logFactory.CreateLogger(); /// Validate all published cross_links in all published links.json files. /// [Command("validate-all")] public async Task ValidateAllInboundLinks(Cancel ctx = default) { - AssignOutputLogger(); - await using var collector = new ConsoleDiagnosticsCollector(logger, githubActionsService).StartAsync(ctx); + await using var collector = new ConsoleDiagnosticsCollector(logFactory, githubActionsService).StartAsync(ctx); await _linkIndexLinkChecker.CheckAll(collector, ctx); await collector.StopAsync(ctx); return collector.Errors; @@ -45,16 +37,15 @@ public async Task ValidateAllInboundLinks(Cancel ctx = default) [Command("validate")] public async Task ValidateRepoInboundLinks(string? from = null, string? to = null, Cancel ctx = default) { - AssignOutputLogger(); var fs = new FileSystem(); var root = fs.DirectoryInfo.New(Paths.WorkingDirectoryRoot.FullName); if (from == null && to == null) { - from ??= GitCheckoutInformation.Create(root, new FileSystem(), logger.CreateLogger(nameof(GitCheckoutInformation))).RepositoryName; + from ??= GitCheckoutInformation.Create(root, new FileSystem(), logFactory.CreateLogger(nameof(GitCheckoutInformation))).RepositoryName; if (from == null) throw new Exception("Unable to determine repository name"); } - await using var collector = new ConsoleDiagnosticsCollector(logger, githubActionsService).StartAsync(ctx); + await using var collector = new ConsoleDiagnosticsCollector(logFactory, githubActionsService).StartAsync(ctx); await _linkIndexLinkChecker.CheckRepository(collector, to, from, ctx); await collector.StopAsync(ctx); return collector.Errors; @@ -69,11 +60,10 @@ public async Task ValidateRepoInboundLinks(string? from = null, string? to [Command("validate-link-reference")] public async Task ValidateLocalLinkReference(string? file = null, string? path = null, Cancel ctx = default) { - AssignOutputLogger(); file ??= ".artifacts/docs/html/links.json"; var fs = new FileSystem(); var root = !string.IsNullOrEmpty(path) ? fs.DirectoryInfo.New(path) : fs.DirectoryInfo.New(Paths.WorkingDirectoryRoot.FullName); - var repository = GitCheckoutInformation.Create(root, fs, logger.CreateLogger(nameof(GitCheckoutInformation))).RepositoryName + var repository = GitCheckoutInformation.Create(root, fs, logFactory.CreateLogger(nameof(GitCheckoutInformation))).RepositoryName ?? throw new Exception("Unable to determine repository name"); var resolvedFile = fs.FileInfo.New(Path.Combine(root.FullName, file)); @@ -92,7 +82,7 @@ public async Task ValidateLocalLinkReference(string? file = null, string? p _log.LogInformation("Validating {File} in {Directory}", file, root.FullName); - await using var collector = new ConsoleDiagnosticsCollector(logger, githubActionsService).StartAsync(ctx); + await using var collector = new ConsoleDiagnosticsCollector(logFactory, githubActionsService).StartAsync(ctx); await _linkIndexLinkChecker.CheckWithLocalLinksJson(collector, repository, resolvedFile.FullName, ctx); await collector.StopAsync(ctx); return collector.Errors; diff --git a/src/tooling/docs-assembler/Cli/LegacyDocsCommands.cs b/src/tooling/docs-assembler/Cli/LegacyDocsCommands.cs index 928d184a0..bb1b155b5 100644 --- a/src/tooling/docs-assembler/Cli/LegacyDocsCommands.cs +++ b/src/tooling/docs-assembler/Cli/LegacyDocsCommands.cs @@ -12,9 +12,9 @@ namespace Documentation.Assembler.Cli; -internal sealed class LegacyDocsCommands(ILoggerFactory logger, ICoreService githubActionsService) +internal sealed class LegacyDocsCommands(ILoggerFactory logFactory, ICoreService githubActionsService) { - private readonly ILogger _log = logger.CreateLogger(); + private readonly ILogger _log = logFactory.CreateLogger(); [SuppressMessage("Usage", "CA2254:Template should be a static expression")] private void AssignOutputLogger() @@ -28,7 +28,7 @@ private void AssignOutputLogger() public async Task CreateBloomBin(string builtDocsDir, Cancel ctx = default) { AssignOutputLogger(); - await using var collector = new ConsoleDiagnosticsCollector(logger, githubActionsService) + await using var collector = new ConsoleDiagnosticsCollector(logFactory, githubActionsService) { NoHints = true }.StartAsync(ctx); @@ -44,7 +44,7 @@ public async Task CreateBloomBin(string builtDocsDir, Cancel ctx = default) public async Task PageExists(string path, Cancel ctx = default) { AssignOutputLogger(); - await using var collector = new ConsoleDiagnosticsCollector(logger, githubActionsService) + await using var collector = new ConsoleDiagnosticsCollector(logFactory, githubActionsService) { NoHints = true }.StartAsync(ctx); diff --git a/src/tooling/docs-assembler/Cli/NavigationCommands.cs b/src/tooling/docs-assembler/Cli/NavigationCommands.cs index a12ee91e6..115210d87 100644 --- a/src/tooling/docs-assembler/Cli/NavigationCommands.cs +++ b/src/tooling/docs-assembler/Cli/NavigationCommands.cs @@ -16,25 +16,14 @@ namespace Documentation.Assembler.Cli; -internal sealed class NavigationCommands(ILoggerFactory logger, ICoreService githubActionsService) +internal sealed class NavigationCommands(ILoggerFactory logFactory, ICoreService githubActionsService) { - [SuppressMessage("Usage", "CA2254:Template should be a static expression")] - private void AssignOutputLogger() - { - var log = logger.CreateLogger(); - ConsoleApp.Log = msg => log.LogInformation(msg); - ConsoleApp.LogError = msg => log.LogError(msg); - } - /// Validates navigation.yml does not contain colliding path prefixes /// [Command("validate")] - [ConsoleAppFilter] - [ConsoleAppFilter] public async Task Validate(Cancel ctx = default) { - AssignOutputLogger(); - await using var collector = new ConsoleDiagnosticsCollector(logger, githubActionsService).StartAsync(ctx); + await using var collector = new ConsoleDiagnosticsCollector(logFactory, githubActionsService).StartAsync(ctx); var assembleContext = new AssembleContext("dev", collector, new FileSystem(), new FileSystem(), null, null); // this validates all path prefixes are unique, early exit if duplicates are detected @@ -44,7 +33,7 @@ public async Task Validate(Cancel ctx = default) return 1; } - var namespaceChecker = new NavigationPrefixChecker(logger, assembleContext); + var namespaceChecker = new NavigationPrefixChecker(logFactory, assembleContext); await namespaceChecker.CheckAllPublishedLinks(assembleContext.Collector, ctx); @@ -56,23 +45,20 @@ public async Task Validate(Cancel ctx = default) /// Path to `links.json` defaults to '.artifacts/docs/html/links.json' /// [Command("validate-link-reference")] - [ConsoleAppFilter] - [ConsoleAppFilter] public async Task ValidateLocalLinkReference([Argument] string? file = null, Cancel ctx = default) { - AssignOutputLogger(); file ??= ".artifacts/docs/html/links.json"; - await using var collector = new ConsoleDiagnosticsCollector(logger, githubActionsService).StartAsync(ctx); + await using var collector = new ConsoleDiagnosticsCollector(logFactory, githubActionsService).StartAsync(ctx); var assembleContext = new AssembleContext("dev", collector, new FileSystem(), new FileSystem(), null, null); var fs = new FileSystem(); var root = fs.DirectoryInfo.New(Paths.WorkingDirectoryRoot.FullName); - var repository = GitCheckoutInformation.Create(root, new FileSystem(), logger.CreateLogger(nameof(GitCheckoutInformation))).RepositoryName + var repository = GitCheckoutInformation.Create(root, new FileSystem(), logFactory.CreateLogger(nameof(GitCheckoutInformation))).RepositoryName ?? throw new Exception("Unable to determine repository name"); - var namespaceChecker = new NavigationPrefixChecker(logger, assembleContext); + var namespaceChecker = new NavigationPrefixChecker(logFactory, assembleContext); await namespaceChecker.CheckWithLocalLinksJson(assembleContext.Collector, repository, file, ctx); diff --git a/src/tooling/docs-assembler/Cli/RepositoryCommands.cs b/src/tooling/docs-assembler/Cli/RepositoryCommands.cs index a94e734d2..c6c1b82a9 100644 --- a/src/tooling/docs-assembler/Cli/RepositoryCommands.cs +++ b/src/tooling/docs-assembler/Cli/RepositoryCommands.cs @@ -27,9 +27,9 @@ namespace Documentation.Assembler.Cli; -internal sealed class RepositoryCommands(ICoreService githubActionsService, ILoggerFactory logger, IOptions versionsConfigOption) +internal sealed class RepositoryCommands(ILoggerFactory logFactory, ICoreService githubActionsService, IOptions versionsConfigOption) { - private readonly ILogger _log = logger.CreateLogger(); + private readonly ILogger _log = logFactory.CreateLogger(); [SuppressMessage("Usage", "CA2254:Template should be a static expression")] private void AssignOutputLogger() @@ -55,10 +55,10 @@ public async Task CloneAll( var githubEnvironmentInput = githubActionsService.GetInput("environment"); environment ??= !string.IsNullOrEmpty(githubEnvironmentInput) ? githubEnvironmentInput : "dev"; - await using var collector = new ConsoleDiagnosticsCollector(logger, githubActionsService).StartAsync(ctx); + await using var collector = new ConsoleDiagnosticsCollector(logFactory, githubActionsService).StartAsync(ctx); var assembleContext = new AssembleContext(environment, collector, new FileSystem(), new FileSystem(), null, null); - var cloner = new AssemblerRepositorySourcer(logger, assembleContext); + var cloner = new AssemblerRepositorySourcer(logFactory, assembleContext); _ = await cloner.CloneAll(fetchLatest ?? false, ctx); @@ -93,7 +93,7 @@ public async Task BuildAll( _log.LogInformation("Building all repositories for environment {Environment}", environment); - await using var collector = new ConsoleDiagnosticsCollector(logger, githubActionsService) + await using var collector = new ConsoleDiagnosticsCollector(logFactory, githubActionsService) { NoHints = true }.StartAsync(ctx); @@ -115,7 +115,7 @@ public async Task BuildAll( } _log.LogInformation("Get all clone directory information"); - var cloner = new AssemblerRepositorySourcer(logger, assembleContext); + var cloner = new AssemblerRepositorySourcer(logFactory, assembleContext); var checkoutResult = cloner.GetAll(); var checkouts = checkoutResult.Checkouts.ToArray(); @@ -123,7 +123,7 @@ public async Task BuildAll( throw new Exception("No checkouts found"); _log.LogInformation("Preparing all assemble sources for build"); - var assembleSources = await AssembleSources.AssembleAsync(logger, assembleContext, checkouts, versionsConfigOption.Value, ctx); + var assembleSources = await AssembleSources.AssembleAsync(logFactory, assembleContext, checkouts, versionsConfigOption.Value, ctx); var navigationFile = new GlobalNavigationFile(assembleContext, assembleSources); _log.LogInformation("Create global navigation"); @@ -134,7 +134,7 @@ public async Task BuildAll( var legacyPageChecker = new LegacyPageChecker(); var historyMapper = new PageLegacyUrlMapper(legacyPageChecker, assembleSources.HistoryMappings); - var builder = new AssemblerBuilder(logger, assembleContext, navigation, htmlWriter, pathProvider, historyMapper); + var builder = new AssemblerBuilder(logFactory, assembleContext, navigation, htmlWriter, pathProvider, historyMapper); await builder.BuildAllAsync(assembleSources.AssembleSets, exporters, ctx); await cloner.WriteLinkRegistrySnapshot(checkoutResult.LinkRegistrySnapshot, ctx); @@ -158,11 +158,11 @@ public async Task BuildAll( [Command("update-all-link-reference")] public async Task UpdateLinkIndexAll(ContentSource contentSource, Cancel ctx = default) { - var collector = new ConsoleDiagnosticsCollector(logger, githubActionsService); + var collector = new ConsoleDiagnosticsCollector(logFactory, githubActionsService); // The environment ist not relevant here. // It's only used to get the list of repositories. var assembleContext = new AssembleContext("prod", collector, new FileSystem(), new FileSystem(), null, null); - var cloner = new RepositorySourcer(logger, assembleContext.CheckoutDirectory, new FileSystem(), collector); + var cloner = new RepositorySourcer(logFactory, assembleContext.CheckoutDirectory, new FileSystem(), collector); var repositories = new Dictionary(assembleContext.Configuration.ReferenceRepositories) { { NarrativeRepository.RepositoryName, assembleContext.Configuration.Narrative } @@ -186,8 +186,8 @@ await Parallel.ForEachAsync(repositories, checkout.Directory.FullName, outputPath ); - var set = new DocumentationSet(context, logger); - var generator = new DocumentationGenerator(set, logger, null, null, null, new NoopDocumentationFileExporter()); + var set = new DocumentationSet(context, logFactory); + var generator = new DocumentationGenerator(set, logFactory, null, null, null, new NoopDocumentationFileExporter()); _ = await generator.GenerateAll(c); IAmazonS3 s3Client = new AmazonS3Client(); diff --git a/src/tooling/docs-assembler/Deploying/AwsS3SyncApplyStrategy.cs b/src/tooling/docs-assembler/Deploying/AwsS3SyncApplyStrategy.cs index d3f3ff7d7..7464850ab 100644 --- a/src/tooling/docs-assembler/Deploying/AwsS3SyncApplyStrategy.cs +++ b/src/tooling/docs-assembler/Deploying/AwsS3SyncApplyStrategy.cs @@ -11,14 +11,14 @@ namespace Documentation.Assembler.Deploying; public class AwsS3SyncApplyStrategy( + ILoggerFactory logFactory, IAmazonS3 s3Client, ITransferUtility transferUtility, string bucketName, AssembleContext context, - ILoggerFactory loggerFactory, DiagnosticsCollector collector) : IDocsSyncApplyStrategy { - private readonly ILogger _logger = loggerFactory.CreateLogger(); + private readonly ILogger _logger = logFactory.CreateLogger(); private void DisplayProgress(object? sender, UploadDirectoryProgressArgs args) => LogProgress(_logger, args, null); diff --git a/src/tooling/docs-assembler/Deploying/AwsS3SyncPlanStrategy.cs b/src/tooling/docs-assembler/Deploying/AwsS3SyncPlanStrategy.cs index bfdf7025d..b8ea406ea 100644 --- a/src/tooling/docs-assembler/Deploying/AwsS3SyncPlanStrategy.cs +++ b/src/tooling/docs-assembler/Deploying/AwsS3SyncPlanStrategy.cs @@ -11,10 +11,10 @@ namespace Documentation.Assembler.Deploying; -public class AwsS3SyncPlanStrategy(IAmazonS3 s3Client, string bucketName, AssembleContext context, ILoggerFactory loggerFactory) : IDocsSyncPlanStrategy +public class AwsS3SyncPlanStrategy(ILoggerFactory logFactory, IAmazonS3 s3Client, string bucketName, AssembleContext context) : IDocsSyncPlanStrategy { internal const long PartSize = 5 * 1024 * 1024; // 5MB - private readonly ILogger _logger = loggerFactory.CreateLogger(); + private readonly ILogger _logger = logFactory.CreateLogger(); private static readonly ConcurrentDictionary EtagCache = new(); private bool IsSymlink(string path) diff --git a/src/tooling/docs-assembler/Links/NavigationPrefixChecker.cs b/src/tooling/docs-assembler/Links/NavigationPrefixChecker.cs index f66128d0f..36cd94fce 100644 --- a/src/tooling/docs-assembler/Links/NavigationPrefixChecker.cs +++ b/src/tooling/docs-assembler/Links/NavigationPrefixChecker.cs @@ -34,12 +34,12 @@ public class NavigationPrefixChecker { private readonly ILogger _logger; private readonly PublishEnvironmentUriResolver _uriResolver; - private readonly ILoggerFactory _loggerFactory; + private readonly ILoggerFactory _logFactoryFactory; private readonly ImmutableHashSet _repositories; private readonly ImmutableHashSet _phantoms; /// - public NavigationPrefixChecker(ILoggerFactory logger, AssembleContext context) + public NavigationPrefixChecker(ILoggerFactory logFactory, AssembleContext context) { _phantoms = GlobalNavigationFile.GetPhantomPrefixes(context); @@ -50,8 +50,8 @@ public NavigationPrefixChecker(ILoggerFactory logger, AssembleContext context) .Select(r => r.Name) .ToImmutableHashSet(); - _logger = logger.CreateLogger(); - _loggerFactory = logger; + _logger = logFactory.CreateLogger(); + _logFactoryFactory = logFactory; var tocTopLevelMappings = AssembleSources.GetTocMappings(context); _uriResolver = new PublishEnvironmentUriResolver(tocTopLevelMappings, context.Environment); @@ -85,7 +85,7 @@ public async Task CheckAllPublishedLinks(DiagnosticsCollector collector, Cancel private async Task FetchAndValidateCrossLinks(DiagnosticsCollector collector, string? updateRepository, RepositoryLinks? updateReference, Cancel ctx) { var linkIndexProvider = Aws3LinkIndexReader.CreateAnonymous(); - var fetcher = new LinksIndexCrossLinkFetcher(linkIndexProvider, _loggerFactory); + var fetcher = new LinksIndexCrossLinkFetcher(_logFactoryFactory, linkIndexProvider); var resolver = new CrossLinkResolver(fetcher); var crossLinks = await resolver.FetchLinks(ctx); var dictionary = new Dictionary(); diff --git a/src/tooling/docs-assembler/Navigation/AssemblerDocumentationSet.cs b/src/tooling/docs-assembler/Navigation/AssemblerDocumentationSet.cs index 723a5d2c2..a68073a31 100644 --- a/src/tooling/docs-assembler/Navigation/AssemblerDocumentationSet.cs +++ b/src/tooling/docs-assembler/Navigation/AssemblerDocumentationSet.cs @@ -25,7 +25,7 @@ public record AssemblerDocumentationSet public DocumentationSet DocumentationSet { get; } public AssemblerDocumentationSet( - ILoggerFactory logger, + ILoggerFactory logFactory, AssembleContext context, Checkout checkout, CrossLinkResolver crossLinkResolver, @@ -76,6 +76,6 @@ public AssemblerDocumentationSet( }; BuildContext = buildContext; - DocumentationSet = new DocumentationSet(buildContext, logger, crossLinkResolver, treeCollector); + DocumentationSet = new DocumentationSet(buildContext, logFactory, crossLinkResolver, treeCollector); } } diff --git a/src/tooling/docs-assembler/Program.cs b/src/tooling/docs-assembler/Program.cs index cdaab2a22..7f05b496e 100644 --- a/src/tooling/docs-assembler/Program.cs +++ b/src/tooling/docs-assembler/Program.cs @@ -2,6 +2,7 @@ // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information +using System.Diagnostics.CodeAnalysis; using Actions.Core.Services; using ConsoleAppFramework; using Documentation.Assembler.Cli; @@ -9,16 +10,17 @@ using Elastic.Documentation.Tooling; using Elastic.Documentation.Tooling.Filters; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; await using var serviceProvider = DocumentationTooling.CreateServiceProvider(ref args, services => services .AddSingleton() .AddSingleton() ); - ConsoleApp.ServiceProvider = serviceProvider; var app = ConsoleApp.Create(); +app.UseFilter(); app.UseFilter(); app.UseFilter(); @@ -35,3 +37,16 @@ args = command.Split(' '); await app.RunAsync(args); + +internal sealed class ReplaceLogFilter(ConsoleAppFilter next, ILogger logger) + : ConsoleAppFilter(next) +{ + [SuppressMessage("Usage", "CA2254:Template should be a static expression")] + public override Task InvokeAsync(ConsoleAppContext context, Cancel cancellationToken) + { + ConsoleApp.Log = msg => logger.LogInformation(msg); + ConsoleApp.LogError = msg => logger.LogError(msg); + + return Next.InvokeAsync(context, cancellationToken); + } +} diff --git a/src/tooling/docs-assembler/Sourcing/RepositorySourcesFetcher.cs b/src/tooling/docs-assembler/Sourcing/RepositorySourcesFetcher.cs index 33d4aa322..9dc3949f2 100644 --- a/src/tooling/docs-assembler/Sourcing/RepositorySourcesFetcher.cs +++ b/src/tooling/docs-assembler/Sourcing/RepositorySourcesFetcher.cs @@ -13,14 +13,14 @@ namespace Documentation.Assembler.Sourcing; -public class AssemblerRepositorySourcer(ILoggerFactory logger, AssembleContext context) +public class AssemblerRepositorySourcer(ILoggerFactory logFactory, AssembleContext context) { - private readonly ILogger _logger = logger.CreateLogger(); + private readonly ILogger _logger = logFactory.CreateLogger(); private AssemblyConfiguration Configuration => context.Configuration; private PublishEnvironment PublishEnvironment => context.Environment; - private RepositorySourcer RepositorySourcer => new(logger, context.CheckoutDirectory, context.ReadFileSystem, context.Collector); + private RepositorySourcer RepositorySourcer => new(logFactory, context.CheckoutDirectory, context.ReadFileSystem, context.Collector); public CheckoutResult GetAll() { @@ -121,9 +121,9 @@ public async Task WriteLinkRegistrySnapshot(LinkRegistry linkRegistrySnapshot, C } -public class RepositorySourcer(ILoggerFactory logger, IDirectoryInfo checkoutDirectory, IFileSystem readFileSystem, DiagnosticsCollector collector) +public class RepositorySourcer(ILoggerFactory logFactory, IDirectoryInfo checkoutDirectory, IFileSystem readFileSystem, DiagnosticsCollector collector) { - private readonly ILogger _logger = logger.CreateLogger(); + private readonly ILogger _logger = logFactory.CreateLogger(); // // Clones the repository to the checkout directory and checks out the specified git reference. diff --git a/src/tooling/docs-builder/Cli/Commands.cs b/src/tooling/docs-builder/Cli/Commands.cs index 178ebb22a..c14ededc6 100644 --- a/src/tooling/docs-builder/Cli/Commands.cs +++ b/src/tooling/docs-builder/Cli/Commands.cs @@ -2,7 +2,6 @@ // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information -using System.Diagnostics.CodeAnalysis; using System.IO.Abstractions; using System.IO.Abstractions.TestingHelpers; using Actions.Core.Services; @@ -13,7 +12,6 @@ using Elastic.Documentation.Configuration.Versions; using Elastic.Documentation.Refactor; using Elastic.Documentation.Tooling.Diagnostics.Console; -using Elastic.Documentation.Tooling.Filters; using Elastic.Markdown; using Elastic.Markdown.Exporters; using Elastic.Markdown.IO; @@ -22,16 +20,9 @@ namespace Documentation.Builder.Cli; -internal sealed class Commands(ILoggerFactory logger, ICoreService githubActionsService, IOptions versionsConfigOption) +internal sealed class Commands(ILoggerFactory logFactory, ICoreService githubActionsService, IOptions versionsConfigOption) { - private readonly ILogger _log = logger.CreateLogger(); - - [SuppressMessage("Usage", "CA2254:Template should be a static expression")] - private void AssignOutputLogger() - { - ConsoleApp.Log = msg => _log.LogInformation(msg); - ConsoleApp.LogError = msg => _log.LogError(msg); - } + private readonly ILogger _log = logFactory.CreateLogger(); /// /// Continuously serve a documentation folder at http://localhost:3000. @@ -43,11 +34,9 @@ private void AssignOutputLogger() /// Port to serve the documentation. /// [Command("serve")] - [ConsoleAppFilter] public async Task Serve(string? path = null, int port = 3000, Cancel ctx = default) { - AssignOutputLogger(); - var host = new DocumentationWebHost(path, port, logger, new FileSystem(), new MockFileSystem(), versionsConfigOption.Value); + var host = new DocumentationWebHost(logFactory, path, port, new FileSystem(), new MockFileSystem(), versionsConfigOption.Value); _log.LogInformation("Find your documentation at http://localhost:{Port}/{Path}", port, host.GeneratorState.Generator.DocumentationSet.FirstInterestingUrl.TrimStart('/') ); @@ -56,22 +45,20 @@ public async Task Serve(string? path = null, int port = 3000, Cancel ctx = defau } /// - /// Serve html files directly + /// Serve HTML files directly /// /// Port to serve the documentation. /// [Command("serve-static")] - [ConsoleAppFilter] public async Task ServeStatic(int port = 4000, Cancel ctx = default) { - AssignOutputLogger(); var host = new StaticWebHost(port); await host.RunAsync(ctx); await host.StopAsync(ctx); } /// - /// Converts a source markdown folder or file to an output folder + /// Converts a source Markdown folder or file to an output folder /// global options: /// --log-level level /// @@ -80,14 +67,11 @@ public async Task ServeStatic(int port = 4000, Cancel ctx = default) /// Specifies the path prefix for urls /// Force a full rebuild of the destination folder /// Treat warnings as errors and fail the build on warnings - /// Allow indexing and following of html files + /// Allow indexing and following of HTML files /// Only emit documentation metadata to output /// The base URL for the canonical url tag /// [Command("generate")] - [ConsoleAppFilter] - [ConsoleAppFilter] - [ConsoleAppFilter] public async Task Generate( string? path = null, string? output = null, @@ -100,10 +84,9 @@ public async Task Generate( Cancel ctx = default ) { - AssignOutputLogger(); pathPrefix ??= githubActionsService.GetInput("prefix"); var fileSystem = new FileSystem(); - await using var collector = new ConsoleDiagnosticsCollector(logger, githubActionsService).StartAsync(ctx); + await using var collector = new ConsoleDiagnosticsCollector(logFactory, githubActionsService).StartAsync(ctx); var runningOnCi = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("GITHUB_ACTIONS")); BuildContext context; @@ -139,7 +122,7 @@ public async Task Generate( var outputDirectory = !string.IsNullOrWhiteSpace(output) ? fileSystem.DirectoryInfo.New(output) : fileSystem.DirectoryInfo.New(Path.Combine(Paths.WorkingDirectoryRoot.FullName, ".artifacts/docs/html")); - // we temporarily do not error when pointed to a non documentation folder. + // we temporarily do not error when pointed to a non-documentation folder. _ = fileSystem.Directory.CreateDirectory(outputDirectory.FullName); ConsoleApp.Log($"Skipping build as we are running on a merge commit and the docs folder is out of date and has no docset.yml. {e.Message}"); @@ -152,7 +135,7 @@ public async Task Generate( await githubActionsService.SetOutputAsync("skip", "false"); // always delete output folder on CI - var set = new DocumentationSet(context, logger); + var set = new DocumentationSet(context, logFactory); if (runningOnCi) set.ClearOutputDirectory(); @@ -161,11 +144,11 @@ public async Task Generate( metadataOnly ??= metaValue; var exporter = metadataOnly.HasValue && metadataOnly.Value ? new NoopDocumentationFileExporter() : null; - var generator = new DocumentationGenerator(set, logger, null, null, null, exporter); + var generator = new DocumentationGenerator(set, logFactory, null, null, null, exporter); _ = await generator.GenerateAll(ctx); - var openApiGenerator = new OpenApiGenerator(context, generator.MarkdownStringRenderer, logger); + var openApiGenerator = new OpenApiGenerator(logFactory, context, generator.MarkdownStringRenderer); await openApiGenerator.Generate(ctx); if (runningOnCi) @@ -180,21 +163,18 @@ public async Task Generate( } /// - /// Converts a source markdown folder or file to an output folder + /// Converts a source Markdown folder or file to an output folder /// /// -p, Defaults to the`{pwd}/docs` folder /// -o, Defaults to `.artifacts/html` /// Specifies the path prefix for urls /// Force a full rebuild of the destination folder /// Treat warnings as errors and fail the build on warnings - /// Allow indexing and following of html files + /// Allow indexing and following of HTML files /// Only emit documentation metadata to output /// The base URL for the canonical url tag /// [Command("")] - [ConsoleAppFilter] - [ConsoleAppFilter] - [ConsoleAppFilter] public async Task GenerateDefault( string? path = null, string? output = null, @@ -218,9 +198,6 @@ public async Task GenerateDefault( /// Dry run the move operation /// [Command("mv")] - [ConsoleAppFilter] - [ConsoleAppFilter] - [ConsoleAppFilter] public async Task Move( [Argument] string source, [Argument] string target, @@ -229,13 +206,12 @@ public async Task Move( Cancel ctx = default ) { - AssignOutputLogger(); var fileSystem = new FileSystem(); - await using var collector = new ConsoleDiagnosticsCollector(logger, null).StartAsync(ctx); + await using var collector = new ConsoleDiagnosticsCollector(logFactory, null).StartAsync(ctx); var context = new BuildContext(collector, fileSystem, fileSystem, versionsConfigOption.Value, path, null); - var set = new DocumentationSet(context, logger); + var set = new DocumentationSet(context, logFactory); - var moveCommand = new Move(fileSystem, fileSystem, set, logger); + var moveCommand = new Move(logFactory, fileSystem, fileSystem, set); var result = await moveCommand.Execute(source, target, dryRun ?? false, ctx); await collector.StopAsync(ctx); return result; diff --git a/src/tooling/docs-builder/Cli/DiffCommands.cs b/src/tooling/docs-builder/Cli/DiffCommands.cs index 618f4fb32..a32812857 100644 --- a/src/tooling/docs-builder/Cli/DiffCommands.cs +++ b/src/tooling/docs-builder/Cli/DiffCommands.cs @@ -11,32 +11,25 @@ using Elastic.Documentation.Configuration.Builder; using Elastic.Documentation.Configuration.Versions; using Elastic.Documentation.Tooling.Diagnostics.Console; -using Elastic.Documentation.Tooling.Filters; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace Documentation.Builder.Cli; -internal sealed class DiffCommands(ILoggerFactory logger, ICoreService githubActionsService, IOptions versionsConfigOption) +internal sealed class DiffCommands(ILoggerFactory logFactory, ICoreService githubActionsService, IOptions versionsConfigOption) { /// - /// Validates redirect updates in the current branch using the redirects file against changes reported by git. + /// Validates redirect updates in the current branch using the redirect file against changes reported by git. /// /// The baseline path to perform the check /// [SuppressMessage("Usage", "CA2254:Template should be a static expression")] [Command("validate")] - [ConsoleAppFilter] - [ConsoleAppFilter] public async Task ValidateRedirects([Argument] string? path = null, Cancel ctx = default) { - var log = logger.CreateLogger(); - ConsoleApp.Log = msg => log.LogInformation(msg); - ConsoleApp.LogError = msg => log.LogError(msg); - path ??= "docs"; - await using var collector = new ConsoleDiagnosticsCollector(logger, githubActionsService).StartAsync(ctx); + await using var collector = new ConsoleDiagnosticsCollector(logFactory, githubActionsService).StartAsync(ctx); var fs = new FileSystem(); var root = fs.DirectoryInfo.New(Paths.WorkingDirectoryRoot.FullName); diff --git a/src/tooling/docs-builder/Cli/InboundLinkCommands.cs b/src/tooling/docs-builder/Cli/InboundLinkCommands.cs index 7da8ecda2..7cc0fe9e2 100644 --- a/src/tooling/docs-builder/Cli/InboundLinkCommands.cs +++ b/src/tooling/docs-builder/Cli/InboundLinkCommands.cs @@ -15,27 +15,17 @@ namespace Documentation.Builder.Cli; -internal sealed class InboundLinkCommands(ILoggerFactory logger, ICoreService githubActionsService) +internal sealed class InboundLinkCommands(ILoggerFactory logFactory, ICoreService githubActionsService) { - private readonly LinkIndexLinkChecker _linkIndexLinkChecker = new(logger); - private readonly ILogger _log = logger.CreateLogger(); - - [SuppressMessage("Usage", "CA2254:Template should be a static expression")] - private void AssignOutputLogger() - { - ConsoleApp.Log = msg => _log.LogInformation(msg); - ConsoleApp.LogError = msg => _log.LogError(msg); - } + private readonly LinkIndexLinkChecker _linkIndexLinkChecker = new(logFactory); + private readonly ILogger _log = logFactory.CreateLogger(); /// Validate all published cross_links in all published links.json files. /// [Command("validate-all")] - [ConsoleAppFilter] - [ConsoleAppFilter] public async Task ValidateAllInboundLinks(Cancel ctx = default) { - AssignOutputLogger(); - await using var collector = new ConsoleDiagnosticsCollector(logger, githubActionsService).StartAsync(ctx); + await using var collector = new ConsoleDiagnosticsCollector(logFactory, githubActionsService).StartAsync(ctx); await _linkIndexLinkChecker.CheckAll(collector, ctx); await collector.StopAsync(ctx); return collector.Errors; @@ -46,20 +36,17 @@ public async Task ValidateAllInboundLinks(Cancel ctx = default) /// Outbound links 'to' repository form others /// [Command("validate")] - [ConsoleAppFilter] - [ConsoleAppFilter] public async Task ValidateRepoInboundLinks(string? from = null, string? to = null, Cancel ctx = default) { - AssignOutputLogger(); var fs = new FileSystem(); var root = fs.DirectoryInfo.New(Paths.WorkingDirectoryRoot.FullName); if (from == null && to == null) { - from ??= GitCheckoutInformation.Create(root, new FileSystem(), logger.CreateLogger(nameof(GitCheckoutInformation))).RepositoryName; + from ??= GitCheckoutInformation.Create(root, new FileSystem(), logFactory.CreateLogger(nameof(GitCheckoutInformation))).RepositoryName; if (from == null) throw new Exception("Unable to determine repository name"); } - await using var collector = new ConsoleDiagnosticsCollector(logger, githubActionsService).StartAsync(ctx); + await using var collector = new ConsoleDiagnosticsCollector(logFactory, githubActionsService).StartAsync(ctx); await _linkIndexLinkChecker.CheckRepository(collector, to, from, ctx); await collector.StopAsync(ctx); return collector.Errors; @@ -72,15 +59,12 @@ public async Task ValidateRepoInboundLinks(string? from = null, string? to /// -p, Defaults to the `{pwd}` folder /// [Command("validate-link-reference")] - [ConsoleAppFilter] - [ConsoleAppFilter] public async Task ValidateLocalLinkReference(string? file = null, string? path = null, Cancel ctx = default) { - AssignOutputLogger(); file ??= ".artifacts/docs/html/links.json"; var fs = new FileSystem(); var root = !string.IsNullOrEmpty(path) ? fs.DirectoryInfo.New(path) : fs.DirectoryInfo.New(Paths.WorkingDirectoryRoot.FullName); - var repository = GitCheckoutInformation.Create(root, new FileSystem(), logger.CreateLogger(nameof(GitCheckoutInformation))).RepositoryName + var repository = GitCheckoutInformation.Create(root, new FileSystem(), logFactory.CreateLogger(nameof(GitCheckoutInformation))).RepositoryName ?? throw new Exception("Unable to determine repository name"); var resolvedFile = fs.FileInfo.New(Path.Combine(root.FullName, file)); @@ -99,7 +83,7 @@ public async Task ValidateLocalLinkReference(string? file = null, string? p _log.LogInformation("Validating {File} in {Directory}", file, root.FullName); - await using var collector = new ConsoleDiagnosticsCollector(logger, githubActionsService).StartAsync(ctx); + await using var collector = new ConsoleDiagnosticsCollector(logFactory, githubActionsService).StartAsync(ctx); await _linkIndexLinkChecker.CheckWithLocalLinksJson(collector, repository, resolvedFile.FullName, ctx); await collector.StopAsync(ctx); return collector.Errors; diff --git a/src/tooling/docs-builder/Diagnostics/LiveMode/LiveModeDiagnosticsCollector.cs b/src/tooling/docs-builder/Diagnostics/LiveMode/LiveModeDiagnosticsCollector.cs index 0ae7209ea..20efc3d49 100644 --- a/src/tooling/docs-builder/Diagnostics/LiveMode/LiveModeDiagnosticsCollector.cs +++ b/src/tooling/docs-builder/Diagnostics/LiveMode/LiveModeDiagnosticsCollector.cs @@ -9,8 +9,8 @@ namespace Documentation.Builder.Diagnostics.LiveMode; -public class LiveModeDiagnosticsCollector(ILoggerFactory loggerFactory) - : DiagnosticsCollector([new Log(loggerFactory.CreateLogger())]) +public class LiveModeDiagnosticsCollector(ILoggerFactory logFactory) + : DiagnosticsCollector([new Log(logFactory.CreateLogger())]) { protected override void HandleItem(Diagnostic diagnostic) { } diff --git a/src/tooling/docs-builder/Http/DocumentationWebHost.cs b/src/tooling/docs-builder/Http/DocumentationWebHost.cs index cbd856b70..60cf0bfb5 100644 --- a/src/tooling/docs-builder/Http/DocumentationWebHost.cs +++ b/src/tooling/docs-builder/Http/DocumentationWebHost.cs @@ -28,7 +28,8 @@ public class DocumentationWebHost private readonly IHostedService _hostedService; private readonly IFileSystem _writeFileSystem; - public DocumentationWebHost(string? path, int port, ILoggerFactory logger, IFileSystem readFs, IFileSystem writeFs, VersionsConfiguration versionsConfig) + public DocumentationWebHost(ILoggerFactory logFactory, string? path, int port, IFileSystem readFs, IFileSystem writeFs, + VersionsConfiguration versionsConfig) { _writeFileSystem = writeFs; var builder = WebApplication.CreateSlimBuilder(); @@ -39,7 +40,7 @@ public DocumentationWebHost(string? path, int port, ILoggerFactory logger, IFile .AddFilter("Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware", LogLevel.Error) .AddFilter("Microsoft.Hosting.Lifetime", LogLevel.Information); - var collector = new LiveModeDiagnosticsCollector(logger); + var collector = new LiveModeDiagnosticsCollector(logFactory); var hostUrl = $"http://localhost:{port}"; @@ -48,7 +49,7 @@ public DocumentationWebHost(string? path, int port, ILoggerFactory logger, IFile { CanonicalBaseUrl = new Uri(hostUrl), }; - GeneratorState = new ReloadableGeneratorState(Context.DocumentationSourceDirectory, Context.DocumentationOutputDirectory, Context, logger); + GeneratorState = new ReloadableGeneratorState(logFactory, Context.DocumentationSourceDirectory, Context.DocumentationOutputDirectory, Context); _ = builder.Services .AddAotLiveReload(s => { diff --git a/src/tooling/docs-builder/Http/ReloadableGeneratorState.cs b/src/tooling/docs-builder/Http/ReloadableGeneratorState.cs index 971cf6979..e265555c1 100644 --- a/src/tooling/docs-builder/Http/ReloadableGeneratorState.cs +++ b/src/tooling/docs-builder/Http/ReloadableGeneratorState.cs @@ -12,28 +12,27 @@ namespace Documentation.Builder.Http; -/// Singleton behaviour enforced by registration on +/// Singleton behavior enforced by registration on public class ReloadableGeneratorState( + ILoggerFactory logFactory, IDirectoryInfo sourcePath, IDirectoryInfo outputPath, - BuildContext context, - ILoggerFactory logger -) + BuildContext context) { private IDirectoryInfo SourcePath { get; } = sourcePath; private IDirectoryInfo OutputPath { get; } = outputPath; public IDirectoryInfo ApiPath { get; } = context.WriteFileSystem.DirectoryInfo.New(Path.Combine(outputPath.FullName, "api")); - private DocumentationGenerator _generator = new(new DocumentationSet(context, logger), logger); + private DocumentationGenerator _generator = new(new DocumentationSet(context, logFactory), logFactory); public DocumentationGenerator Generator => _generator; public async Task ReloadAsync(Cancel ctx) { SourcePath.Refresh(); OutputPath.Refresh(); - var docSet = new DocumentationSet(context, logger); + var docSet = new DocumentationSet(context, logFactory); _ = await docSet.LinkResolver.FetchLinks(ctx); - var generator = new DocumentationGenerator(docSet, logger); + var generator = new DocumentationGenerator(docSet, logFactory); await generator.ResolveDirectoryTree(ctx); _ = Interlocked.Exchange(ref _generator, generator); @@ -45,7 +44,7 @@ private async Task ReloadApiReferences(IMarkdownStringRenderer markdownStringRen if (ApiPath.Exists) ApiPath.Delete(true); ApiPath.Create(); - var generator = new OpenApiGenerator(context, markdownStringRenderer, logger); + var generator = new OpenApiGenerator(logFactory, context, markdownStringRenderer); await generator.Generate(ctx); } } diff --git a/src/tooling/docs-builder/Program.cs b/src/tooling/docs-builder/Program.cs index 15a0bbfb3..62c18079f 100644 --- a/src/tooling/docs-builder/Program.cs +++ b/src/tooling/docs-builder/Program.cs @@ -2,21 +2,39 @@ // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information +using System.Diagnostics.CodeAnalysis; using ConsoleAppFramework; using Documentation.Builder.Cli; -using Elastic.Documentation.Diagnostics; using Elastic.Documentation.Tooling; -using Microsoft.Extensions.DependencyInjection; +using Elastic.Documentation.Tooling.Filters; +using Microsoft.Extensions.Logging; -await using var serviceProvider = DocumentationTooling.CreateServiceProvider(ref args, services => services - .AddSingleton() - .AddSingleton() -); +await using var serviceProvider = DocumentationTooling.CreateServiceProvider(ref args, _ => { }); ConsoleApp.ServiceProvider = serviceProvider; var app = ConsoleApp.Create(); + +app.UseFilter(); +app.UseFilter(); +app.UseFilter(); +app.UseFilter(); + app.Add(); app.Add("inbound-links"); app.Add("diff"); await app.RunAsync(args).ConfigureAwait(false); + + +internal sealed class ReplaceLogFilter(ConsoleAppFilter next, ILogger logger) + : ConsoleAppFilter(next) +{ + [SuppressMessage("Usage", "CA2254:Template should be a static expression")] + public override Task InvokeAsync(ConsoleAppContext context, Cancel cancellationToken) + { + ConsoleApp.Log = msg => logger.LogInformation(msg); + ConsoleApp.LogError = msg => logger.LogError(msg); + + return Next.InvokeAsync(context, cancellationToken); + } +} diff --git a/tests/Elastic.ApiExplorer.Tests/ReaderTests.cs b/tests/Elastic.ApiExplorer.Tests/ReaderTests.cs index f9c734b12..ea9858d3a 100644 --- a/tests/Elastic.ApiExplorer.Tests/ReaderTests.cs +++ b/tests/Elastic.ApiExplorer.Tests/ReaderTests.cs @@ -62,7 +62,7 @@ public async Task Navigation() }; var collector = new DiagnosticsCollector([]); var context = new BuildContext(collector, new FileSystem(), versionsConfig); - var generator = new OpenApiGenerator(context, NoopMarkdownStringRenderer.Instance, NullLoggerFactory.Instance); + var generator = new OpenApiGenerator(NullLoggerFactory.Instance, context, NoopMarkdownStringRenderer.Instance); context.Configuration.OpenApiSpecification.Should().NotBeNull(); var openApiDocument = await OpenApiReader.Create(context.Configuration.OpenApiSpecification); diff --git a/tests/Elastic.Markdown.Tests/Mover/MoverTests.cs b/tests/Elastic.Markdown.Tests/Mover/MoverTests.cs index cc8711e12..e696a8e18 100644 --- a/tests/Elastic.Markdown.Tests/Mover/MoverTests.cs +++ b/tests/Elastic.Markdown.Tests/Mover/MoverTests.cs @@ -18,7 +18,7 @@ public async Task RelativeLinks() var workingDirectory = Set.Configuration.SourceFile.DirectoryName; Directory.SetCurrentDirectory(workingDirectory!); - var mover = new Move(ReadFileSystem, WriteFileSystem, Set, LoggerFactory); + var mover = new Move(LoggerFactory, ReadFileSystem, WriteFileSystem, Set); await mover.Execute("testing/mover/first-page.md", "new-folder/hello-world.md", true, TestContext.Current.CancellationToken); mover.Changes.Should().HaveCount(1); @@ -47,7 +47,7 @@ public async Task MoveToFolder() var workingDirectory = Set.Configuration.SourceFile.DirectoryName; Directory.SetCurrentDirectory(workingDirectory!); - var mover = new Move(ReadFileSystem, WriteFileSystem, Set, LoggerFactory); + var mover = new Move(LoggerFactory, ReadFileSystem, WriteFileSystem, Set); await mover.Execute("testing/mover/first-page.md", "new-folder", true, TestContext.Current.CancellationToken); mover.Changes.Should().HaveCount(1); @@ -75,7 +75,7 @@ public async Task MoveFolderToFolder() var workingDirectory = Set.Configuration.SourceFile.DirectoryName; Directory.SetCurrentDirectory(workingDirectory!); - var mover = new Move(ReadFileSystem, WriteFileSystem, Set, LoggerFactory); + var mover = new Move(LoggerFactory, ReadFileSystem, WriteFileSystem, Set); await mover.Execute("testing/mover", "new-folder", true, TestContext.Current.CancellationToken); mover.Changes.Should().HaveCount(2); diff --git a/tests/docs-assembler.Tests/src/docs-assembler.Tests/DocsSyncTests.cs b/tests/docs-assembler.Tests/src/docs-assembler.Tests/DocsSyncTests.cs index 07ce24cd9..e8163b826 100644 --- a/tests/docs-assembler.Tests/src/docs-assembler.Tests/DocsSyncTests.cs +++ b/tests/docs-assembler.Tests/src/docs-assembler.Tests/DocsSyncTests.cs @@ -57,7 +57,7 @@ public async Task TestPlan() } ] }); - var planStrategy = new AwsS3SyncPlanStrategy(mockS3Client, "fake", context, new LoggerFactory()); + var planStrategy = new AwsS3SyncPlanStrategy(new LoggerFactory(), mockS3Client, "fake", context); // Act var plan = await planStrategy.Plan(Cancel.None); @@ -130,7 +130,7 @@ public async Task TestApply() { transferredFiles = fileSystem.Directory.GetFiles(request.Directory, request.SearchPattern, request.SearchOption); }); - var applier = new AwsS3SyncApplyStrategy(moxS3Client, moxTransferUtility, "fake", context, new LoggerFactory(), collector); + var applier = new AwsS3SyncApplyStrategy(new LoggerFactory(), moxS3Client, moxTransferUtility, "fake", context, collector); // Act await applier.Apply(plan, Cancel.None);