From 15586446c3d8328e2e58f914ac04f6b32a60a90e Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Thu, 31 Jul 2025 10:49:13 +0200 Subject: [PATCH 01/17] Initial infra work for assembler integration tests --- Directory.Packages.props | 5 + docs-builder.sln | 15 +++ tests-integration/Directory.Build.props | 33 ++++++ .../AssembleFixture.cs | 111 ++++++++++++++++++ .../Class1.cs | 9 ++ .../Elastic.Assembler.IntegrationTests.csproj | 18 +++ tests/Directory.Build.props | 31 +++++ .../Elastic.ApiExplorer.Tests.csproj | 25 ---- ...stic.Documentation.LegacyDocs.Tests.csproj | 37 +----- .../Elastic.Markdown.Tests.csproj | 21 ---- tests/authoring/authoring.fsproj | 9 -- .../docs-assembler.Tests.csproj | 18 +-- 12 files changed, 229 insertions(+), 103 deletions(-) create mode 100644 tests-integration/Directory.Build.props create mode 100644 tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs create mode 100644 tests-integration/Elastic.Assembler.IntegrationTests/Class1.cs create mode 100644 tests-integration/Elastic.Assembler.IntegrationTests/Elastic.Assembler.IntegrationTests.csproj create mode 100644 tests/Directory.Build.props diff --git a/Directory.Packages.props b/Directory.Packages.props index ed9d3acb4..a8bd859a6 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -3,6 +3,8 @@ true true + enable + enable @@ -19,8 +21,11 @@ + + + diff --git a/docs-builder.sln b/docs-builder.sln index 03a3c206d..0813d4ae1 100644 --- a/docs-builder.sln +++ b/docs-builder.sln @@ -25,6 +25,9 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = ".github", ".github\.github.csproj", "{1A8659C1-222A-4824-B562-ED8F88658C05}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{67B576EE-02FA-4F9B-94BC-3630BC09ECE5}" + ProjectSection(SolutionItems) = preProject + tests\Directory.Build.props = tests\Directory.Build.props + EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elastic.Markdown.Tests", "tests\Elastic.Markdown.Tests\Elastic.Markdown.Tests.csproj", "{B27C5107-128B-465A-B8F8-8985399E4CFB}" EndProject @@ -119,6 +122,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "config", "config", "{6FAB56 config\navigation.yml = config\navigation.yml EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests-integration", "tests-integration", "{BCAD38D5-6C83-46E2-8398-4BE463931098}" + ProjectSection(SolutionItems) = preProject + tests-integration\Directory.Build.props = tests-integration\Directory.Build.props + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests-integration\Elastic.Assembler.IntegrationTests", "tests-integration\Elastic.Assembler.IntegrationTests\Elastic.Assembler.IntegrationTests.csproj", "{A272D3EC-FAAF-4795-A796-302725382AFF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -204,6 +214,10 @@ Global {164F55EC-9412-4CD4-81AD-3598B57632A6}.Debug|Any CPU.Build.0 = Debug|Any CPU {164F55EC-9412-4CD4-81AD-3598B57632A6}.Release|Any CPU.ActiveCfg = Release|Any CPU {164F55EC-9412-4CD4-81AD-3598B57632A6}.Release|Any CPU.Build.0 = Release|Any CPU + {A272D3EC-FAAF-4795-A796-302725382AFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A272D3EC-FAAF-4795-A796-302725382AFF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A272D3EC-FAAF-4795-A796-302725382AFF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A272D3EC-FAAF-4795-A796-302725382AFF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {4D198E25-C211-41DC-9E84-B15E89BD7048} = {BE6011CC-1200-4957-B01F-FCCA10C5CF5A} @@ -234,5 +248,6 @@ Global {89B83007-71E6-4B57-BA78-2544BFA476DB} = {BE6011CC-1200-4957-B01F-FCCA10C5CF5A} {111E7029-BB29-4039-9B45-04776798A8DD} = {BE6011CC-1200-4957-B01F-FCCA10C5CF5A} {164F55EC-9412-4CD4-81AD-3598B57632A6} = {67B576EE-02FA-4F9B-94BC-3630BC09ECE5} + {A272D3EC-FAAF-4795-A796-302725382AFF} = {BCAD38D5-6C83-46E2-8398-4BE463931098} EndGlobalSection EndGlobal diff --git a/tests-integration/Directory.Build.props b/tests-integration/Directory.Build.props new file mode 100644 index 000000000..2617f5126 --- /dev/null +++ b/tests-integration/Directory.Build.props @@ -0,0 +1,33 @@ + + + + + + false + false + true + CA1822 + + false + true + Exe + + + + + + + + + + + + + + + + + + + + diff --git a/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs b/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs new file mode 100644 index 000000000..6b694ede9 --- /dev/null +++ b/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs @@ -0,0 +1,111 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// 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.Collections.ObjectModel; +using System.IO.Abstractions; +using Documentation.Assembler; +using Documentation.Assembler.Building; +using Documentation.Assembler.Legacy; +using Documentation.Assembler.Navigation; +using Documentation.Assembler.Sourcing; +using Documentation.Builder.Http; +using Elastic.Documentation.Configuration; +using Elastic.Documentation.Configuration.Assembler; +using Elastic.Documentation.Configuration.Versions; +using Elastic.Documentation.LegacyDocs; +using Elastic.Documentation.Tooling.Diagnostics.Console; +using Microsoft.Extensions.Logging; +using FluentAssertions; +using Xunit; + +[assembly: CaptureConsole, AssemblyFixture(typeof(Elastic.Assembler.IntegrationTests.AssembleFixture))] + +namespace Elastic.Assembler.IntegrationTests; + + +public class AssembleFixture : IAsyncLifetime +{ + private static IFileSystem FileSystem { get; } = new FileSystem(); + public ConfigurationFileProvider ConfigurationFileProvider { get; } = new(FileSystem); + public StaticWebHost WebsiteHost { get; private set; } = null!; + public Task WebsiteRunning { get; private set; } = null!; + + /// + public async ValueTask DisposeAsync() + { + GC.SuppressFinalize(this); + await WebsiteHost.StopAsync(TestContext.Current.CancellationToken); + } + + /// + public async ValueTask InitializeAsync() + { + var ctx = TestContext.Current.CancellationToken; + var logFactory = LoggerFactory.Create(builder => + { + _ = builder.AddConsole(); + }); + await using var collector = new ConsoleDiagnosticsCollector(logFactory, null).StartAsync(ctx); + + var assemblyConfiguration = AssemblyConfiguration.Create(ConfigurationFileProvider); + var versionsConfig = ConfigurationFileProvider.CreateVersionConfiguration(); + + var assembleContext = new AssembleContext(assemblyConfiguration, ConfigurationFileProvider, "dev", collector, FileSystem, FileSystem, null, null); + var cloner = new AssemblerRepositorySourcer(logFactory, assembleContext); + + _ = await cloner.CloneAll(false, ctx); + + _ = GlobalNavigationFile.ValidatePathPrefixes(assembleContext); + + var checkoutResult = cloner.GetAll(); + var checkouts = checkoutResult.Checkouts.ToArray(); + + if (checkouts.Length == 0) + throw new Exception("No checkouts found"); + + var assembleSources = await AssembleSources.AssembleAsync(logFactory, assembleContext, checkouts, versionsConfig, ctx); + var navigationFile = new GlobalNavigationFile(assembleContext, assembleSources); + + var navigation = new GlobalNavigation(assembleSources, navigationFile); + + var pathProvider = new GlobalNavigationPathProvider(navigationFile, assembleSources, assembleContext); + var htmlWriter = new GlobalNavigationHtmlWriter(logFactory, navigation, collector); + var legacyPageChecker = new LegacyPageChecker(); + var historyMapper = new PageLegacyUrlMapper(legacyPageChecker, assembleSources.HistoryMappings); + + var exporters = new HashSet([ExportOption.Html, ExportOption.Configuration]); + var builder = new AssemblerBuilder(logFactory, assembleContext, navigation, htmlWriter, pathProvider, historyMapper); + await builder.BuildAllAsync(assembleSources.AssembleSets, exporters, ctx); + + await cloner.WriteLinkRegistrySnapshot(checkoutResult.LinkRegistrySnapshot, ctx); + + var redirectsPath = Path.Combine(assembleContext.OutputDirectory.FullName, "redirects.json"); + + var sitemapBuilder = new SitemapBuilder(navigation.NavigationItems, assembleContext.WriteFileSystem, assembleContext.OutputDirectory); + sitemapBuilder.Generate(); + + await collector.StopAsync(ctx); + + WebsiteHost = new StaticWebHost(4001); + WebsiteRunning = WebsiteHost.RunAsync(ctx); + } + +} + +public class DatabaseTestClass1 +{ + public AssembleFixture AssembleTestContext { get; } + + public DatabaseTestClass1(AssembleFixture fixture) => AssembleTestContext = fixture; + + [Fact] + public async Task X() + { + await AssembleTestContext.WebsiteRunning; + AssembleTestContext.Should().NotBeNull(); + } + + + // ... +} diff --git a/tests-integration/Elastic.Assembler.IntegrationTests/Class1.cs b/tests-integration/Elastic.Assembler.IntegrationTests/Class1.cs new file mode 100644 index 000000000..55f79944d --- /dev/null +++ b/tests-integration/Elastic.Assembler.IntegrationTests/Class1.cs @@ -0,0 +1,9 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// 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 + +namespace Elastic.Assembler.IntegrationTests; + +public class Class1 +{ +} diff --git a/tests-integration/Elastic.Assembler.IntegrationTests/Elastic.Assembler.IntegrationTests.csproj b/tests-integration/Elastic.Assembler.IntegrationTests/Elastic.Assembler.IntegrationTests.csproj new file mode 100644 index 000000000..9745a7805 --- /dev/null +++ b/tests-integration/Elastic.Assembler.IntegrationTests/Elastic.Assembler.IntegrationTests.csproj @@ -0,0 +1,18 @@ + + + + net9.0 + enable + enable + + + + + + + + + + + + diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props new file mode 100644 index 000000000..2339f7c53 --- /dev/null +++ b/tests/Directory.Build.props @@ -0,0 +1,31 @@ + + + + + + false + false + true + CA1822 + + false + true + Exe + + + + + + + + + + + + + + + + + + diff --git a/tests/Elastic.ApiExplorer.Tests/Elastic.ApiExplorer.Tests.csproj b/tests/Elastic.ApiExplorer.Tests/Elastic.ApiExplorer.Tests.csproj index c09d6cce9..35899012f 100644 --- a/tests/Elastic.ApiExplorer.Tests/Elastic.ApiExplorer.Tests.csproj +++ b/tests/Elastic.ApiExplorer.Tests/Elastic.ApiExplorer.Tests.csproj @@ -2,35 +2,10 @@ net9.0 - enable - enable - - false - true - Exe - - false - true - CA1822 - - - - - - - - - - - - - - - diff --git a/tests/Elastic.Documentation.LegacyDocs.Tests/Elastic.Documentation.LegacyDocs.Tests.csproj b/tests/Elastic.Documentation.LegacyDocs.Tests/Elastic.Documentation.LegacyDocs.Tests.csproj index 3b0324670..ae6ce021d 100644 --- a/tests/Elastic.Documentation.LegacyDocs.Tests/Elastic.Documentation.LegacyDocs.Tests.csproj +++ b/tests/Elastic.Documentation.LegacyDocs.Tests/Elastic.Documentation.LegacyDocs.Tests.csproj @@ -1,34 +1,9 @@  + + net9.0 + - - - net9.0 - enable - enable - - false - true - Library - - false - true - - - - - - - - - - - - - - - - - - - + + + diff --git a/tests/Elastic.Markdown.Tests/Elastic.Markdown.Tests.csproj b/tests/Elastic.Markdown.Tests/Elastic.Markdown.Tests.csproj index 5530dffce..01b287269 100644 --- a/tests/Elastic.Markdown.Tests/Elastic.Markdown.Tests.csproj +++ b/tests/Elastic.Markdown.Tests/Elastic.Markdown.Tests.csproj @@ -2,28 +2,11 @@ net9.0 - enable - enable - - false - true - Exe - - false - true - - - - - - - - @@ -31,8 +14,4 @@ - - - - diff --git a/tests/authoring/authoring.fsproj b/tests/authoring/authoring.fsproj index 4bfb1f994..053238969 100644 --- a/tests/authoring/authoring.fsproj +++ b/tests/authoring/authoring.fsproj @@ -7,18 +7,9 @@ true Library - false - true - - - - - - - diff --git a/tests/docs-assembler.Tests/src/docs-assembler.Tests/docs-assembler.Tests.csproj b/tests/docs-assembler.Tests/src/docs-assembler.Tests/docs-assembler.Tests.csproj index 817de1c4b..0fe87c358 100644 --- a/tests/docs-assembler.Tests/src/docs-assembler.Tests/docs-assembler.Tests.csproj +++ b/tests/docs-assembler.Tests/src/docs-assembler.Tests/docs-assembler.Tests.csproj @@ -1,10 +1,6 @@ - - net9.0 - enable - enable false true @@ -17,21 +13,9 @@ - - - - - - - - - - - - - \ No newline at end of file + From a4e04702375bceb26b80c976f04c6a0d42ffc485 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Thu, 31 Jul 2025 15:56:24 +0200 Subject: [PATCH 02/17] Move to Aspire --- Directory.Packages.props | 18 ++- docs-builder.sln | 16 ++- .../AppDefaultsExtensions.cs | 94 ++++++++++++++ ...astic.Documentation.ServiceDefaults.csproj | 28 +++++ .../Extensions.cs | 119 ++++++++++++++++++ .../Logging/CondensedConsoleLogger.cs | 2 +- .../DocumentationTooling.cs | 67 +--------- .../Elastic.Documentation.Tooling.csproj | 7 +- src/tooling/docs-assembler/Program.cs | 18 +-- .../docs-assembler/docs-assembler.csproj | 1 + .../docs-builder/Http/DocumentationWebHost.cs | 3 +- .../docs-builder/Http/StaticWebHost.cs | 30 +++-- src/tooling/docs-builder/Program.cs | 9 +- tests-integration/Directory.Build.props | 4 +- .../AssembleFixture.cs | 17 +-- .../Elastic.Assembler.IntegrationTests.csproj | 1 + .../Elastic.Documentation.Aspire/AppHost.cs | 18 +++ .../Elastic.Documentation.Aspire.csproj | 24 ++++ .../Properties/launchSettings.json | 29 +++++ .../appsettings.Development.json | 8 ++ .../appsettings.json | 9 ++ 21 files changed, 422 insertions(+), 100 deletions(-) create mode 100644 src/Elastic.Documentation.ServiceDefaults/AppDefaultsExtensions.cs create mode 100644 src/Elastic.Documentation.ServiceDefaults/Elastic.Documentation.ServiceDefaults.csproj create mode 100644 src/Elastic.Documentation.ServiceDefaults/Extensions.cs rename src/{tooling/Elastic.Documentation.Tooling => Elastic.Documentation.ServiceDefaults}/Logging/CondensedConsoleLogger.cs (97%) create mode 100644 tests-integration/Elastic.Documentation.Aspire/AppHost.cs create mode 100644 tests-integration/Elastic.Documentation.Aspire/Elastic.Documentation.Aspire.csproj create mode 100644 tests-integration/Elastic.Documentation.Aspire/Properties/launchSettings.json create mode 100644 tests-integration/Elastic.Documentation.Aspire/appsettings.Development.json create mode 100644 tests-integration/Elastic.Documentation.Aspire/appsettings.json diff --git a/Directory.Packages.props b/Directory.Packages.props index a8bd859a6..597c0e684 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -16,9 +16,12 @@ + + + @@ -43,8 +46,8 @@ - - + + @@ -61,6 +64,17 @@ + + + + + + + + + + + diff --git a/docs-builder.sln b/docs-builder.sln index 0813d4ae1..ee0c2b9ba 100644 --- a/docs-builder.sln +++ b/docs-builder.sln @@ -127,7 +127,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests-integration", "tests- tests-integration\Directory.Build.props = tests-integration\Directory.Build.props EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests-integration\Elastic.Assembler.IntegrationTests", "tests-integration\Elastic.Assembler.IntegrationTests\Elastic.Assembler.IntegrationTests.csproj", "{A272D3EC-FAAF-4795-A796-302725382AFF}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elastic.Assembler.IntegrationTests", "tests-integration\Elastic.Assembler.IntegrationTests\Elastic.Assembler.IntegrationTests.csproj", "{A272D3EC-FAAF-4795-A796-302725382AFF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elastic.Documentation.Aspire", "tests-integration\Elastic.Documentation.Aspire\Elastic.Documentation.Aspire.csproj", "{4DFECE72-4A1F-4B58-918E-DCD07B585231}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elastic.Documentation.ServiceDefaults", "src\Elastic.Documentation.ServiceDefaults\Elastic.Documentation.ServiceDefaults.csproj", "{2A83ED35-B631-4F02-8D4C-15611D0DB72C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -218,6 +222,14 @@ Global {A272D3EC-FAAF-4795-A796-302725382AFF}.Debug|Any CPU.Build.0 = Debug|Any CPU {A272D3EC-FAAF-4795-A796-302725382AFF}.Release|Any CPU.ActiveCfg = Release|Any CPU {A272D3EC-FAAF-4795-A796-302725382AFF}.Release|Any CPU.Build.0 = Release|Any CPU + {4DFECE72-4A1F-4B58-918E-DCD07B585231}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4DFECE72-4A1F-4B58-918E-DCD07B585231}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4DFECE72-4A1F-4B58-918E-DCD07B585231}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4DFECE72-4A1F-4B58-918E-DCD07B585231}.Release|Any CPU.Build.0 = Release|Any CPU + {2A83ED35-B631-4F02-8D4C-15611D0DB72C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A83ED35-B631-4F02-8D4C-15611D0DB72C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A83ED35-B631-4F02-8D4C-15611D0DB72C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A83ED35-B631-4F02-8D4C-15611D0DB72C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {4D198E25-C211-41DC-9E84-B15E89BD7048} = {BE6011CC-1200-4957-B01F-FCCA10C5CF5A} @@ -249,5 +261,7 @@ Global {111E7029-BB29-4039-9B45-04776798A8DD} = {BE6011CC-1200-4957-B01F-FCCA10C5CF5A} {164F55EC-9412-4CD4-81AD-3598B57632A6} = {67B576EE-02FA-4F9B-94BC-3630BC09ECE5} {A272D3EC-FAAF-4795-A796-302725382AFF} = {BCAD38D5-6C83-46E2-8398-4BE463931098} + {4DFECE72-4A1F-4B58-918E-DCD07B585231} = {BCAD38D5-6C83-46E2-8398-4BE463931098} + {2A83ED35-B631-4F02-8D4C-15611D0DB72C} = {BE6011CC-1200-4957-B01F-FCCA10C5CF5A} EndGlobalSection EndGlobal diff --git a/src/Elastic.Documentation.ServiceDefaults/AppDefaultsExtensions.cs b/src/Elastic.Documentation.ServiceDefaults/AppDefaultsExtensions.cs new file mode 100644 index 000000000..93bf87a4e --- /dev/null +++ b/src/Elastic.Documentation.ServiceDefaults/AppDefaultsExtensions.cs @@ -0,0 +1,94 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// 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 Actions.Core.Extensions; +using Elastic.Documentation.Configuration; +using Elastic.Documentation.Configuration.Versions; +using Elastic.Documentation.Diagnostics; +using Elastic.Documentation.ServiceDefaults.Logging; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Console; + +namespace Elastic.Documentation.ServiceDefaults; + +public static class AppDefaultsExtensions +{ + public static TBuilder AddAppDefaults(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + var args = Array.Empty(); + return builder.AddAppDefaults(ref args); + } + public static TBuilder AddAppDefaults(this TBuilder builder, LogLevel defaultLogLevel) where TBuilder : IHostApplicationBuilder + { + var args = Array.Empty(); + return builder.AddAppDefaults(ref args, defaultLogLevel); + } + public static TBuilder AddAppDefaults(this TBuilder builder, ref string[] args, Action configure) where TBuilder : IHostApplicationBuilder => + builder.AddAppDefaults(ref args, null, configure); + + public static TBuilder AddAppDefaults(this TBuilder builder, ref string[] args, LogLevel? defaultLogLevel = null, Action? configure = null) where TBuilder : IHostApplicationBuilder + { + var logLevel = defaultLogLevel ?? LogLevel.Information; + ProcessCommandLineArguments(ref args, ref logLevel); + + var services = builder.Services; + _ = services.AddLogging(x => x + .ClearProviders() + .SetMinimumLevel(logLevel).AddConsole(c => c.FormatterName = "condensed") + ); + + _ = services + .AddGitHubActionsCore() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddConfigurationFileProvider((s, p) => + { + _ = s.AddSingleton(p.CreateVersionConfiguration()); + configure?.Invoke(s, p); + }); + services.TryAddEnumerable(ServiceDescriptor.Singleton()); + _ = services.AddLogging(x => x + .ClearProviders() + .SetMinimumLevel(logLevel) + .AddConsole(c => c.FormatterName = "condensed") + ); + + return builder; + } + + private static void ProcessCommandLineArguments(ref string[] args, ref LogLevel defaultLogLevel) + { + var newArgs = new List(); + for (var i = 0; i < args.Length; i++) + { + if (args[i] == "--log-level") + { + if (args.Length > i + 1) + defaultLogLevel = GetLogLevel(args[i + 1]); + + i++; + } + else + newArgs.Add(args[i]); + } + + args = [.. newArgs]; + } + + private static LogLevel GetLogLevel(string? logLevel) => logLevel switch + { + "trace" => LogLevel.Trace, + "debug" => LogLevel.Debug, + "information" => LogLevel.Information, + "info" => LogLevel.Information, + "warning" => LogLevel.Warning, + "error" => LogLevel.Error, + "critical" => LogLevel.Critical, + _ => LogLevel.Information + }; +} diff --git a/src/Elastic.Documentation.ServiceDefaults/Elastic.Documentation.ServiceDefaults.csproj b/src/Elastic.Documentation.ServiceDefaults/Elastic.Documentation.ServiceDefaults.csproj new file mode 100644 index 000000000..1091489a9 --- /dev/null +++ b/src/Elastic.Documentation.ServiceDefaults/Elastic.Documentation.ServiceDefaults.csproj @@ -0,0 +1,28 @@ + + + + net9.0 + enable + enable + true + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Elastic.Documentation.ServiceDefaults/Extensions.cs b/src/Elastic.Documentation.ServiceDefaults/Extensions.cs new file mode 100644 index 000000000..4af55c492 --- /dev/null +++ b/src/Elastic.Documentation.ServiceDefaults/Extensions.cs @@ -0,0 +1,119 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// 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 Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using OpenTelemetry; +using OpenTelemetry.Logs; +using OpenTelemetry.Metrics; +using OpenTelemetry.Trace; + +namespace Elastic.Documentation.ServiceDefaults; + +// Adds common .NET Aspire services: service discovery, resilience, health checks, and OpenTelemetry. +// This project should be referenced by each service project in your solution. +// To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults +public static class Extensions +{ + private const string HealthEndpointPath = "/health"; + private const string AlivenessEndpointPath = "/alive"; + + public static TBuilder AddServiceDefaults(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + _ = builder + .ConfigureOpenTelemetry() + .AddDefaultHealthChecks(); + + _ = builder.Services + .AddServiceDiscovery() + .ConfigureHttpClientDefaults(http => + { + _ = http.AddStandardResilienceHandler(); + _ = http.AddServiceDiscovery(); + }); + return builder; + } + + public static TBuilder ConfigureOpenTelemetry(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + _ = builder.Logging.AddOpenTelemetry(logging => + { + logging.IncludeFormattedMessage = true; + logging.IncludeScopes = true; + }); + + _ = builder.Services.AddOpenTelemetry() + .WithMetrics(metrics => + { + _ = metrics.AddAspNetCoreInstrumentation() + .AddHttpClientInstrumentation() + .AddRuntimeInstrumentation(); + }) + .WithTracing(tracing => + { + _ = tracing.AddSource(builder.Environment.ApplicationName) + .AddAspNetCoreInstrumentation(tracing => + // Exclude health check requests from tracing + tracing.Filter = context => + !context.Request.Path.StartsWithSegments(HealthEndpointPath) + && !context.Request.Path.StartsWithSegments(AlivenessEndpointPath) + ) + // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package) + //.AddGrpcClientInstrumentation() + .AddHttpClientInstrumentation(); + }); + + _ = builder.AddOpenTelemetryExporters(); + + return builder; + } + + private static TBuilder AddOpenTelemetryExporters(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]); + + if (useOtlpExporter) + _ = builder.Services.AddOpenTelemetry().UseOtlpExporter(); + + // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package) + //if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"])) + //{ + // builder.Services.AddOpenTelemetry() + // .UseAzureMonitor(); + //} + + return builder; + } + + public static TBuilder AddDefaultHealthChecks(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + _ = builder.Services.AddHealthChecks() + .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]); + + return builder; + } + + public static WebApplication MapDefaultEndpoints(this WebApplication app) + { + // Adding health checks endpoints to applications in non-development environments has security implications. + // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments. + if (app.Environment.IsDevelopment()) + { + // All health checks must pass for app to be considered ready to accept traffic after starting + _ = app.MapHealthChecks(HealthEndpointPath); + + // Only health checks tagged with the "live" tag must pass for app to be considered alive + _ = app.MapHealthChecks(AlivenessEndpointPath, new HealthCheckOptions + { + Predicate = r => r.Tags.Contains("live") + }); + } + + return app; + } +} diff --git a/src/tooling/Elastic.Documentation.Tooling/Logging/CondensedConsoleLogger.cs b/src/Elastic.Documentation.ServiceDefaults/Logging/CondensedConsoleLogger.cs similarity index 97% rename from src/tooling/Elastic.Documentation.Tooling/Logging/CondensedConsoleLogger.cs rename to src/Elastic.Documentation.ServiceDefaults/Logging/CondensedConsoleLogger.cs index 852087708..ef00eabff 100644 --- a/src/tooling/Elastic.Documentation.Tooling/Logging/CondensedConsoleLogger.cs +++ b/src/Elastic.Documentation.ServiceDefaults/Logging/CondensedConsoleLogger.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.Logging.Console; using static Crayon.Output; -namespace Elastic.Documentation.Tooling.Logging; +namespace Elastic.Documentation.ServiceDefaults.Logging; public class CondensedConsoleFormatter() : ConsoleFormatter("condensed") { diff --git a/src/tooling/Elastic.Documentation.Tooling/DocumentationTooling.cs b/src/tooling/Elastic.Documentation.Tooling/DocumentationTooling.cs index a85980927..06c309d27 100644 --- a/src/tooling/Elastic.Documentation.Tooling/DocumentationTooling.cs +++ b/src/tooling/Elastic.Documentation.Tooling/DocumentationTooling.cs @@ -7,7 +7,7 @@ using Elastic.Documentation.Configuration.Assembler; using Elastic.Documentation.Configuration.Versions; using Elastic.Documentation.Diagnostics; -using Elastic.Documentation.Tooling.Logging; +using Elastic.Documentation.ServiceDefaults.Logging; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Logging; @@ -17,69 +17,4 @@ namespace Elastic.Documentation.Tooling; public static class DocumentationTooling { - public static ServiceProvider CreateServiceProvider(ref string[] args, Action? configure = null) - { - var defaultLogLevel = LogLevel.Information; - ProcessCommandLineArguments(ref args, ref defaultLogLevel); - - var services = new ServiceCollection(); - CreateServiceCollection(services, defaultLogLevel, configure); - return services.BuildServiceProvider(); - } - - public static void CreateServiceCollection( - IServiceCollection services, - LogLevel defaultLogLevel, - Action? configure = null - ) - { - _ = services - .AddGitHubActionsCore() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddConfigurationFileProvider((s, p) => - { - _ = s.AddSingleton(p.CreateVersionConfiguration()); - configure?.Invoke(s, p); - }); - services.TryAddEnumerable(ServiceDescriptor.Singleton()); - _ = services.AddLogging(x => x - .ClearProviders() - .SetMinimumLevel(defaultLogLevel) - .AddConsole(c => c.FormatterName = "condensed") - ); - - } - - private static void ProcessCommandLineArguments(ref string[] args, ref LogLevel defaultLogLevel) - { - var newArgs = new List(); - for (var i = 0; i < args.Length; i++) - { - if (args[i] == "--log-level") - { - if (args.Length > i + 1) - defaultLogLevel = GetLogLevel(args[i + 1]); - - i++; - } - else - newArgs.Add(args[i]); - } - - args = [.. newArgs]; - } - - private static LogLevel GetLogLevel(string? logLevel) => logLevel switch - { - "trace" => LogLevel.Trace, - "debug" => LogLevel.Debug, - "information" => LogLevel.Information, - "info" => LogLevel.Information, - "warning" => LogLevel.Warning, - "error" => LogLevel.Error, - "critical" => LogLevel.Critical, - _ => LogLevel.Information - }; } diff --git a/src/tooling/Elastic.Documentation.Tooling/Elastic.Documentation.Tooling.csproj b/src/tooling/Elastic.Documentation.Tooling/Elastic.Documentation.Tooling.csproj index 772393998..3932d4ad8 100644 --- a/src/tooling/Elastic.Documentation.Tooling/Elastic.Documentation.Tooling.csproj +++ b/src/tooling/Elastic.Documentation.Tooling/Elastic.Documentation.Tooling.csproj @@ -10,14 +10,17 @@ - - + + + + + diff --git a/src/tooling/docs-assembler/Program.cs b/src/tooling/docs-assembler/Program.cs index bca2c65a7..0fae69696 100644 --- a/src/tooling/docs-assembler/Program.cs +++ b/src/tooling/docs-assembler/Program.cs @@ -3,23 +3,27 @@ // See the LICENSE file in the project root for more information using System.Diagnostics.CodeAnalysis; +using System.Reflection.Metadata; using Actions.Core.Services; using ConsoleAppFramework; using Documentation.Assembler.Cli; using Elastic.Documentation.Configuration.Assembler; +using Elastic.Documentation.ServiceDefaults; using Elastic.Documentation.Tooling; using Elastic.Documentation.Tooling.Filters; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -await using var serviceProvider = DocumentationTooling.CreateServiceProvider(ref args, (s, p) => -{ - _ = s.AddSingleton(AssemblyConfiguration.Create(p)); -}); +var builder = Host.CreateApplicationBuilder() + .AddAppDefaults(ref args, (s, p) => + { + _ = s.AddSingleton(AssemblyConfiguration.Create(p)); + }) + .AddServiceDefaults(); -ConsoleApp.ServiceProvider = serviceProvider; +var app = builder.ToConsoleAppBuilder(); -var app = ConsoleApp.Create(); app.UseFilter(); app.UseFilter(); app.UseFilter(); @@ -32,7 +36,7 @@ app.Add("deploy"); app.Add("legacy-docs"); -var githubActions = ConsoleApp.ServiceProvider.GetService(); +var githubActions = ConsoleApp.ServiceProvider!.GetService(); var command = githubActions?.GetInput("COMMAND"); if (!string.IsNullOrEmpty(command)) args = command.Split(' '); diff --git a/src/tooling/docs-assembler/docs-assembler.csproj b/src/tooling/docs-assembler/docs-assembler.csproj index ccdd564d1..d7a387fc9 100644 --- a/src/tooling/docs-assembler/docs-assembler.csproj +++ b/src/tooling/docs-assembler/docs-assembler.csproj @@ -17,6 +17,7 @@ + diff --git a/src/tooling/docs-builder/Http/DocumentationWebHost.cs b/src/tooling/docs-builder/Http/DocumentationWebHost.cs index 8469d1431..6220534a8 100644 --- a/src/tooling/docs-builder/Http/DocumentationWebHost.cs +++ b/src/tooling/docs-builder/Http/DocumentationWebHost.cs @@ -9,6 +9,7 @@ using Documentation.Builder.Diagnostics.LiveMode; using Elastic.Documentation.Configuration; using Elastic.Documentation.Configuration.Versions; +using Elastic.Documentation.ServiceDefaults; using Elastic.Documentation.Site.FileProviders; using Elastic.Documentation.Tooling; using Elastic.Markdown.IO; @@ -34,7 +35,7 @@ public DocumentationWebHost(ILoggerFactory logFactory, string? path, int port, I { _writeFileSystem = writeFs; var builder = WebApplication.CreateSlimBuilder(); - DocumentationTooling.CreateServiceCollection(builder.Services, LogLevel.Information); + _ = builder.AddAppDefaults().AddServiceDefaults(); _ = builder.Logging .AddFilter("Microsoft.AspNetCore.Hosting.Diagnostics", LogLevel.Error) diff --git a/src/tooling/docs-builder/Http/StaticWebHost.cs b/src/tooling/docs-builder/Http/StaticWebHost.cs index 387c77548..12fbbd5e0 100644 --- a/src/tooling/docs-builder/Http/StaticWebHost.cs +++ b/src/tooling/docs-builder/Http/StaticWebHost.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information using Elastic.Documentation.Configuration; +using Elastic.Documentation.ServiceDefaults; using Elastic.Documentation.Tooling; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -14,7 +15,7 @@ namespace Documentation.Builder.Http; public class StaticWebHost { - private readonly WebApplication _webApplication; + public WebApplication WebApplication { get; } public StaticWebHost(int port) { @@ -24,7 +25,8 @@ public StaticWebHost(int port) { ContentRootPath = contentRoot }); - DocumentationTooling.CreateServiceCollection(builder.Services, LogLevel.Warning); + + _ = builder.AddAppDefaults().AddServiceDefaults(); _ = builder.Logging .AddFilter("Microsoft.AspNetCore.Hosting.Diagnostics", LogLevel.Error) @@ -32,23 +34,35 @@ public StaticWebHost(int port) .AddFilter("Microsoft.Hosting.Lifetime", LogLevel.Information); _ = builder.WebHost.UseUrls($"http://localhost:{port}"); - _webApplication = builder.Build(); + WebApplication = builder.Build(); SetUpRoutes(); } - public async Task RunAsync(Cancel ctx) => await _webApplication.RunAsync(ctx); + public async Task WaitForAppStartup(Cancel ctx) + { + var startedSource = new TaskCompletionSource(); + var cancelledSource = new TaskCompletionSource(); + + await using var reg1 = WebApplication.Lifetime.ApplicationStarted.Register(() => startedSource.SetResult()); + await using var reg2 = ctx.Register(() => cancelledSource.SetResult()); + + var completedTask = await Task.WhenAny(startedSource.Task, cancelledSource.Task).ConfigureAwait(false); + return completedTask == startedSource.Task; + } + + public async Task RunAsync(Cancel ctx) => await WebApplication.RunAsync(ctx); - public async Task StopAsync(Cancel ctx) => await _webApplication.StopAsync(ctx); + public async Task StopAsync(Cancel ctx) => await WebApplication.StopAsync(ctx); private void SetUpRoutes() { _ = - _webApplication + WebApplication .UseRouting(); - _ = _webApplication.MapGet("/", (Cancel _) => Results.Redirect("docs")); + _ = WebApplication.MapGet("/", (Cancel _) => Results.Redirect("docs")); - _ = _webApplication.MapGet("{**slug}", ServeDocumentationFile); + _ = WebApplication.MapGet("{**slug}", ServeDocumentationFile); } private async Task ServeDocumentationFile(string slug, Cancel _) diff --git a/src/tooling/docs-builder/Program.cs b/src/tooling/docs-builder/Program.cs index 493064625..dcc3f2ac3 100644 --- a/src/tooling/docs-builder/Program.cs +++ b/src/tooling/docs-builder/Program.cs @@ -5,14 +5,17 @@ using System.Diagnostics.CodeAnalysis; using ConsoleAppFramework; using Documentation.Builder.Cli; +using Elastic.Documentation.ServiceDefaults; using Elastic.Documentation.Tooling; using Elastic.Documentation.Tooling.Filters; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -await using var serviceProvider = DocumentationTooling.CreateServiceProvider(ref args, (s, p) => { }); -ConsoleApp.ServiceProvider = serviceProvider; +var builder = Host.CreateApplicationBuilder() + .AddAppDefaults(ref args) + .AddServiceDefaults(); -var app = ConsoleApp.Create(); +var app = builder.ToConsoleAppBuilder(); app.UseFilter(); app.UseFilter(); diff --git a/tests-integration/Directory.Build.props b/tests-integration/Directory.Build.props index 2617f5126..009f14389 100644 --- a/tests-integration/Directory.Build.props +++ b/tests-integration/Directory.Build.props @@ -13,7 +13,7 @@ Exe - + @@ -26,7 +26,7 @@ - + diff --git a/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs b/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs index 6b694ede9..7babe1e49 100644 --- a/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs +++ b/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs @@ -4,6 +4,7 @@ using System.Collections.ObjectModel; using System.IO.Abstractions; +using Aspire.Hosting.Testing; using Documentation.Assembler; using Documentation.Assembler.Building; using Documentation.Assembler.Legacy; @@ -14,6 +15,7 @@ using Elastic.Documentation.Configuration.Assembler; using Elastic.Documentation.Configuration.Versions; using Elastic.Documentation.LegacyDocs; +using Elastic.Documentation.Tooling; using Elastic.Documentation.Tooling.Diagnostics.Console; using Microsoft.Extensions.Logging; using FluentAssertions; @@ -41,6 +43,7 @@ public async ValueTask DisposeAsync() /// public async ValueTask InitializeAsync() { + //var builder = await DistributedApplicationTestingBuilder.CreateAsync([]); var ctx = TestContext.Current.CancellationToken; var logFactory = LoggerFactory.Create(builder => { @@ -89,21 +92,21 @@ public async ValueTask InitializeAsync() WebsiteHost = new StaticWebHost(4001); WebsiteRunning = WebsiteHost.RunAsync(ctx); + _ = await WebsiteHost.WaitForAppStartup(ctx); } } -public class DatabaseTestClass1 +public class DatabaseTestClass1(AssembleFixture fixture) { - public AssembleFixture AssembleTestContext { get; } - - public DatabaseTestClass1(AssembleFixture fixture) => AssembleTestContext = fixture; - [Fact] public async Task X() { - await AssembleTestContext.WebsiteRunning; - AssembleTestContext.Should().NotBeNull(); + using var client = new HttpClient { BaseAddress = new Uri("http://localhost:4001") }; + var root = await client.GetStringAsync("/", TestContext.Current.CancellationToken); + Console.WriteLine(root); + + fixture.Should().NotBeNull(); } diff --git a/tests-integration/Elastic.Assembler.IntegrationTests/Elastic.Assembler.IntegrationTests.csproj b/tests-integration/Elastic.Assembler.IntegrationTests/Elastic.Assembler.IntegrationTests.csproj index 9745a7805..1aec8571c 100644 --- a/tests-integration/Elastic.Assembler.IntegrationTests/Elastic.Assembler.IntegrationTests.csproj +++ b/tests-integration/Elastic.Assembler.IntegrationTests/Elastic.Assembler.IntegrationTests.csproj @@ -13,6 +13,7 @@ + diff --git a/tests-integration/Elastic.Documentation.Aspire/AppHost.cs b/tests-integration/Elastic.Documentation.Aspire/AppHost.cs new file mode 100644 index 000000000..8b9c48a7a --- /dev/null +++ b/tests-integration/Elastic.Documentation.Aspire/AppHost.cs @@ -0,0 +1,18 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// 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 + +var builder = DistributedApplication.CreateBuilder(args); + +var cloneAll = builder.AddProject("DocsAssemblerCloneAll").WithArgs("repo", "clone-all"); + +var buildAll = builder.AddProject("DocsAssemblerBuildAll").WithArgs("repo", "build-all").WaitForCompletion(cloneAll); + +var serveStatic = builder.AddProject("DocsBuilderServeStatic") + .WithHttpEndpoint(name: "serve-static", port: 4000, isProxied: false) + .WithArgs("serve-static") + .WaitForCompletion(buildAll); + +builder.AddElasticsearch("elasticsearch"); + +builder.Build().Run(); diff --git a/tests-integration/Elastic.Documentation.Aspire/Elastic.Documentation.Aspire.csproj b/tests-integration/Elastic.Documentation.Aspire/Elastic.Documentation.Aspire.csproj new file mode 100644 index 000000000..51c7ae5e5 --- /dev/null +++ b/tests-integration/Elastic.Documentation.Aspire/Elastic.Documentation.Aspire.csproj @@ -0,0 +1,24 @@ + + + + + + Exe + net9.0 + enable + enable + 72f50f33-6fb9-4d08-bff3-39568fe370b3 + false + + + + + + + + + + + + + diff --git a/tests-integration/Elastic.Documentation.Aspire/Properties/launchSettings.json b/tests-integration/Elastic.Documentation.Aspire/Properties/launchSettings.json new file mode 100644 index 000000000..474d114c7 --- /dev/null +++ b/tests-integration/Elastic.Documentation.Aspire/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:17166;http://localhost:15066", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21053", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22211" + } + }, + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:15066", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19109", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20157" + } + } + } +} diff --git a/tests-integration/Elastic.Documentation.Aspire/appsettings.Development.json b/tests-integration/Elastic.Documentation.Aspire/appsettings.Development.json new file mode 100644 index 000000000..0c208ae91 --- /dev/null +++ b/tests-integration/Elastic.Documentation.Aspire/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/tests-integration/Elastic.Documentation.Aspire/appsettings.json b/tests-integration/Elastic.Documentation.Aspire/appsettings.json new file mode 100644 index 000000000..31c092aa4 --- /dev/null +++ b/tests-integration/Elastic.Documentation.Aspire/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning", + "Aspire.Hosting.Dcp": "Warning" + } + } +} From a2fb51623014f202ba5749b4d67a67fa4f679ba6 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Thu, 31 Jul 2025 17:01:17 +0200 Subject: [PATCH 03/17] Move integration tests over to aspire --- .../AppDefaultsExtensions.cs | 7 +- src/tooling/docs-assembler/Program.cs | 3 +- .../docs-builder/Http/DocumentationWebHost.cs | 2 +- .../docs-builder/Http/StaticWebHost.cs | 2 +- src/tooling/docs-builder/Program.cs | 3 +- .../AssembleFixture.cs | 93 +++---------------- .../Elastic.Assembler.IntegrationTests.csproj | 1 + .../Elastic.Documentation.Aspire/AppHost.cs | 5 +- 8 files changed, 24 insertions(+), 92 deletions(-) diff --git a/src/Elastic.Documentation.ServiceDefaults/AppDefaultsExtensions.cs b/src/Elastic.Documentation.ServiceDefaults/AppDefaultsExtensions.cs index 93bf87a4e..8481c37d2 100644 --- a/src/Elastic.Documentation.ServiceDefaults/AppDefaultsExtensions.cs +++ b/src/Elastic.Documentation.ServiceDefaults/AppDefaultsExtensions.cs @@ -36,11 +36,6 @@ public static TBuilder AddAppDefaults(this TBuilder builder, ref strin ProcessCommandLineArguments(ref args, ref logLevel); var services = builder.Services; - _ = services.AddLogging(x => x - .ClearProviders() - .SetMinimumLevel(logLevel).AddConsole(c => c.FormatterName = "condensed") - ); - _ = services .AddGitHubActionsCore() .AddSingleton() @@ -58,7 +53,7 @@ public static TBuilder AddAppDefaults(this TBuilder builder, ref strin .AddConsole(c => c.FormatterName = "condensed") ); - return builder; + return builder.AddServiceDefaults(); } private static void ProcessCommandLineArguments(ref string[] args, ref LogLevel defaultLogLevel) diff --git a/src/tooling/docs-assembler/Program.cs b/src/tooling/docs-assembler/Program.cs index 0fae69696..881c9dbb7 100644 --- a/src/tooling/docs-assembler/Program.cs +++ b/src/tooling/docs-assembler/Program.cs @@ -19,8 +19,7 @@ .AddAppDefaults(ref args, (s, p) => { _ = s.AddSingleton(AssemblyConfiguration.Create(p)); - }) - .AddServiceDefaults(); + }); var app = builder.ToConsoleAppBuilder(); diff --git a/src/tooling/docs-builder/Http/DocumentationWebHost.cs b/src/tooling/docs-builder/Http/DocumentationWebHost.cs index 6220534a8..b98c9b1e3 100644 --- a/src/tooling/docs-builder/Http/DocumentationWebHost.cs +++ b/src/tooling/docs-builder/Http/DocumentationWebHost.cs @@ -35,7 +35,7 @@ public DocumentationWebHost(ILoggerFactory logFactory, string? path, int port, I { _writeFileSystem = writeFs; var builder = WebApplication.CreateSlimBuilder(); - _ = builder.AddAppDefaults().AddServiceDefaults(); + _ = builder.AddAppDefaults(); _ = builder.Logging .AddFilter("Microsoft.AspNetCore.Hosting.Diagnostics", LogLevel.Error) diff --git a/src/tooling/docs-builder/Http/StaticWebHost.cs b/src/tooling/docs-builder/Http/StaticWebHost.cs index 12fbbd5e0..f967fd704 100644 --- a/src/tooling/docs-builder/Http/StaticWebHost.cs +++ b/src/tooling/docs-builder/Http/StaticWebHost.cs @@ -26,7 +26,7 @@ public StaticWebHost(int port) ContentRootPath = contentRoot }); - _ = builder.AddAppDefaults().AddServiceDefaults(); + _ = builder.AddAppDefaults(); _ = builder.Logging .AddFilter("Microsoft.AspNetCore.Hosting.Diagnostics", LogLevel.Error) diff --git a/src/tooling/docs-builder/Program.cs b/src/tooling/docs-builder/Program.cs index dcc3f2ac3..b283bff2d 100644 --- a/src/tooling/docs-builder/Program.cs +++ b/src/tooling/docs-builder/Program.cs @@ -12,8 +12,7 @@ using Microsoft.Extensions.Logging; var builder = Host.CreateApplicationBuilder() - .AddAppDefaults(ref args) - .AddServiceDefaults(); + .AddAppDefaults(ref args); var app = builder.ToConsoleAppBuilder(); diff --git a/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs b/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs index 7babe1e49..166a812c1 100644 --- a/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs +++ b/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs @@ -2,24 +2,9 @@ // 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.Collections.ObjectModel; -using System.IO.Abstractions; +using Aspire.Hosting; using Aspire.Hosting.Testing; -using Documentation.Assembler; -using Documentation.Assembler.Building; -using Documentation.Assembler.Legacy; -using Documentation.Assembler.Navigation; -using Documentation.Assembler.Sourcing; -using Documentation.Builder.Http; -using Elastic.Documentation.Configuration; -using Elastic.Documentation.Configuration.Assembler; -using Elastic.Documentation.Configuration.Versions; -using Elastic.Documentation.LegacyDocs; -using Elastic.Documentation.Tooling; -using Elastic.Documentation.Tooling.Diagnostics.Console; -using Microsoft.Extensions.Logging; using FluentAssertions; -using Xunit; [assembly: CaptureConsole, AssemblyFixture(typeof(Elastic.Assembler.IntegrationTests.AssembleFixture))] @@ -28,73 +13,25 @@ namespace Elastic.Assembler.IntegrationTests; public class AssembleFixture : IAsyncLifetime { - private static IFileSystem FileSystem { get; } = new FileSystem(); - public ConfigurationFileProvider ConfigurationFileProvider { get; } = new(FileSystem); - public StaticWebHost WebsiteHost { get; private set; } = null!; - public Task WebsiteRunning { get; private set; } = null!; + public DistributedApplication DistributedApplication { get; private set; } = null!; /// - public async ValueTask DisposeAsync() + public async ValueTask InitializeAsync() { - GC.SuppressFinalize(this); - await WebsiteHost.StopAsync(TestContext.Current.CancellationToken); + var builder = await DistributedApplicationTestingBuilder.CreateAsync(); + DistributedApplication = await builder.BuildAsync(); + await DistributedApplication.StartAsync(); } /// - public async ValueTask InitializeAsync() + public async ValueTask DisposeAsync() { - //var builder = await DistributedApplicationTestingBuilder.CreateAsync([]); - var ctx = TestContext.Current.CancellationToken; - var logFactory = LoggerFactory.Create(builder => - { - _ = builder.AddConsole(); - }); - await using var collector = new ConsoleDiagnosticsCollector(logFactory, null).StartAsync(ctx); - - var assemblyConfiguration = AssemblyConfiguration.Create(ConfigurationFileProvider); - var versionsConfig = ConfigurationFileProvider.CreateVersionConfiguration(); - - var assembleContext = new AssembleContext(assemblyConfiguration, ConfigurationFileProvider, "dev", collector, FileSystem, FileSystem, null, null); - var cloner = new AssemblerRepositorySourcer(logFactory, assembleContext); - - _ = await cloner.CloneAll(false, ctx); - - _ = GlobalNavigationFile.ValidatePathPrefixes(assembleContext); - - var checkoutResult = cloner.GetAll(); - var checkouts = checkoutResult.Checkouts.ToArray(); - - if (checkouts.Length == 0) - throw new Exception("No checkouts found"); - - var assembleSources = await AssembleSources.AssembleAsync(logFactory, assembleContext, checkouts, versionsConfig, ctx); - var navigationFile = new GlobalNavigationFile(assembleContext, assembleSources); - - var navigation = new GlobalNavigation(assembleSources, navigationFile); - - var pathProvider = new GlobalNavigationPathProvider(navigationFile, assembleSources, assembleContext); - var htmlWriter = new GlobalNavigationHtmlWriter(logFactory, navigation, collector); - var legacyPageChecker = new LegacyPageChecker(); - var historyMapper = new PageLegacyUrlMapper(legacyPageChecker, assembleSources.HistoryMappings); - - var exporters = new HashSet([ExportOption.Html, ExportOption.Configuration]); - var builder = new AssemblerBuilder(logFactory, assembleContext, navigation, htmlWriter, pathProvider, historyMapper); - await builder.BuildAllAsync(assembleSources.AssembleSets, exporters, ctx); - - await cloner.WriteLinkRegistrySnapshot(checkoutResult.LinkRegistrySnapshot, ctx); - - var redirectsPath = Path.Combine(assembleContext.OutputDirectory.FullName, "redirects.json"); - - var sitemapBuilder = new SitemapBuilder(navigation.NavigationItems, assembleContext.WriteFileSystem, assembleContext.OutputDirectory); - sitemapBuilder.Generate(); - - await collector.StopAsync(ctx); - - WebsiteHost = new StaticWebHost(4001); - WebsiteRunning = WebsiteHost.RunAsync(ctx); - _ = await WebsiteHost.WaitForAppStartup(ctx); + await DistributedApplication.StopAsync(); + await DistributedApplication.DisposeAsync(); + GC.SuppressFinalize(this); } + } public class DatabaseTestClass1(AssembleFixture fixture) @@ -102,11 +39,11 @@ public class DatabaseTestClass1(AssembleFixture fixture) [Fact] public async Task X() { - using var client = new HttpClient { BaseAddress = new Uri("http://localhost:4001") }; + _ = await fixture.DistributedApplication.ResourceNotifications + .WaitForResourceHealthyAsync("DocsBuilderServeStatic", cancellationToken: TestContext.Current.CancellationToken); + var client = fixture.DistributedApplication.CreateHttpClient("DocsBuilderServeStatic", "http"); var root = await client.GetStringAsync("/", TestContext.Current.CancellationToken); - Console.WriteLine(root); - - fixture.Should().NotBeNull(); + _ = root.Should().NotBeNullOrEmpty(); } diff --git a/tests-integration/Elastic.Assembler.IntegrationTests/Elastic.Assembler.IntegrationTests.csproj b/tests-integration/Elastic.Assembler.IntegrationTests/Elastic.Assembler.IntegrationTests.csproj index 1aec8571c..ed79961c2 100644 --- a/tests-integration/Elastic.Assembler.IntegrationTests/Elastic.Assembler.IntegrationTests.csproj +++ b/tests-integration/Elastic.Assembler.IntegrationTests/Elastic.Assembler.IntegrationTests.csproj @@ -10,6 +10,7 @@ + diff --git a/tests-integration/Elastic.Documentation.Aspire/AppHost.cs b/tests-integration/Elastic.Documentation.Aspire/AppHost.cs index 8b9c48a7a..5d359fa6f 100644 --- a/tests-integration/Elastic.Documentation.Aspire/AppHost.cs +++ b/tests-integration/Elastic.Documentation.Aspire/AppHost.cs @@ -9,10 +9,11 @@ var buildAll = builder.AddProject("DocsAssemblerBuildAll").WithArgs("repo", "build-all").WaitForCompletion(cloneAll); var serveStatic = builder.AddProject("DocsBuilderServeStatic") - .WithHttpEndpoint(name: "serve-static", port: 4000, isProxied: false) + .WithHttpEndpoint(port: 4000, isProxied: false) .WithArgs("serve-static") + .WithHttpHealthCheck("/", 200) .WaitForCompletion(buildAll); -builder.AddElasticsearch("elasticsearch"); +//builder.AddElasticsearch("elasticsearch"); builder.Build().Run(); From 9e722947a2453f5831c3b60940ae0749679279be Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Thu, 31 Jul 2025 22:43:10 +0200 Subject: [PATCH 04/17] Touchup logging --- .../AppDefaultsExtensions.cs | 11 +++++++++-- .../AssembleFixture.cs | 7 ++++++- .../Elastic.Assembler.IntegrationTests/Class1.cs | 9 --------- 3 files changed, 15 insertions(+), 12 deletions(-) delete mode 100644 tests-integration/Elastic.Assembler.IntegrationTests/Class1.cs diff --git a/src/Elastic.Documentation.ServiceDefaults/AppDefaultsExtensions.cs b/src/Elastic.Documentation.ServiceDefaults/AppDefaultsExtensions.cs index 8481c37d2..1212841e2 100644 --- a/src/Elastic.Documentation.ServiceDefaults/AppDefaultsExtensions.cs +++ b/src/Elastic.Documentation.ServiceDefaults/AppDefaultsExtensions.cs @@ -46,14 +46,21 @@ public static TBuilder AddAppDefaults(this TBuilder builder, ref strin _ = s.AddSingleton(p.CreateVersionConfiguration()); configure?.Invoke(s, p); }); + _ = builder.Services.AddAppLogging(logLevel); + + return builder.AddServiceDefaults(); + } + + public static TServiceCollection AddAppLogging(this TServiceCollection services, LogLevel logLevel) + where TServiceCollection : IServiceCollection + { services.TryAddEnumerable(ServiceDescriptor.Singleton()); _ = services.AddLogging(x => x .ClearProviders() .SetMinimumLevel(logLevel) .AddConsole(c => c.FormatterName = "condensed") ); - - return builder.AddServiceDefaults(); + return services; } private static void ProcessCommandLineArguments(ref string[] args, ref LogLevel defaultLogLevel) diff --git a/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs b/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs index 166a812c1..1595aa182 100644 --- a/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs +++ b/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs @@ -4,7 +4,10 @@ using Aspire.Hosting; using Aspire.Hosting.Testing; +using Elastic.Documentation.ServiceDefaults; using FluentAssertions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; [assembly: CaptureConsole, AssemblyFixture(typeof(Elastic.Assembler.IntegrationTests.AssembleFixture))] @@ -19,6 +22,7 @@ public class AssembleFixture : IAsyncLifetime public async ValueTask InitializeAsync() { var builder = await DistributedApplicationTestingBuilder.CreateAsync(); + _ = builder.Services.AddAppLogging(LogLevel.Information); DistributedApplication = await builder.BuildAsync(); await DistributedApplication.StartAsync(); } @@ -34,7 +38,7 @@ public async ValueTask DisposeAsync() } -public class DatabaseTestClass1(AssembleFixture fixture) +public class DatabaseTestClass1(AssembleFixture fixture, ITestOutputHelper output) { [Fact] public async Task X() @@ -43,6 +47,7 @@ public async Task X() .WaitForResourceHealthyAsync("DocsBuilderServeStatic", cancellationToken: TestContext.Current.CancellationToken); var client = fixture.DistributedApplication.CreateHttpClient("DocsBuilderServeStatic", "http"); var root = await client.GetStringAsync("/", TestContext.Current.CancellationToken); + output.WriteLine(root); _ = root.Should().NotBeNullOrEmpty(); } diff --git a/tests-integration/Elastic.Assembler.IntegrationTests/Class1.cs b/tests-integration/Elastic.Assembler.IntegrationTests/Class1.cs deleted file mode 100644 index 55f79944d..000000000 --- a/tests-integration/Elastic.Assembler.IntegrationTests/Class1.cs +++ /dev/null @@ -1,9 +0,0 @@ -// Licensed to Elasticsearch B.V under one or more agreements. -// 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 - -namespace Elastic.Assembler.IntegrationTests; - -public class Class1 -{ -} From 69a3c5c62cd84450de3e6d82e54ce0f83688820c Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Sun, 3 Aug 2025 11:20:40 +0200 Subject: [PATCH 05/17] ensure we log startup in case of failed tests --- Directory.Packages.props | 3 ++- .../AssembleFixture.cs | 23 +++++++++++++++++-- .../Elastic.Assembler.IntegrationTests.csproj | 1 + 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index e2241b85d..d785e6180 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -25,6 +25,7 @@ + @@ -92,4 +93,4 @@ - + \ No newline at end of file diff --git a/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs b/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs index 1595aa182..5053faf3e 100644 --- a/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs +++ b/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs @@ -6,6 +6,7 @@ using Aspire.Hosting.Testing; using Elastic.Documentation.ServiceDefaults; using FluentAssertions; +using InMemLogger; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -18,12 +19,17 @@ public class AssembleFixture : IAsyncLifetime { public DistributedApplication DistributedApplication { get; private set; } = null!; + public InMemoryLogger InMemoryLogger { get; private set; } = null!; + /// public async ValueTask InitializeAsync() { var builder = await DistributedApplicationTestingBuilder.CreateAsync(); _ = builder.Services.AddAppLogging(LogLevel.Information); + _ = builder.Services.AddLogging(c => c.AddXUnit()); + _ = builder.Services.AddLogging(c => c.AddInMemory()); DistributedApplication = await builder.BuildAsync(); + InMemoryLogger = DistributedApplication.Services.GetService()!; await DistributedApplication.StartAsync(); } @@ -38,7 +44,8 @@ public async ValueTask DisposeAsync() } -public class DatabaseTestClass1(AssembleFixture fixture, ITestOutputHelper output) + +public class DatabaseTestClass1(AssembleFixture fixture, ITestOutputHelper output) : IAsyncLifetime { [Fact] public async Task X() @@ -52,5 +59,17 @@ public async Task X() } - // ... + /// + public ValueTask DisposeAsync() + { + GC.SuppressFinalize(this); + if (TestContext.Current.TestState?.Result is TestResult.Passed) + return default; + foreach (var resource in fixture.InMemoryLogger.RecordedLogs) + output.WriteLine(resource.Message); + return default; + } + + /// + public ValueTask InitializeAsync() => default; } diff --git a/tests-integration/Elastic.Assembler.IntegrationTests/Elastic.Assembler.IntegrationTests.csproj b/tests-integration/Elastic.Assembler.IntegrationTests/Elastic.Assembler.IntegrationTests.csproj index ed79961c2..d81a39e9b 100644 --- a/tests-integration/Elastic.Assembler.IntegrationTests/Elastic.Assembler.IntegrationTests.csproj +++ b/tests-integration/Elastic.Assembler.IntegrationTests/Elastic.Assembler.IntegrationTests.csproj @@ -15,6 +15,7 @@ + From 5c483199f4ee27580c1596f143e350541f83d788 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 4 Aug 2025 11:13:50 +0200 Subject: [PATCH 06/17] LlmGatwewayAskAiGateway needs to be registered as scoped since it depends on scoped options --- .../ServicesExtension.cs | 2 +- .../Elastic.Assembler.IntegrationTests/AssembleFixture.cs | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/api/Elastic.Documentation.Api.Infrastructure/ServicesExtension.cs b/src/api/Elastic.Documentation.Api.Infrastructure/ServicesExtension.cs index c8e37f029..7ad66c446 100644 --- a/src/api/Elastic.Documentation.Api.Infrastructure/ServicesExtension.cs +++ b/src/api/Elastic.Documentation.Api.Infrastructure/ServicesExtension.cs @@ -104,8 +104,8 @@ private static void AddAskAiUsecase(IServiceCollection services, AppEnv appEnv) var logger = GetLogger(services); logger?.LogInformation("Configuring AskAi use case for environment {AppEnvironment}", appEnv); _ = services.AddSingleton(); - _ = services.AddSingleton, LlmGatewayAskAiGateway>(); _ = services.AddScoped(); _ = services.AddScoped(); + _ = services.AddScoped, LlmGatewayAskAiGateway>(); } } diff --git a/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs b/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs index 5053faf3e..18b13e8ec 100644 --- a/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs +++ b/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs @@ -40,8 +40,6 @@ public async ValueTask DisposeAsync() await DistributedApplication.DisposeAsync(); GC.SuppressFinalize(this); } - - } @@ -54,7 +52,6 @@ public async Task X() .WaitForResourceHealthyAsync("DocsBuilderServeStatic", cancellationToken: TestContext.Current.CancellationToken); var client = fixture.DistributedApplication.CreateHttpClient("DocsBuilderServeStatic", "http"); var root = await client.GetStringAsync("/", TestContext.Current.CancellationToken); - output.WriteLine(root); _ = root.Should().NotBeNullOrEmpty(); } @@ -63,8 +60,8 @@ public async Task X() public ValueTask DisposeAsync() { GC.SuppressFinalize(this); - if (TestContext.Current.TestState?.Result is TestResult.Passed) - return default; + // if (TestContext.Current.TestState?.Result is TestResult.Passed) + // return default; foreach (var resource in fixture.InMemoryLogger.RecordedLogs) output.WriteLine(resource.Message); return default; From 93656a9794e13178228d83150c89d95e4217e2ff Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 4 Aug 2025 12:17:24 +0200 Subject: [PATCH 07/17] Ensure we set default branch on CI to main To limit noise from clone-all --- .github/actions/bootstrap/action.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/actions/bootstrap/action.yml b/.github/actions/bootstrap/action.yml index 8a74e471d..169d50c22 100644 --- a/.github/actions/bootstrap/action.yml +++ b/.github/actions/bootstrap/action.yml @@ -18,6 +18,12 @@ runs: run: | git fetch --prune --unshallow --tags git tag --list + + - name: Git config + shell: bash + run: | + git config --global init.defaultBranch main + - uses: actions/setup-dotnet@v4 with: global-json-file: global.json @@ -37,4 +43,3 @@ runs: cache: npm cache-dependency-path: src/Elastic.Documentation.Site/package-lock.json node-version-file: .nvmrc - \ No newline at end of file From 97a57812d88b7131e21eac3548e9cd1ac8417108 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 4 Aug 2025 16:37:00 +0200 Subject: [PATCH 08/17] Support building only public repositories --- config/assembler.yml | 8 +- .../Assembler/AssemblyConfiguration.cs | 29 ++++++- .../Assembler/Repository.cs | 3 + .../ConfigurationFileProvider.cs | 80 +++++++++++++++++-- .../AppDefaultsExtensions.cs | 59 +++----------- .../GlobalCommandLine.cs | 47 +++++++++++ .../ServicesExtension.cs | 2 - .../Program.cs | 3 +- .../DocumentationTooling.cs | 9 +++ src/tooling/docs-assembler/AssembleContext.cs | 2 + src/tooling/docs-assembler/AssembleSources.cs | 5 +- .../Building/AssemblerCrossLinkFetcher.cs | 6 +- .../Cli/ContentSourceCommands.cs | 4 +- .../Links/NavigationPrefixChecker.cs | 5 +- .../Navigation/GlobalNavigationFile.cs | 9 ++- src/tooling/docs-assembler/Program.cs | 6 +- .../Sourcing/RepositorySourcesFetcher.cs | 11 +-- .../docs-builder/Http/DocumentationWebHost.cs | 2 +- .../docs-builder/Http/StaticWebHost.cs | 2 +- src/tooling/docs-builder/Program.cs | 6 +- .../AssembleFixture.cs | 11 ++- .../Elastic.Documentation.Aspire/AppHost.cs | 24 +++++- .../Elastic.Documentation.Aspire.csproj | 1 + .../AssemblerConfigurationTests.cs | 36 +++++++++ 24 files changed, 273 insertions(+), 97 deletions(-) create mode 100644 src/Elastic.Documentation/GlobalCommandLine.cs diff --git a/config/assembler.yml b/config/assembler.yml index c56fa05c4..21330a29f 100644 --- a/config/assembler.yml +++ b/config/assembler.yml @@ -94,6 +94,7 @@ references: elastic-otel-python: elastic-serverless-forwarder: integration-docs: + private: true integrations: logstash-docs-md: opentelemetry: @@ -104,7 +105,12 @@ references: # @elastic/admin-docs cloud-on-k8s: - cloud: *master + cloud: + current: master + next: master + edge: master + private: true + curator: *master ecctl: *master diff --git a/src/Elastic.Documentation.Configuration/Assembler/AssemblyConfiguration.cs b/src/Elastic.Documentation.Configuration/Assembler/AssemblyConfiguration.cs index 472b7715e..7e37ea96b 100644 --- a/src/Elastic.Documentation.Configuration/Assembler/AssemblyConfiguration.cs +++ b/src/Elastic.Documentation.Configuration/Assembler/AssemblyConfiguration.cs @@ -4,7 +4,6 @@ using System.Text.RegularExpressions; using Elastic.Documentation.Extensions; -using YamlDotNet.RepresentationModel; using YamlDotNet.Serialization; using YamlStaticContext = Elastic.Documentation.Configuration.Serialization.YamlStaticContext; @@ -13,9 +12,9 @@ namespace Elastic.Documentation.Configuration.Assembler; public record AssemblyConfiguration { public static AssemblyConfiguration Create(ConfigurationFileProvider provider) => - Deserialize(provider.AssemblerFile.ReadToEnd()); + Deserialize(provider.AssemblerFile.ReadToEnd(), skipPrivateRepositories: provider.SkipPrivateRepositories); - public static AssemblyConfiguration Deserialize(string yaml) + public static AssemblyConfiguration Deserialize(string yaml, bool skipPrivateRepositories = false) { var input = new StringReader(yaml); @@ -28,13 +27,28 @@ public static AssemblyConfiguration Deserialize(string yaml) var config = deserializer.Deserialize(input); foreach (var (name, r) in config.ReferenceRepositories) { + if (name == "cloud") + { + } var repository = RepositoryDefaults(r, name); config.ReferenceRepositories[name] = repository; } + var privateRepositories = config.ReferenceRepositories.Where(r => r.Value.Private).ToList(); + foreach (var (name, _) in privateRepositories) + { + if (skipPrivateRepositories) + _ = config.ReferenceRepositories.Remove(name); + } foreach (var (name, env) in config.Environments) env.Name = name; config.Narrative = RepositoryDefaults(config.Narrative, NarrativeRepository.RepositoryName); + + config.AvailableRepositories = config.ReferenceRepositories.Values + .Where(r => !r.Skip) + .Concat([config.Narrative]).ToDictionary(kvp => kvp.Name, kvp => kvp); + + config.PrivateRepositories = privateRepositories.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); return config; } catch (Exception e) @@ -80,6 +94,15 @@ private static TRepository RepositoryDefaults(TRepository r, string [YamlMember(Alias = "references")] public Dictionary ReferenceRepositories { get; set; } = []; + /// All available repositories, combines and and will filter private repositories if `skip-private-repositories` + /// is specified + [YamlIgnore] + public IReadOnlyDictionary AvailableRepositories { get; private set; } = new Dictionary(); + + /// Repositories marked as private, these are listed under if `--skip-private-repositories` is not specified + [YamlIgnore] + public IReadOnlyDictionary PrivateRepositories { get; private set; } = new Dictionary(); + [YamlMember(Alias = "environments")] public Dictionary Environments { get; set; } = []; diff --git a/src/Elastic.Documentation.Configuration/Assembler/Repository.cs b/src/Elastic.Documentation.Configuration/Assembler/Repository.cs index cabdbf837..389fc257d 100644 --- a/src/Elastic.Documentation.Configuration/Assembler/Repository.cs +++ b/src/Elastic.Documentation.Configuration/Assembler/Repository.cs @@ -48,6 +48,9 @@ public record Repository [YamlMember(Alias = "sparse_paths")] public string[] SparsePaths { get; set; } = ["docs"]; + [YamlMember(Alias = "private")] + public bool Private { get; set; } + public string GetBranch(ContentSource contentSource) => contentSource switch { ContentSource.Current => GitReferenceCurrent, diff --git a/src/Elastic.Documentation.Configuration/ConfigurationFileProvider.cs b/src/Elastic.Documentation.Configuration/ConfigurationFileProvider.cs index 31cb19e68..c5e8fdbfc 100644 --- a/src/Elastic.Documentation.Configuration/ConfigurationFileProvider.cs +++ b/src/Elastic.Documentation.Configuration/ConfigurationFileProvider.cs @@ -3,8 +3,11 @@ // See the LICENSE file in the project root for more information using System.IO.Abstractions; +using System.Text.RegularExpressions; +using Elastic.Documentation.Configuration.Assembler; using Microsoft.Extensions.DependencyInjection; using NetEscapades.EnumGenerators; +using YamlDotNet.RepresentationModel; namespace Elastic.Documentation.Configuration; @@ -16,7 +19,7 @@ public enum ConfigurationSource Embedded } -public class ConfigurationFileProvider +public partial class ConfigurationFileProvider { private readonly IFileSystem _fileSystem; private readonly string _assemblyName; @@ -24,10 +27,11 @@ public class ConfigurationFileProvider public ConfigurationSource ConfigurationSource { get; private set; } = ConfigurationSource.Embedded; public string? GitReference { get; } - public ConfigurationFileProvider(IFileSystem fileSystem) + public ConfigurationFileProvider(IFileSystem fileSystem, bool skipPrivateRepositories = false) { _fileSystem = fileSystem; _assemblyName = typeof(ConfigurationFileProvider).Assembly.GetName().Name!; + SkipPrivateRepositories = skipPrivateRepositories; TemporaryDirectory = fileSystem.Directory.CreateTempSubdirectory("docs-builder-config"); VersionFile = CreateTemporaryConfigurationFile("versions.yml"); @@ -39,9 +43,11 @@ public ConfigurationFileProvider(IFileSystem fileSystem) GitReference = _fileSystem.File.ReadAllText(path); } + public bool SkipPrivateRepositories { get; } + private IDirectoryInfo TemporaryDirectory { get; } - public IFileInfo NavigationFile { get; } + public IFileInfo NavigationFile { get; private set; } public IFileInfo VersionFile { get; } @@ -49,6 +55,63 @@ public ConfigurationFileProvider(IFileSystem fileSystem) public IFileInfo LegacyUrlMappingsFile { get; } + public IFileInfo CreateNavigationFile(IReadOnlyDictionary privateRepositories) + { + if (privateRepositories.Count == 0) + return NavigationFile; + + var targets = string.Join("|", privateRepositories.Keys); + + var tempFile = Path.Combine(TemporaryDirectory.FullName, "navigation.filtered.yml"); + if (_fileSystem.File.Exists(tempFile)) + return NavigationFile; + + var spacing = -1; + var reindenting = -1; + var breakingLine = string.Empty; + foreach (var l in _fileSystem.File.ReadAllLines(NavigationFile.FullName)) + { + var line = l; + if (spacing > -1 && !string.IsNullOrWhiteSpace(line) && !line.StartsWith(new string(' ', spacing), StringComparison.Ordinal)) + { + spacing = -1; + reindenting = -1; + } + + if (spacing != -1 && Regex.IsMatch(line, $@"^\s{{{spacing}}}\S")) + { + spacing = -1; + reindenting = -1; + } + + else if (spacing != -1 && Regex.IsMatch(line, $@"^(\s{{{spacing + 3},}})\S")) + { + var matches = Regex.Match(line, $@"^(?\s{{{spacing}}})(?.+)$"); + line = $"{new string(' ', Math.Max(0, spacing - 4))}{matches.Groups["remainder"].Value}"; + reindenting = spacing; + } + + else if (spacing == -1 && TocPrefixRegex().IsMatch(line)) + { + var matches = Regex.Match(line, $@"^(?\s+)-\s?toc:\s?(?:{targets})\:"); + if (matches.Success) + { + spacing = matches.Groups["spacing"].Value.Length; + breakingLine = line; + } + if (spacing == 0) + spacing = -1; + } + + if (spacing == -1 || reindenting > 0) + _fileSystem.File.AppendAllLines(tempFile, [line]); + } + NavigationFile = _fileSystem.FileInfo.New(tempFile); + return NavigationFile; + + + } + private IFileInfo CreateTemporaryConfigurationFile(string fileName) { using var stream = GetLocalOrEmbedded(fileName); @@ -90,14 +153,19 @@ private StreamReader GetEmbeddedStream(string fileName) private static string GetLocalPath(string file) => Path.Combine(LocalConfigurationDirectory, file); private static string GetAppDataPath(string file) => Path.Combine(AppDataConfigurationDirectory, file); + [GeneratedRegex(@"^\s+-?\s?toc:\s?")] + private static partial Regex TocPrefixRegex(); } public static class ConfigurationFileProviderServiceCollectionExtensions { - public static IServiceCollection AddConfigurationFileProvider(this IServiceCollection services, - Action configure) + public static IServiceCollection AddConfigurationFileProvider( + this IServiceCollection services, + bool skipPrivateRepositories, + Action configure + ) { - var provider = new ConfigurationFileProvider(new FileSystem()); + var provider = new ConfigurationFileProvider(new FileSystem(), skipPrivateRepositories); _ = services.AddSingleton(provider); configure(services, provider); return services; diff --git a/src/Elastic.Documentation.ServiceDefaults/AppDefaultsExtensions.cs b/src/Elastic.Documentation.ServiceDefaults/AppDefaultsExtensions.cs index 1212841e2..bcfda4fd1 100644 --- a/src/Elastic.Documentation.ServiceDefaults/AppDefaultsExtensions.cs +++ b/src/Elastic.Documentation.ServiceDefaults/AppDefaultsExtensions.cs @@ -2,10 +2,8 @@ // 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 Actions.Core.Extensions; using Elastic.Documentation.Configuration; using Elastic.Documentation.Configuration.Versions; -using Elastic.Documentation.Diagnostics; using Elastic.Documentation.ServiceDefaults.Logging; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -17,41 +15,32 @@ namespace Elastic.Documentation.ServiceDefaults; public static class AppDefaultsExtensions { - public static TBuilder AddAppDefaults(this TBuilder builder) where TBuilder : IHostApplicationBuilder + public static TBuilder AddDocumentationServiceDefaults(this TBuilder builder) where TBuilder : IHostApplicationBuilder { var args = Array.Empty(); - return builder.AddAppDefaults(ref args); + return builder.AddDocumentationServiceDefaults(ref args); } - public static TBuilder AddAppDefaults(this TBuilder builder, LogLevel defaultLogLevel) where TBuilder : IHostApplicationBuilder - { - var args = Array.Empty(); - return builder.AddAppDefaults(ref args, defaultLogLevel); - } - public static TBuilder AddAppDefaults(this TBuilder builder, ref string[] args, Action configure) where TBuilder : IHostApplicationBuilder => - builder.AddAppDefaults(ref args, null, configure); + public static TBuilder AddDocumentationServiceDefaults(this TBuilder builder, ref string[] args, Action configure) where TBuilder : IHostApplicationBuilder => + builder.AddDocumentationServiceDefaults(ref args, null, configure); - public static TBuilder AddAppDefaults(this TBuilder builder, ref string[] args, LogLevel? defaultLogLevel = null, Action? configure = null) where TBuilder : IHostApplicationBuilder + public static TBuilder AddDocumentationServiceDefaults(this TBuilder builder, ref string[] args, LogLevel? defaultLogLevel = null, Action? configure = null) where TBuilder : IHostApplicationBuilder { var logLevel = defaultLogLevel ?? LogLevel.Information; - ProcessCommandLineArguments(ref args, ref logLevel); + GlobalCommandLine.Process(ref args, ref logLevel, out var skipPrivateRepositories); var services = builder.Services; _ = services - .AddGitHubActionsCore() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddConfigurationFileProvider((s, p) => + .AddConfigurationFileProvider(skipPrivateRepositories, (s, p) => { _ = s.AddSingleton(p.CreateVersionConfiguration()); configure?.Invoke(s, p); }); - _ = builder.Services.AddAppLogging(logLevel); + _ = builder.Services.AddElasticDocumentationLogging(logLevel); return builder.AddServiceDefaults(); } - public static TServiceCollection AddAppLogging(this TServiceCollection services, LogLevel logLevel) + public static TServiceCollection AddElasticDocumentationLogging(this TServiceCollection services, LogLevel logLevel) where TServiceCollection : IServiceCollection { services.TryAddEnumerable(ServiceDescriptor.Singleton()); @@ -63,34 +52,4 @@ public static TServiceCollection AddAppLogging(this TService return services; } - private static void ProcessCommandLineArguments(ref string[] args, ref LogLevel defaultLogLevel) - { - var newArgs = new List(); - for (var i = 0; i < args.Length; i++) - { - if (args[i] == "--log-level") - { - if (args.Length > i + 1) - defaultLogLevel = GetLogLevel(args[i + 1]); - - i++; - } - else - newArgs.Add(args[i]); - } - - args = [.. newArgs]; - } - - private static LogLevel GetLogLevel(string? logLevel) => logLevel switch - { - "trace" => LogLevel.Trace, - "debug" => LogLevel.Debug, - "information" => LogLevel.Information, - "info" => LogLevel.Information, - "warning" => LogLevel.Warning, - "error" => LogLevel.Error, - "critical" => LogLevel.Critical, - _ => LogLevel.Information - }; } diff --git a/src/Elastic.Documentation/GlobalCommandLine.cs b/src/Elastic.Documentation/GlobalCommandLine.cs new file mode 100644 index 000000000..9ebedb554 --- /dev/null +++ b/src/Elastic.Documentation/GlobalCommandLine.cs @@ -0,0 +1,47 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// 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 Microsoft.Extensions.Logging; + +namespace Elastic.Documentation; + +public static class GlobalCommandLine +{ + public static void Process(ref string[] args, ref LogLevel defaultLogLevel, out bool skipPrivateRepositories) + { + skipPrivateRepositories = false; + var newArgs = new List(); + for (var i = 0; i < args.Length; i++) + { + if (args[i] == "--log-level") + { + if (args.Length > i + 1) + defaultLogLevel = GetLogLevel(args[i + 1]); + i++; + } + else if (args[i] == "--skip-private-repositories") + { + skipPrivateRepositories = true; + i++; + } + else + newArgs.Add(args[i]); + } + + args = [.. newArgs]; + } + + private static LogLevel GetLogLevel(string? logLevel) => logLevel switch + { + "trace" => LogLevel.Trace, + "debug" => LogLevel.Debug, + "information" => LogLevel.Information, + "info" => LogLevel.Information, + "warning" => LogLevel.Warning, + "error" => LogLevel.Error, + "critical" => LogLevel.Critical, + _ => LogLevel.Information + }; + +} diff --git a/src/api/Elastic.Documentation.Api.Infrastructure/ServicesExtension.cs b/src/api/Elastic.Documentation.Api.Infrastructure/ServicesExtension.cs index 7ad66c446..13c66738e 100644 --- a/src/api/Elastic.Documentation.Api.Infrastructure/ServicesExtension.cs +++ b/src/api/Elastic.Documentation.Api.Infrastructure/ServicesExtension.cs @@ -40,9 +40,7 @@ public static class ServicesExtension public static void AddElasticDocsApiUsecases(this IServiceCollection services, string? appEnvironment) { if (AppEnvExtensions.TryParse(appEnvironment, out var parsedEnvironment, true)) - { AddElasticDocsApiUsecases(services, parsedEnvironment); - } else { var logger = GetLogger(services); diff --git a/src/api/Elastic.Documentation.Api.Lambda/Program.cs b/src/api/Elastic.Documentation.Api.Lambda/Program.cs index 2a4ee9ff4..bd03e3d15 100644 --- a/src/api/Elastic.Documentation.Api.Lambda/Program.cs +++ b/src/api/Elastic.Documentation.Api.Lambda/Program.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.Text.Json; using System.Text.Json.Serialization; using Amazon.Lambda.APIGatewayEvents; using Amazon.Lambda.Serialization.SystemTextJson; @@ -12,7 +11,7 @@ var builder = WebApplication.CreateSlimBuilder(args); -builder.Services.AddAppLogging(LogLevel.Information); +builder.AddDocumentationServiceDefaults(ref args); builder.Services.AddAWSLambdaHosting(LambdaEventSource.RestApi, new SourceGeneratorLambdaJsonSerializer()); builder.Services.AddElasticDocsApiUsecases(Environment.GetEnvironmentVariable("ENVIRONMENT")); diff --git a/src/tooling/Elastic.Documentation.Tooling/DocumentationTooling.cs b/src/tooling/Elastic.Documentation.Tooling/DocumentationTooling.cs index 06c309d27..341db9003 100644 --- a/src/tooling/Elastic.Documentation.Tooling/DocumentationTooling.cs +++ b/src/tooling/Elastic.Documentation.Tooling/DocumentationTooling.cs @@ -10,6 +10,7 @@ using Elastic.Documentation.ServiceDefaults.Logging; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Console; @@ -17,4 +18,12 @@ namespace Elastic.Documentation.Tooling; public static class DocumentationTooling { + public static TBuilder AddDocumentationToolingDefaults(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + _ = builder.Services + .AddGitHubActionsCore() + .AddSingleton() + .AddSingleton(); + return builder; + } } diff --git a/src/tooling/docs-assembler/AssembleContext.cs b/src/tooling/docs-assembler/AssembleContext.cs index 2440b80a6..5cbf78901 100644 --- a/src/tooling/docs-assembler/AssembleContext.cs +++ b/src/tooling/docs-assembler/AssembleContext.cs @@ -31,6 +31,8 @@ public class AssembleContext /// This property is used to determine if the site should be indexed by search engines public bool AllowIndexing { get; init; } + public bool IgnorePrivateRepositories { get; init; } + public PublishEnvironment Environment { get; } public AssembleContext( diff --git a/src/tooling/docs-assembler/AssembleSources.cs b/src/tooling/docs-assembler/AssembleSources.cs index f0aa51606..63d926a79 100644 --- a/src/tooling/docs-assembler/AssembleSources.cs +++ b/src/tooling/docs-assembler/AssembleSources.cs @@ -16,7 +16,6 @@ using Elastic.Markdown.IO.Navigation; using Elastic.Markdown.Links.CrossLinks; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; using YamlDotNet.RepresentationModel; namespace Documentation.Assembler; @@ -39,6 +38,7 @@ public record TocConfigurationMapping public class AssembleSources { public AssembleContext AssembleContext { get; } + public FrozenDictionary AssembleSets { get; } public FrozenDictionary NavigationTocMappings { get; } @@ -154,7 +154,8 @@ static void ReadHistoryMappings(IDictionary> public static FrozenDictionary GetTocMappings(AssembleContext context) { var dictionary = new Dictionary(); - var reader = new YamlStreamReader(context.ConfigurationFileProvider.NavigationFile, context.Collector); + var file = context.ConfigurationFileProvider.CreateNavigationFile(context.Configuration.PrivateRepositories); + var reader = new YamlStreamReader(file, context.Collector); var entries = new List>(); foreach (var entry in reader.Read()) { diff --git a/src/tooling/docs-assembler/Building/AssemblerCrossLinkFetcher.cs b/src/tooling/docs-assembler/Building/AssemblerCrossLinkFetcher.cs index c6d9f74ca..5d1f091f8 100644 --- a/src/tooling/docs-assembler/Building/AssemblerCrossLinkFetcher.cs +++ b/src/tooling/docs-assembler/Building/AssemblerCrossLinkFetcher.cs @@ -19,7 +19,11 @@ public override async Task Fetch(Cancel ctx) var linkReferences = new Dictionary(); var linkIndexEntries = new Dictionary(); var declaredRepositories = new HashSet(); - var repositories = configuration.ReferenceRepositories.Values.Concat([configuration.Narrative]); + // We do want to always fetch cross-link data for all repositories. + // This is public information + var repositories = configuration.AvailableRepositories.Values + .Concat(configuration.PrivateRepositories.Values) + .ToList(); foreach (var repository in repositories) { diff --git a/src/tooling/docs-assembler/Cli/ContentSourceCommands.cs b/src/tooling/docs-assembler/Cli/ContentSourceCommands.cs index 9ff91f494..645bdb3e9 100644 --- a/src/tooling/docs-assembler/Cli/ContentSourceCommands.cs +++ b/src/tooling/docs-assembler/Cli/ContentSourceCommands.cs @@ -41,10 +41,10 @@ public async Task Validate(Cancel ctx = default) ILinkIndexReader linkIndexReader = Aws3LinkIndexReader.CreateAnonymous(); var fetcher = new AssemblerCrossLinkFetcher(logFactory, context.Configuration, context.Environment, linkIndexReader); var links = await fetcher.FetchLinkIndex(ctx); - var repositories = context.Configuration.ReferenceRepositories.Values.Concat([context.Configuration.Narrative]).ToList(); + var repositories = context.Configuration.AvailableRepositories; var reportPath = context.ConfigurationFileProvider.AssemblerFile; - foreach (var repository in repositories) + foreach (var repository in repositories.Values) { if (!links.Repositories.TryGetValue(repository.Name, out var registryMapping)) { diff --git a/src/tooling/docs-assembler/Links/NavigationPrefixChecker.cs b/src/tooling/docs-assembler/Links/NavigationPrefixChecker.cs index 36cd94fce..866527ba5 100644 --- a/src/tooling/docs-assembler/Links/NavigationPrefixChecker.cs +++ b/src/tooling/docs-assembler/Links/NavigationPrefixChecker.cs @@ -43,10 +43,7 @@ public NavigationPrefixChecker(ILoggerFactory logFactory, AssembleContext contex { _phantoms = GlobalNavigationFile.GetPhantomPrefixes(context); - _repositories = context.Configuration.ReferenceRepositories - .Values - .Concat([context.Configuration.Narrative]) - .Where(p => !p.Skip) + _repositories = context.Configuration.AvailableRepositories.Values .Select(r => r.Name) .ToImmutableHashSet(); diff --git a/src/tooling/docs-assembler/Navigation/GlobalNavigationFile.cs b/src/tooling/docs-assembler/Navigation/GlobalNavigationFile.cs index ffe72d4b2..472650402 100644 --- a/src/tooling/docs-assembler/Navigation/GlobalNavigationFile.cs +++ b/src/tooling/docs-assembler/Navigation/GlobalNavigationFile.cs @@ -27,7 +27,7 @@ public GlobalNavigationFile(AssembleContext context, AssembleSources assembleSou { _context = context; _assembleSources = assembleSources; - NavigationFile = context.ConfigurationFileProvider.NavigationFile; + NavigationFile = context.ConfigurationFileProvider.CreateNavigationFile(context.Configuration.PrivateRepositories); TableOfContents = Deserialize("toc"); Phantoms = Deserialize("phantoms"); ScopeDirectory = NavigationFile.Directory!; @@ -62,7 +62,8 @@ public static ImmutableHashSet GetPhantomPrefixes(AssembleContext context) private static ImmutableHashSet GetSourceUris(string key, AssembleContext context) { - var reader = new YamlStreamReader(context.ConfigurationFileProvider.NavigationFile, context.Collector); + var navigationFile = context.ConfigurationFileProvider.CreateNavigationFile(context.Configuration.PrivateRepositories); + var reader = new YamlStreamReader(navigationFile, context.Collector); var set = new HashSet(); foreach (var entry in reader.Read()) { @@ -149,10 +150,10 @@ public void EmitWarning(string message) => public void EmitError(string message) => _context.Collector.EmitWarning(NavigationFile, message); - private IReadOnlyCollection Deserialize(string key) { - var reader = new YamlStreamReader(NavigationFile, _context.Collector); + var navigationFile = _context.ConfigurationFileProvider.CreateNavigationFile(_context.Configuration.PrivateRepositories); + var reader = new YamlStreamReader(navigationFile, _context.Collector); try { foreach (var entry in reader.Read()) diff --git a/src/tooling/docs-assembler/Program.cs b/src/tooling/docs-assembler/Program.cs index 881c9dbb7..24a8b9527 100644 --- a/src/tooling/docs-assembler/Program.cs +++ b/src/tooling/docs-assembler/Program.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information using System.Diagnostics.CodeAnalysis; -using System.Reflection.Metadata; using Actions.Core.Services; using ConsoleAppFramework; using Documentation.Assembler.Cli; @@ -16,10 +15,11 @@ using Microsoft.Extensions.Logging; var builder = Host.CreateApplicationBuilder() - .AddAppDefaults(ref args, (s, p) => + .AddDocumentationServiceDefaults(ref args, (s, p) => { _ = s.AddSingleton(AssemblyConfiguration.Create(p)); - }); + }) + .AddDocumentationToolingDefaults(); var app = builder.ToConsoleAppBuilder(); diff --git a/src/tooling/docs-assembler/Sourcing/RepositorySourcesFetcher.cs b/src/tooling/docs-assembler/Sourcing/RepositorySourcesFetcher.cs index 64cc5770d..74521cf57 100644 --- a/src/tooling/docs-assembler/Sourcing/RepositorySourcesFetcher.cs +++ b/src/tooling/docs-assembler/Sourcing/RepositorySourcesFetcher.cs @@ -25,14 +25,14 @@ public class AssemblerRepositorySourcer(ILoggerFactory logFactory, AssembleConte public CheckoutResult GetAll() { var fs = context.ReadFileSystem; - var repositories = Configuration.ReferenceRepositories.Values.Concat([Configuration.Narrative]); + var repositories = Configuration.AvailableRepositories; var checkouts = new List(); var linkRegistrySnapshotPath = Path.Combine(context.CheckoutDirectory.FullName, CheckoutResult.LinkRegistrySnapshotFileName); if (!fs.File.Exists(linkRegistrySnapshotPath)) throw new FileNotFoundException("Link-index snapshot not found. Run the clone-all command first.", linkRegistrySnapshotPath); var linkRegistrySnapshotStr = File.ReadAllText(linkRegistrySnapshotPath); var linkRegistry = LinkRegistry.Deserialize(linkRegistrySnapshotStr); - foreach (var repo in repositories) + foreach (var repo in repositories.Values) { var checkoutFolder = fs.DirectoryInfo.New(Path.Combine(context.CheckoutDirectory.FullName, repo.Name)); IGitRepository gitFacade = new SingleCommitOptimizedGitRepository(context.Collector, checkoutFolder); @@ -68,12 +68,7 @@ public async Task CloneAll(bool fetchLatest, Cancel ctx = defaul ILinkIndexReader linkIndexReader = Aws3LinkIndexReader.CreateAnonymous(); var linkRegistry = await linkIndexReader.GetRegistry(ctx); - var repositories = new Dictionary(Configuration.ReferenceRepositories) - { - { NarrativeRepository.RepositoryName, Configuration.Narrative } - }; - - await Parallel.ForEachAsync(repositories, + await Parallel.ForEachAsync(Configuration.AvailableRepositories, new ParallelOptions { CancellationToken = ctx, diff --git a/src/tooling/docs-builder/Http/DocumentationWebHost.cs b/src/tooling/docs-builder/Http/DocumentationWebHost.cs index 0cceb5803..2ab0c6289 100644 --- a/src/tooling/docs-builder/Http/DocumentationWebHost.cs +++ b/src/tooling/docs-builder/Http/DocumentationWebHost.cs @@ -41,7 +41,7 @@ public DocumentationWebHost(ILoggerFactory logFactory, string? path, int port, I { _writeFileSystem = writeFs; var builder = WebApplication.CreateSlimBuilder(); - _ = builder.AddAppDefaults(); + _ = builder.AddDocumentationServiceDefaults(); builder.Services.AddElasticDocsApiUsecases("dev"); _ = builder.Logging diff --git a/src/tooling/docs-builder/Http/StaticWebHost.cs b/src/tooling/docs-builder/Http/StaticWebHost.cs index cfefb0c5f..dd63cb5df 100644 --- a/src/tooling/docs-builder/Http/StaticWebHost.cs +++ b/src/tooling/docs-builder/Http/StaticWebHost.cs @@ -26,7 +26,7 @@ public StaticWebHost(int port) ContentRootPath = contentRoot }); - _ = builder.AddAppDefaults(); + _ = builder.AddDocumentationServiceDefaults(); _ = builder.Logging .AddFilter("Microsoft.AspNetCore.Hosting.Diagnostics", LogLevel.Error) diff --git a/src/tooling/docs-builder/Program.cs b/src/tooling/docs-builder/Program.cs index b283bff2d..ddd76f905 100644 --- a/src/tooling/docs-builder/Program.cs +++ b/src/tooling/docs-builder/Program.cs @@ -3,16 +3,20 @@ // See the LICENSE file in the project root for more information using System.Diagnostics.CodeAnalysis; +using Actions.Core.Extensions; using ConsoleAppFramework; using Documentation.Builder.Cli; +using Elastic.Documentation.Diagnostics; using Elastic.Documentation.ServiceDefaults; using Elastic.Documentation.Tooling; using Elastic.Documentation.Tooling.Filters; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; var builder = Host.CreateApplicationBuilder() - .AddAppDefaults(ref args); + .AddDocumentationServiceDefaults(ref args) + .AddDocumentationToolingDefaults(); var app = builder.ToConsoleAppBuilder(); diff --git a/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs b/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs index 18b13e8ec..489a73489 100644 --- a/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs +++ b/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs @@ -24,8 +24,15 @@ public class AssembleFixture : IAsyncLifetime /// public async ValueTask InitializeAsync() { - var builder = await DistributedApplicationTestingBuilder.CreateAsync(); - _ = builder.Services.AddAppLogging(LogLevel.Information); + var builder = await DistributedApplicationTestingBuilder.CreateAsync( + ["--skip-private-repositories"], + (options, settings) => + { + options.DisableDashboard = true; + options.AllowUnsecuredTransport = true; + } + ); + _ = builder.Services.AddElasticDocumentationLogging(LogLevel.Information); _ = builder.Services.AddLogging(c => c.AddXUnit()); _ = builder.Services.AddLogging(c => c.AddInMemory()); DistributedApplication = await builder.BuildAsync(); diff --git a/tests-integration/Elastic.Documentation.Aspire/AppHost.cs b/tests-integration/Elastic.Documentation.Aspire/AppHost.cs index 61a4013aa..fdb1848ad 100644 --- a/tests-integration/Elastic.Documentation.Aspire/AppHost.cs +++ b/tests-integration/Elastic.Documentation.Aspire/AppHost.cs @@ -2,17 +2,33 @@ // 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 Elastic.Documentation; +using Microsoft.Extensions.Logging; + +var logLevel = LogLevel.Information; +GlobalCommandLine.Process(ref args, ref logLevel, out var skipPrivateRepositories); +var globalArguments = new List(); +if (skipPrivateRepositories) + globalArguments.Add("--skip-private-repositories"); + +if (logLevel != LogLevel.Information) +{ + globalArguments.Add("--log-level"); + globalArguments.Add(logLevel.ToString()); +} + var builder = DistributedApplication.CreateBuilder(args); -var cloneAll = builder.AddProject("DocsAssemblerCloneAll").WithArgs("repo", "clone-all"); +var cloneAll = builder.AddProject("DocsAssemblerCloneAll").WithArgs(["repo", "clone-all", .. globalArguments]); -var buildAll = builder.AddProject("DocsAssemblerBuildAll").WithArgs("repo", "build-all").WaitForCompletion(cloneAll); +var buildAll = builder.AddProject("DocsAssemblerBuildAll").WithArgs(["repo", "build-all", .. globalArguments]) + .WaitForCompletion(cloneAll); -var api = builder.AddProject("ApiLambda"); +var api = builder.AddProject("ApiLambda").WithArgs(globalArguments); var serveStatic = builder.AddProject("DocsBuilderServeStatic") .WithHttpEndpoint(port: 4000, isProxied: false) - .WithArgs("serve-static") + .WithArgs(["serve-static", .. globalArguments]) .WithHttpHealthCheck("/", 200) .WaitForCompletion(buildAll); diff --git a/tests-integration/Elastic.Documentation.Aspire/Elastic.Documentation.Aspire.csproj b/tests-integration/Elastic.Documentation.Aspire/Elastic.Documentation.Aspire.csproj index 8c3d221d6..44282aa75 100644 --- a/tests-integration/Elastic.Documentation.Aspire/Elastic.Documentation.Aspire.csproj +++ b/tests-integration/Elastic.Documentation.Aspire/Elastic.Documentation.Aspire.csproj @@ -18,6 +18,7 @@ + diff --git a/tests/docs-assembler.Tests/src/docs-assembler.Tests/AssemblerConfigurationTests.cs b/tests/docs-assembler.Tests/src/docs-assembler.Tests/AssemblerConfigurationTests.cs index b232b9dc0..8504d7bd1 100644 --- a/tests/docs-assembler.Tests/src/docs-assembler.Tests/AssemblerConfigurationTests.cs +++ b/tests/docs-assembler.Tests/src/docs-assembler.Tests/AssemblerConfigurationTests.cs @@ -10,6 +10,38 @@ namespace Documentation.Assembler.Tests; +public class PublicOnlyAssemblerConfigurationTests +{ + private DiagnosticsCollector Collector { get; } + private AssembleContext Context { get; } + private FileSystem FileSystem { get; } + private IDirectoryInfo CheckoutDirectory { get; set; } + public PublicOnlyAssemblerConfigurationTests() + { + FileSystem = new FileSystem(); + CheckoutDirectory = FileSystem.DirectoryInfo.New( + FileSystem.Path.Combine(Paths.GetSolutionDirectory()!.FullName, ".artifacts", "checkouts") + ); + Collector = new DiagnosticsCollector([]); + var configurationFileProvider = new ConfigurationFileProvider(FileSystem, skipPrivateRepositories: true); + var config = AssemblyConfiguration.Create(configurationFileProvider); + Context = new AssembleContext(config, configurationFileProvider, "dev", Collector, FileSystem, FileSystem, CheckoutDirectory.FullName, null); + } + + [Fact] + public void ReadsPrivateRepositories() + { + var config = Context.Configuration; + config.ReferenceRepositories.Should().NotBeEmpty().And.NotContainKey("cloud"); + config.PrivateRepositories.Should().NotBeEmpty().And.ContainKey("cloud"); + var cloud = config.PrivateRepositories["cloud"]; + cloud.Should().NotBeNull(); + cloud.GitReferenceCurrent.Should().NotBeNullOrEmpty() + .And.Be("master"); + } + +} + public class AssemblerConfigurationTests { private DiagnosticsCollector Collector { get; } @@ -76,5 +108,9 @@ public void ReadsVersions() var beats = config.ReferenceRepositories["beats"]; beats.GitReferenceCurrent.Should().NotBeNullOrEmpty() .And.NotBe("main"); + + var cloud = config.ReferenceRepositories["cloud"]; + cloud.GitReferenceCurrent.Should().NotBeNullOrEmpty() + .And.Be("master"); } } From 174b904c5a4a7e3ba5dcd29a3413b2d5b4bf4c5f Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 4 Aug 2025 16:46:02 +0200 Subject: [PATCH 09/17] update test names --- .../AssembleFixture.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs b/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs index 489a73489..dab428366 100644 --- a/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs +++ b/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs @@ -10,12 +10,12 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -[assembly: CaptureConsole, AssemblyFixture(typeof(Elastic.Assembler.IntegrationTests.AssembleFixture))] +[assembly: CaptureConsole, AssemblyFixture(typeof(Elastic.Assembler.IntegrationTests.DocumentationFixture))] namespace Elastic.Assembler.IntegrationTests; -public class AssembleFixture : IAsyncLifetime +public class DocumentationFixture : IAsyncLifetime { public DistributedApplication DistributedApplication { get; private set; } = null!; @@ -50,10 +50,10 @@ public async ValueTask DisposeAsync() } -public class DatabaseTestClass1(AssembleFixture fixture, ITestOutputHelper output) : IAsyncLifetime +public class ServeStaticTests(DocumentationFixture fixture, ITestOutputHelper output) : IAsyncLifetime { [Fact] - public async Task X() + public async Task AssertRequestToRootReturnsData() { _ = await fixture.DistributedApplication.ResourceNotifications .WaitForResourceHealthyAsync("DocsBuilderServeStatic", cancellationToken: TestContext.Current.CancellationToken); @@ -67,8 +67,8 @@ public async Task X() public ValueTask DisposeAsync() { GC.SuppressFinalize(this); - // if (TestContext.Current.TestState?.Result is TestResult.Passed) - // return default; + if (TestContext.Current.TestState?.Result is TestResult.Passed) + return default; foreach (var resource in fixture.InMemoryLogger.RecordedLogs) output.WriteLine(resource.Message); return default; From 0511b37b4f23f568442f51b90dd4adf12ac83aab Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 4 Aug 2025 16:51:04 +0200 Subject: [PATCH 10/17] format --- .../AssembleFixture.cs | 4 +-- .../Elastic.Assembler.IntegrationTests.csproj | 30 +++++++++---------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs b/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs index dab428366..8577ba5e7 100644 --- a/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs +++ b/tests-integration/Elastic.Assembler.IntegrationTests/AssembleFixture.cs @@ -14,7 +14,6 @@ namespace Elastic.Assembler.IntegrationTests; - public class DocumentationFixture : IAsyncLifetime { public DistributedApplication DistributedApplication { get; private set; } = null!; @@ -49,7 +48,6 @@ public async ValueTask DisposeAsync() } } - public class ServeStaticTests(DocumentationFixture fixture, ITestOutputHelper output) : IAsyncLifetime { [Fact] @@ -68,7 +66,7 @@ public ValueTask DisposeAsync() { GC.SuppressFinalize(this); if (TestContext.Current.TestState?.Result is TestResult.Passed) - return default; + return default; foreach (var resource in fixture.InMemoryLogger.RecordedLogs) output.WriteLine(resource.Message); return default; diff --git a/tests-integration/Elastic.Assembler.IntegrationTests/Elastic.Assembler.IntegrationTests.csproj b/tests-integration/Elastic.Assembler.IntegrationTests/Elastic.Assembler.IntegrationTests.csproj index d81a39e9b..563a928ac 100644 --- a/tests-integration/Elastic.Assembler.IntegrationTests/Elastic.Assembler.IntegrationTests.csproj +++ b/tests-integration/Elastic.Assembler.IntegrationTests/Elastic.Assembler.IntegrationTests.csproj @@ -1,21 +1,21 @@  - - net9.0 - enable - enable - + + net9.0 + enable + enable + - - - - - - + + + + + + - - - - + + + + From 4fcb099558db94b2659db0ea62b12bd5a7a25e94 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 4 Aug 2025 16:55:28 +0200 Subject: [PATCH 11/17] ensure we only mutate navigation if --skip-private-repositories is actually specified --- .../ConfigurationFileProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Elastic.Documentation.Configuration/ConfigurationFileProvider.cs b/src/Elastic.Documentation.Configuration/ConfigurationFileProvider.cs index c5e8fdbfc..3a9bb609e 100644 --- a/src/Elastic.Documentation.Configuration/ConfigurationFileProvider.cs +++ b/src/Elastic.Documentation.Configuration/ConfigurationFileProvider.cs @@ -57,7 +57,7 @@ public ConfigurationFileProvider(IFileSystem fileSystem, bool skipPrivateReposit public IFileInfo CreateNavigationFile(IReadOnlyDictionary privateRepositories) { - if (privateRepositories.Count == 0) + if (privateRepositories.Count == 0 || !SkipPrivateRepositories) return NavigationFile; var targets = string.Join("|", privateRepositories.Keys); From 72cda1614e9add75af6acc167aeb59a8c52a5bd0 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 4 Aug 2025 16:55:52 +0200 Subject: [PATCH 12/17] formatting --- .../ConfigurationFileProvider.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Elastic.Documentation.Configuration/ConfigurationFileProvider.cs b/src/Elastic.Documentation.Configuration/ConfigurationFileProvider.cs index 3a9bb609e..7edc6ccd8 100644 --- a/src/Elastic.Documentation.Configuration/ConfigurationFileProvider.cs +++ b/src/Elastic.Documentation.Configuration/ConfigurationFileProvider.cs @@ -68,7 +68,6 @@ public IFileInfo CreateNavigationFile(IReadOnlyDictionary pr var spacing = -1; var reindenting = -1; - var breakingLine = string.Empty; foreach (var l in _fileSystem.File.ReadAllLines(NavigationFile.FullName)) { var line = l; @@ -95,10 +94,7 @@ public IFileInfo CreateNavigationFile(IReadOnlyDictionary pr { var matches = Regex.Match(line, $@"^(?\s+)-\s?toc:\s?(?:{targets})\:"); if (matches.Success) - { spacing = matches.Groups["spacing"].Value.Length; - breakingLine = line; - } if (spacing == 0) spacing = -1; } From dfbd4af468e5af92f7f975d1155503136a55e7e4 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 4 Aug 2025 17:00:21 +0200 Subject: [PATCH 13/17] comment --- .../ConfigurationFileProvider.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Elastic.Documentation.Configuration/ConfigurationFileProvider.cs b/src/Elastic.Documentation.Configuration/ConfigurationFileProvider.cs index 7edc6ccd8..045e6832f 100644 --- a/src/Elastic.Documentation.Configuration/ConfigurationFileProvider.cs +++ b/src/Elastic.Documentation.Configuration/ConfigurationFileProvider.cs @@ -66,6 +66,8 @@ public IFileInfo CreateNavigationFile(IReadOnlyDictionary pr if (_fileSystem.File.Exists(tempFile)) return NavigationFile; + // This routine removes `toc: `'s linking to private repositories and reindents any later lines if needed. + // This will make any public children in the nav move up one place. var spacing = -1; var reindenting = -1; foreach (var l in _fileSystem.File.ReadAllLines(NavigationFile.FullName)) From 2195a0fd9383b189fd2126d8a467f1032621687d Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 4 Aug 2025 17:42:43 +0200 Subject: [PATCH 14/17] Separate integration tests --- .github/workflows/ci.yml | 29 ++++++++++++++++++++++++++++- build/CommandLine.fs | 22 ++++++++++++++++++---- build/Targets.fs | 16 +++++++++++++--- 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b3cfbe80..9341bc3ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,7 +91,34 @@ jobs: run: dotnet run --project build -c release - name: Test - run: dotnet run --project build -c release -- test + run: dotnet run --project build -c release -- unit-test - name: Publish AOT run: dotnet run --project build -c release -- publishbinaries + + integration: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - macos-latest + - windows-latest + steps: + - uses: actions/checkout@v4 + + - name: Bootstrap Action Workspace + id: bootstrap + uses: ./.github/actions/bootstrap + + - name: Free Disk Space + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 + with: + tool-cache: false + + - name: Install Aspire workload + run: dotnet workload install aspire + + - name: Integration Tests + run: dotnet run --project build -c release -- integrate diff --git a/build/CommandLine.fs b/build/CommandLine.fs index d3244adb8..87feb1d96 100644 --- a/build/CommandLine.fs +++ b/build/CommandLine.fs @@ -9,13 +9,22 @@ open Microsoft.FSharp.Reflection open System open Bullseye +type TestSuite = All | Unit | Integration + with + member this.SuitName = + match FSharpValue.GetUnionFields(this, typeof) with + | case, _ -> case.Name.ToLowerInvariant() + type Build = | [] Clean | [] Version | [] Compile | [] Build + | [] Test - + | [] Unit_Test + | [] Integrate + | [] Format | [] Watch @@ -33,6 +42,7 @@ type Build = | [] Single_Target | [] Token of string | [] Skip_Dirty_Check + | [] Test_Suite of TestSuite with interface IArgParserTemplate with member this.Usage = @@ -41,8 +51,11 @@ with | Clean -> "clean known output locations" | Version -> "print version information" | Build -> "Run build" - - | Test -> "runs a clean build and then runs all the tests " + + | Unit_Test -> "alias to providing: test --test-suite=unit" + | Integrate -> "alias to providing: test --test-suite=integration" + | Test -> "runs a clean build and then runs all the tests unless --test-suite is provided" + | Release -> "runs build, tests, and create and validates the packages shy of publishing them" | Publish -> "Publishes artifacts" | Format -> "runs dotnet format" @@ -62,6 +75,7 @@ with | Single_Target -> "Runs the provided sub command without running their dependencies" | Token _ -> "Token to be used to authenticate with github" | Skip_Dirty_Check -> "Skip the clean checkout check that guards the release/publish targets" + | Test_Suite _ -> "Specify the test suite to run, defaults to all" member this.StepName = match FSharpValue.GetUnionFields(this, typeof) with @@ -87,4 +101,4 @@ with let dependsOn = if singleTarget then [] else dependsOn let steps = dependsOn @ composedOf |> List.map _.StepName - Targets.Target(target.StepName, steps, Action(fun _ -> action parsed)) \ No newline at end of file + Targets.Target(target.StepName, steps, Action(fun _ -> action parsed)) diff --git a/build/Targets.fs b/build/Targets.fs index efc5f7852..47baaf75a 100644 --- a/build/Targets.fs +++ b/build/Targets.fs @@ -107,10 +107,17 @@ let private publishContainers _ = createImage "docs-builder" createImage "docs-assembler" -let private runTests _ = +let private runTests (testSuite: TestSuite) _ = + let testFilter = + match testSuite with + | All -> [] + | Unit -> ["--filter"; "FullyQualifiedName~.Tests"] + | Integration -> ["--filter"; "FullyQualifiedName~.IntegrationTests"] + exec { run "dotnet" ( ["test"; "-c"; "release"; "--no-restore"; "--no-build"; "--logger"; "GitHubActions"] + @ testFilter @ ["--"; "RunConfiguration.CollectSourceInformation=true"] ) } @@ -132,8 +139,10 @@ let Setup (parsed:ParseResults) = Build.Cmd [Clean; Lint; Compile] [] build - | Test -> Build.Cmd [Compile] [] runTests - + | Test -> Build.Cmd [Compile] [] <| runTests TestSuite.All + | Unit_Test -> Build.Cmd [Compile] [] <| runTests TestSuite.Unit + | Integrate -> Build.Cmd [Compile] [] <| runTests TestSuite.Integration + | Release -> Build.Cmd [PristineCheck; Build] @@ -159,6 +168,7 @@ let Setup (parsed:ParseResults) = // flags | Single_Target + | Test_Suite _ | Token _ | Skip_Dirty_Check -> Build.Ignore From e3ebe00ba09e110a1976a79c83c2ce2f867b6614 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 4 Aug 2025 17:52:13 +0200 Subject: [PATCH 15/17] update free disk pace --- .github/workflows/ci.yml | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9341bc3ad..8be8172c2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -98,25 +98,18 @@ jobs: integration: runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - os: - - ubuntu-latest - - macos-latest - - windows-latest steps: - uses: actions/checkout@v4 - - name: Bootstrap Action Workspace - id: bootstrap - uses: ./.github/actions/bootstrap - - name: Free Disk Space uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 with: tool-cache: false + - name: Bootstrap Action Workspace + id: bootstrap + uses: ./.github/actions/bootstrap + - name: Install Aspire workload run: dotnet workload install aspire From c12aa940d1bea051749906360cd21fb918c55eea Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 4 Aug 2025 17:52:47 +0200 Subject: [PATCH 16/17] keep dotnet --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8be8172c2..84095eea5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -105,6 +105,7 @@ jobs: uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 with: tool-cache: false + dotnet: true - name: Bootstrap Action Workspace id: bootstrap From f4a4d29ba5f09b0a451d9491e1db2eb2582a392a Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 4 Aug 2025 18:33:47 +0200 Subject: [PATCH 17/17] Disable integration tests temporarily --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 84095eea5..612b835d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -97,6 +97,7 @@ jobs: run: dotnet run --project build -c release -- publishbinaries integration: + if: false runs-on: ubuntu-latest steps: - uses: actions/checkout@v4