From bfc971ee5ae1174457c756608456eeea8fca9a58 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 13 Apr 2026 20:25:57 +0200 Subject: [PATCH] Skip redirect validation for docset-excluded paths ValidateRedirects now uses Configuration.IsExcluded (docset globs, folder TOC excludes, include overrides) so deleted or renamed Markdown under excluded trees does not require redirects.yml entries. Adds ConfigurationFileExcludeTests for Elasticsearch-style exclude globs. Made-with: Cursor --- .../Tracking/LocalChangesService.cs | 2 + .../ConfigurationFileExcludeTests.cs | 97 +++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 tests/Elastic.Documentation.Configuration.Tests/ConfigurationFileExcludeTests.cs diff --git a/src/authoring/Elastic.Documentation.Refactor/Tracking/LocalChangesService.cs b/src/authoring/Elastic.Documentation.Refactor/Tracking/LocalChangesService.cs index 530e46a02..c81f18279 100644 --- a/src/authoring/Elastic.Documentation.Refactor/Tracking/LocalChangesService.cs +++ b/src/authoring/Elastic.Documentation.Refactor/Tracking/LocalChangesService.cs @@ -68,6 +68,8 @@ public Task ValidateRedirects(IDiagnosticsCollector collector, string? pat var lookupPath = change is RenamedGitChange renamed ? renamed.OldFilePath : change.FilePath; var docSetRelativePath = Path.GetRelativePath(buildContext.DocumentationSourceDirectory.FullName, Path.Join(root.FullName, lookupPath)); var rootRelativePath = Path.GetRelativePath(root.FullName, Path.Join(root.FullName, lookupPath)); + if (buildContext.Configuration.IsExcluded(docSetRelativePath.OptionalWindowsReplace())) + continue; if (redirects.ContainsKey(docSetRelativePath)) continue; if (redirects.ContainsKey(rootRelativePath)) diff --git a/tests/Elastic.Documentation.Configuration.Tests/ConfigurationFileExcludeTests.cs b/tests/Elastic.Documentation.Configuration.Tests/ConfigurationFileExcludeTests.cs new file mode 100644 index 000000000..ca4f863d5 --- /dev/null +++ b/tests/Elastic.Documentation.Configuration.Tests/ConfigurationFileExcludeTests.cs @@ -0,0 +1,97 @@ +// 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.Frozen; +using System.IO.Abstractions; +using System.IO.Abstractions.TestingHelpers; +using AwesomeAssertions; +using Elastic.Documentation.Configuration.Builder; +using Elastic.Documentation.Configuration.Products; +using Elastic.Documentation.Configuration.Toc; +using Elastic.Documentation.Configuration.Versions; +using Elastic.Documentation.Diagnostics; +using Nullean.ScopedFileSystem; + +namespace Elastic.Documentation.Configuration.Tests; + +public class ConfigurationFileExcludeTests +{ + [Fact] + public void IsExcluded_DocsetGlob_MatchesNestedKibanaDocsPath() + { + var docSet = new DocumentationSetFile + { + Project = "test", + TableOfContents = [], + Exclude = + [ + "reference/query-languages/esql/kibana/docs/**" + ] + }; + var config = CreateConfiguration(docSet); + + config.IsExcluded("reference/query-languages/esql/kibana/docs/functions/mv_slice.md").Should().BeTrue(); + } + + [Fact] + public void IsExcluded_DocsetGlob_DoesNotMatchOutsideTree() + { + var docSet = new DocumentationSetFile + { + Project = "test", + TableOfContents = [], + Exclude = + [ + "reference/query-languages/esql/kibana/docs/**" + ] + }; + var config = CreateConfiguration(docSet); + + config.IsExcluded("reference/query-languages/esql/guide.md").Should().BeFalse(); + } + + private static ConfigurationFile CreateConfiguration(DocumentationSetFile docSet) + { + var collector = new DiagnosticsCollector([]); + var root = Paths.WorkingDirectoryRoot.FullName; + var configFilePath = Path.Join(root, "docs", "_docset.yml"); + var fileSystem = new MockFileSystem(new Dictionary + { + { configFilePath, new MockFileData("") } + }, root); + + var configPath = fileSystem.FileInfo.New(configFilePath); + var docsDir = fileSystem.DirectoryInfo.New(Path.Join(root, "docs")); + + var context = new MockDocumentationSetContext(collector, fileSystem, configPath, docsDir); + var versionsConfig = new VersionsConfiguration + { + VersioningSystems = new Dictionary() + }; + var productsConfig = new ProductsConfiguration + { + Products = new Dictionary().ToFrozenDictionary(), + ProductDisplayNames = new Dictionary().ToFrozenDictionary() + }; + + return new ConfigurationFile(docSet, context, versionsConfig, productsConfig); + } + + private sealed class MockDocumentationSetContext( + IDiagnosticsCollector collector, + IFileSystem fileSystem, + IFileInfo configurationPath, + IDirectoryInfo documentationSourceDirectory) + : IDocumentationSetContext + { + public IDiagnosticsCollector Collector => collector; + public ScopedFileSystem ReadFileSystem => WriteFileSystem; + public ScopedFileSystem WriteFileSystem { get; } = FileSystemFactory.ScopeCurrentWorkingDirectoryForWrite(fileSystem); + public IDirectoryInfo OutputDirectory => fileSystem.DirectoryInfo.New(Path.Join(Paths.WorkingDirectoryRoot.FullName, ".artifacts")); + public IFileInfo ConfigurationPath => configurationPath; + public BuildType BuildType => BuildType.Isolated; + public IDirectoryInfo DocumentationSourceDirectory => documentationSourceDirectory; + public GitCheckoutInformation Git => GitCheckoutInformation.Create(documentationSourceDirectory, fileSystem); + } +}