Skip to content

Commit 25cf121

Browse files
Mpdreamzcotti
andauthored
Collect all redirects during assemble builds (#1207)
* Collect all redirects during assemble builds * Fix merge for builder * Fix tests --------- Co-authored-by: Felipe Cotti <[email protected]>
1 parent bb2e19d commit 25cf121

File tree

9 files changed

+78
-27
lines changed

9 files changed

+78
-27
lines changed

src/Elastic.Markdown/BuildContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public record BuildContext : IDocumentationContext
3030

3131
public bool Force { get; init; }
3232

33-
public bool SkipMetadata { get; init; }
33+
public bool SkipDocumentationState { get; init; }
3434

3535
// This property is used to determine if the site should be indexed by search engines
3636
public bool AllowIndexing { get; init; }

src/Elastic.Markdown/DocumentationGenerator.cs

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Reflection;
77
using System.Text.Json;
88
using Elastic.Documentation.Legacy;
9+
using Elastic.Documentation.Links;
910
using Elastic.Documentation.Serialization;
1011
using Elastic.Documentation.State;
1112
using Elastic.Markdown.Exporters;
@@ -27,6 +28,11 @@ public interface IDocumentationFileOutputProvider
2728
IFileInfo? OutputFile(DocumentationSet documentationSet, IFileInfo defaultOutputFile, string relativePath);
2829
}
2930

31+
public record GenerationResult
32+
{
33+
public IReadOnlyDictionary<string, LinkRedirect> Redirects { get; set; } = new Dictionary<string, LinkRedirect>();
34+
}
35+
3036
public class DocumentationGenerator
3137
{
3238
private readonly IDocumentationFileOutputProvider? _documentationFileOutputProvider;
@@ -87,14 +93,23 @@ public async Task ResolveDirectoryTree(Cancel ctx)
8793
_logger.LogInformation("Resolved tree");
8894
}
8995

90-
public async Task GenerateAll(Cancel ctx)
96+
public async Task<GenerationResult> GenerateAll(Cancel ctx)
9197
{
92-
var generationState = GetPreviousGenerationState();
93-
if (!Context.SkipMetadata && (Context.Force || generationState == null))
98+
var result = new GenerationResult();
99+
100+
HashSet<string> offendingFiles = [];
101+
var outputSeenChanges = DateTimeOffset.MinValue;
102+
if (Context.SkipDocumentationState)
94103
DocumentationSet.ClearOutputDirectory();
104+
else
105+
{
106+
var generationState = GetPreviousGenerationState();
107+
if (Context.Force || generationState == null)
108+
DocumentationSet.ClearOutputDirectory();
95109

96-
if (CompilationNotNeeded(generationState, out var offendingFiles, out var outputSeenChanges))
97-
return;
110+
if (CompilationNotNeeded(generationState, out offendingFiles, out outputSeenChanges))
111+
return result;
112+
}
98113

99114
_logger.LogInformation($"Fetching external links");
100115
_ = await Resolver.FetchLinks(ctx);
@@ -107,14 +122,20 @@ public async Task GenerateAll(Cancel ctx)
107122

108123
await ExtractEmbeddedStaticResources(ctx);
109124

110-
if (Context.SkipMetadata)
111-
return;
112-
113-
_logger.LogInformation($"Generating documentation compilation state");
114-
await GenerateDocumentationState(ctx);
125+
if (!Context.SkipDocumentationState)
126+
{
127+
_logger.LogInformation($"Generating documentation compilation state");
128+
await GenerateDocumentationState(ctx);
129+
}
115130

116131
_logger.LogInformation($"Generating links.json");
117-
await GenerateLinkReference(ctx);
132+
var linkReference = await GenerateLinkReference(ctx);
133+
134+
// ReSharper disable once WithExpressionModifiesAllMembers
135+
return result with
136+
{
137+
Redirects = linkReference.Redirects ?? []
138+
};
118139
}
119140

120141
private async Task ProcessDocumentationFiles(HashSet<string> offendingFiles, DateTimeOffset outputSeenChanges, Cancel ctx)
@@ -254,13 +275,13 @@ private bool CompilationNotNeeded(GenerationState? generationState, out HashSet<
254275
return false;
255276
}
256277

257-
private async Task GenerateLinkReference(Cancel ctx)
278+
private async Task<LinkReference> GenerateLinkReference(Cancel ctx)
258279
{
259280
var file = DocumentationSet.LinkReferenceFile;
260281
var state = DocumentationSet.CreateLinkReference();
261-
262282
var bytes = JsonSerializer.SerializeToUtf8Bytes(state, SourceGenerationContext.Default.LinkReference);
263283
await DocumentationSet.OutputDirectory.FileSystem.File.WriteAllBytesAsync(file.FullName, bytes, ctx);
284+
return state;
264285
}
265286

266287
private async Task GenerateDocumentationState(Cancel ctx)

src/tooling/docs-assembler/AssembleContext.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ public AssembleContext(
7272
Environment = env;
7373

7474
var contentSource = Environment.ContentSource.ToStringFast(true);
75-
CheckoutDirectory = ReadFileSystem.DirectoryInfo.New(checkoutDirectory ?? Path.Combine(".artifacts", "checkouts", contentSource));
75+
var defaultCheckoutDirectory = Path.Combine(Paths.WorkingDirectoryRoot.FullName, ".artifacts", "checkouts", contentSource);
76+
CheckoutDirectory = ReadFileSystem.DirectoryInfo.New(checkoutDirectory ?? defaultCheckoutDirectory);
7677
OutputDirectory = ReadFileSystem.DirectoryInfo.New(output ?? Path.Combine(".artifacts", "assembly"));
7778

7879

src/tooling/docs-assembler/Building/AssemblerBuilder.cs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
using System.Collections.Frozen;
66
using Documentation.Assembler.Navigation;
77
using Elastic.Documentation.Legacy;
8+
using Elastic.Documentation.Links;
89
using Elastic.Markdown;
10+
using Elastic.Markdown.Links.CrossLinks;
911
using Microsoft.Extensions.Logging;
1012

1113
namespace Documentation.Assembler.Building;
@@ -29,6 +31,8 @@ public async Task BuildAllAsync(FrozenDictionary<string, AssemblerDocumentationS
2931
context.OutputDirectory.Delete(true);
3032
context.OutputDirectory.Create();
3133

34+
var redirects = new Dictionary<string, string>();
35+
3236
foreach (var (_, set) in assembleSets)
3337
{
3438
var checkout = set.Checkout;
@@ -40,7 +44,8 @@ public async Task BuildAllAsync(FrozenDictionary<string, AssemblerDocumentationS
4044

4145
try
4246
{
43-
await BuildAsync(set, ctx);
47+
var result = await BuildAsync(set, ctx);
48+
CollectRedirects(redirects, result.Redirects, checkout.Repository.Name, set.DocumentationSet.LinkResolver);
4449
}
4550
catch (Exception e) when (e.Message.Contains("Can not locate docset.yml file in"))
4651
{
@@ -56,7 +61,36 @@ public async Task BuildAllAsync(FrozenDictionary<string, AssemblerDocumentationS
5661
await context.Collector.StopAsync(ctx);
5762
}
5863

59-
private async Task BuildAsync(AssemblerDocumentationSet set, Cancel ctx)
64+
private static void CollectRedirects(
65+
Dictionary<string, string> allRedirects,
66+
IReadOnlyDictionary<string, LinkRedirect> redirects,
67+
string repository,
68+
ICrossLinkResolver linkResolver
69+
)
70+
{
71+
if (redirects.Count == 0)
72+
return;
73+
74+
foreach (var (k, v) in redirects)
75+
{
76+
if (v.To is { } to)
77+
allRedirects[Resolve(k)] = Resolve(to);
78+
else if (v.Many is { } many)
79+
{
80+
var target = many.FirstOrDefault(l => l.To is not null);
81+
if (target?.To is { } t)
82+
allRedirects[Resolve(k)] = Resolve(t);
83+
}
84+
}
85+
string Resolve(string relativeMarkdownPath)
86+
{
87+
var uri = linkResolver.UriResolver.Resolve(new Uri($"{repository}://{relativeMarkdownPath}"),
88+
PublishEnvironmentUriResolver.MarkdownPathToUrlPath(relativeMarkdownPath));
89+
return uri.AbsolutePath;
90+
}
91+
}
92+
93+
private async Task<GenerationResult> BuildAsync(AssemblerDocumentationSet set, Cancel ctx)
6094
{
6195
var generator = new DocumentationGenerator(
6296
set.DocumentationSet,
@@ -65,7 +99,7 @@ private async Task BuildAsync(AssemblerDocumentationSet set, Cancel ctx)
6599
legacyUrlMapper: LegacyUrlMapper,
66100
positionalNavigation: navigation
67101
);
68-
await generator.GenerateAll(ctx);
102+
return await generator.GenerateAll(ctx);
69103
}
70104

71105
}

src/tooling/docs-assembler/Building/PublishEnvironmentUriResolver.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,6 @@ public PublishEnvironmentUriResolver(FrozenDictionary<Uri, TocTopLevelMapping> t
4141

4242
public Uri Resolve(Uri crossLinkUri, string path)
4343
{
44-
if (crossLinkUri.Scheme == "detection-rules")
45-
{
46-
47-
}
48-
4944
var subPath = GetSubPathPrefix(crossLinkUri, ref path);
5045

5146
var fullPath = (PublishEnvironment.PathPrefix, subPath) switch

src/tooling/docs-assembler/Cli/RepositoryCommands.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ await Parallel.ForEachAsync(repositories,
164164
);
165165
var set = new DocumentationSet(context, logger);
166166
var generator = new DocumentationGenerator(set, logger, null, null, new NoopDocumentationFileExporter());
167-
await generator.GenerateAll(c);
167+
_ = await generator.GenerateAll(c);
168168

169169
IAmazonS3 s3Client = new AmazonS3Client();
170170
const string bucketName = "elastic-docs-link-index";

src/tooling/docs-assembler/Navigation/AssemblerDocumentationSet.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public AssemblerDocumentationSet(
6969
CookiesWin = env.GoogleTagManager.CookiesWin
7070
},
7171
CanonicalBaseUrl = new Uri("https://www.elastic.co"), // Always use the production URL. In case a page is leaked to a search engine, it should point to the production site.
72-
SkipMetadata = true,
72+
SkipDocumentationState = true,
7373
};
7474
BuildContext = buildContext;
7575

src/tooling/docs-builder/Cli/Commands.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ public async Task<int> Generate(
153153
var exporter = metadataOnly.HasValue && metadataOnly.Value ? new NoopDocumentationFileExporter() : null;
154154

155155
var generator = new DocumentationGenerator(set, logger, null, null, exporter);
156-
await generator.GenerateAll(ctx);
156+
_ = await generator.GenerateAll(ctx);
157157

158158
if (runningOnCi)
159159
await githubActionsService.SetOutputAsync("landing-page-path", set.MarkdownFiles.First().Value.Url);

tests/authoring/Framework/TestValues.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ and MarkdownTestContext =
9999
member this.Bootstrap () = backgroundTask {
100100
let! ctx = Async.CancellationToken
101101
let _ = this.Collector.StartAsync(ctx)
102-
do! this.Generator.GenerateAll(ctx)
102+
let! _ = this.Generator.GenerateAll(ctx)
103103
do! this.Collector.StopAsync(ctx)
104104

105105
let results =

0 commit comments

Comments
 (0)