From 44ff26cf8d8ef996d70bd5d4729003c4e300d069 Mon Sep 17 00:00:00 2001 From: lcawl Date: Tue, 24 Feb 2026 12:47:19 -0800 Subject: [PATCH] Fix changelog bundle --directory --- .../Bundling/ChangelogBundlingService.cs | 29 ++++---- .../docs-builder/Commands/ChangelogCommand.cs | 2 +- .../Changelogs/BundleChangelogsTests.cs | 67 +++++++++++++++++-- 3 files changed, 78 insertions(+), 20 deletions(-) diff --git a/src/services/Elastic.Changelog/Bundling/ChangelogBundlingService.cs b/src/services/Elastic.Changelog/Bundling/ChangelogBundlingService.cs index c72ca461c..73cb06ffa 100644 --- a/src/services/Elastic.Changelog/Bundling/ChangelogBundlingService.cs +++ b/src/services/Elastic.Changelog/Bundling/ChangelogBundlingService.cs @@ -24,7 +24,10 @@ namespace Elastic.Changelog.Bundling; /// public record BundleChangelogsArguments { - public required string Directory { get; init; } + /// + /// Directory containing changelog YAML files. null = use config default. + /// + public string? Directory { get; init; } public string? Output { get; init; } public bool All { get; init; } public IReadOnlyList? InputProducts { get; init; } @@ -137,16 +140,19 @@ public async Task BundleChangelogs(IDiagnosticsCollector collector, Bundle issuesToMatch = issueFilterResult.IssuesToMatch; } + // Directory is resolved by ApplyConfigDefaults (never null at this point) + var directory = input.Directory!; + // Determine output path - var outputPath = input.Output ?? _fileSystem.Path.Combine(input.Directory, "changelog-bundle.yaml"); + var outputPath = input.Output ?? _fileSystem.Path.Combine(directory, "changelog-bundle.yaml"); // Discover changelog files var fileDiscovery = new ChangelogFileDiscovery(_fileSystem, _logger); - var yamlFiles = await fileDiscovery.DiscoverChangelogFilesAsync(input.Directory, outputPath, ctx); + var yamlFiles = await fileDiscovery.DiscoverChangelogFilesAsync(directory, outputPath, ctx); if (yamlFiles.Count == 0) { - collector.EmitError(input.Directory, "No YAML files found in directory"); + collector.EmitError(directory, "No YAML files found in directory"); return false; } @@ -269,7 +275,7 @@ public async Task BundleChangelogs(IDiagnosticsCollector collector, Bundle string? outputPath = null; if (!string.IsNullOrWhiteSpace(outputPattern)) { - var outputDir = config.Bundle.OutputDirectory ?? input.OutputDirectory ?? input.Directory; + var outputDir = config.Bundle.OutputDirectory ?? input.OutputDirectory ?? input.Directory ?? _fileSystem.Directory.GetCurrentDirectory(); outputPath = _fileSystem.Path.Combine(outputDir, outputPattern); } @@ -324,16 +330,11 @@ private static List ParseProfileProducts(string pattern) private static BundleChangelogsArguments ApplyConfigDefaults(BundleChangelogsArguments input, ChangelogConfiguration? config) { - if (config?.Bundle == null) - return input; + // Apply directory: CLI takes precedence. Only use config when --directory not specified. + var directory = input.Directory ?? config?.Bundle?.Directory ?? Directory.GetCurrentDirectory(); - // Apply directory default if not specified - var directory = input.Directory; - if ((string.IsNullOrWhiteSpace(directory) || directory == Directory.GetCurrentDirectory()) - && !string.IsNullOrWhiteSpace(config.Bundle.Directory)) - { - directory = config.Bundle.Directory; - } + if (config?.Bundle == null) + return input with { Directory = directory }; // Apply output default when --output not specified: use bundle.output_directory if set var output = input.Output; diff --git a/src/tooling/docs-builder/Commands/ChangelogCommand.cs b/src/tooling/docs-builder/Commands/ChangelogCommand.cs index 7329b9651..4c961ca77 100644 --- a/src/tooling/docs-builder/Commands/ChangelogCommand.cs +++ b/src/tooling/docs-builder/Commands/ChangelogCommand.cs @@ -627,7 +627,7 @@ public async Task Bundle( var input = new BundleChangelogsArguments { - Directory = directory ?? Directory.GetCurrentDirectory(), + Directory = directory, Output = processedOutput, All = all, InputProducts = inputProducts, diff --git a/tests/Elastic.Changelog.Tests/Changelogs/BundleChangelogsTests.cs b/tests/Elastic.Changelog.Tests/Changelogs/BundleChangelogsTests.cs index 701091d6f..6fa23d772 100644 --- a/tests/Elastic.Changelog.Tests/Changelogs/BundleChangelogsTests.cs +++ b/tests/Elastic.Changelog.Tests/Changelogs/BundleChangelogsTests.cs @@ -2079,11 +2079,10 @@ public async Task BundleChangelogs_WithConfigOutputDirectory_WhenOutputNotSpecif } [Fact] - public async Task BundleChangelogs_WithConfigDirectory_WhenDirectoryIsCurrentDirectory_UsesConfigDirectory() + public async Task BundleChangelogs_WithConfigDirectory_WhenDirectoryNotSpecified_UsesConfigDirectory() { - // Arrange - When --directory is not specified (current directory), use bundle.directory from config if set + // Arrange - When --directory is not specified (null), use bundle.directory from config if set - var currentDir = Directory.GetCurrentDirectory(); var outputDir = FileSystem.Path.Combine(FileSystem.Path.GetTempPath(), Guid.NewGuid().ToString()); FileSystem.Directory.CreateDirectory(outputDir); @@ -2116,13 +2115,13 @@ public async Task BundleChangelogs_WithConfigDirectory_WhenDirectoryIsCurrentDir var input = new BundleChangelogsArguments { - Directory = currentDir, + Directory = null, Config = configPath, Output = null, All = true }; - // Act - Directory equals GetCurrentDirectory(), so ApplyConfigDefaults should use config.Bundle.Directory + // Act - Directory not specified, so ApplyConfigDefaults uses config.Bundle.Directory var result = await ServiceWithConfig.BundleChangelogs(Collector, input, TestContext.Current.CancellationToken); // Assert @@ -2137,6 +2136,64 @@ public async Task BundleChangelogs_WithConfigDirectory_WhenDirectoryIsCurrentDir bundleContent.Should().Contain("name: 1755268130-feature.yaml"); } + [Fact] + public async Task BundleChangelogs_WithExplicitDirectory_OverridesConfigDirectory() + { + // Arrange - config has directory pointing elsewhere, but CLI passes --directory explicitly. + // The explicit CLI value must win (e.g. --directory . when cwd has changelogs). + + var configDir = FileSystem.Path.Combine(FileSystem.Path.GetTempPath(), Guid.NewGuid().ToString()); + FileSystem.Directory.CreateDirectory(configDir); + var outputDir = FileSystem.Path.Combine(FileSystem.Path.GetTempPath(), Guid.NewGuid().ToString()); + FileSystem.Directory.CreateDirectory(outputDir); + + // language=yaml + var configContent = + $""" + bundle: + directory: "{configDir.Replace("\\", "/")}" + output_directory: "{outputDir.Replace("\\", "/")}" + """; + + var configPath = FileSystem.Path.Combine(FileSystem.Path.GetTempPath(), "config-dir-override", "changelog.yml"); + FileSystem.Directory.CreateDirectory(FileSystem.Path.GetDirectoryName(configPath)!); + await FileSystem.File.WriteAllTextAsync(configPath, configContent, TestContext.Current.CancellationToken); + + // language=yaml + var changelog1 = + """ + title: Test feature + type: feature + products: + - product: elasticsearch + target: 9.2.0 + prs: + - https://github.com/elastic/elasticsearch/pull/100 + """; + + var file1 = FileSystem.Path.Combine(_changelogDir, "1755268130-feature.yaml"); + await FileSystem.File.WriteAllTextAsync(file1, changelog1, TestContext.Current.CancellationToken); + + var input = new BundleChangelogsArguments + { + Directory = _changelogDir, + Config = configPath, + Output = FileSystem.Path.Combine(outputDir, "bundle.yaml"), + All = true + }; + + // Act - Explicit Directory overrides config.Bundle.Directory + var result = await ServiceWithConfig.BundleChangelogs(Collector, input, TestContext.Current.CancellationToken); + + // Assert - used _changelogDir (CLI), not configDir (config) + result.Should().BeTrue($"Expected bundling to succeed. Errors: {string.Join("; ", Collector.Diagnostics.Where(d => d.Severity == Severity.Error).Select(d => d.Message))}"); + Collector.Errors.Should().Be(0); + + var bundleContent = await FileSystem.File.ReadAllTextAsync(input.Output, TestContext.Current.CancellationToken); + bundleContent.Should().Contain("product: elasticsearch"); + bundleContent.Should().Contain("name: 1755268130-feature.yaml"); + } + [Fact] public async Task BundleChangelogs_WithProfileHideFeatures_IncludesHideFeaturesInBundle() {