Skip to content

Commit e889c86

Browse files
committed
Collect all redirects during assemble builds
1 parent e71b76a commit e889c86

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
public async Task StopDiagnosticCollection(Cancel ctx)
@@ -266,13 +287,13 @@ private bool CompilationNotNeeded(GenerationState? generationState, out HashSet<
266287
return false;
267288
}
268289

269-
private async Task GenerateLinkReference(Cancel ctx)
290+
private async Task<LinkReference> GenerateLinkReference(Cancel ctx)
270291
{
271292
var file = DocumentationSet.LinkReferenceFile;
272293
var state = DocumentationSet.CreateLinkReference();
273-
274294
var bytes = JsonSerializer.SerializeToUtf8Bytes(state, SourceGenerationContext.Default.LinkReference);
275295
await DocumentationSet.OutputDirectory.FileSystem.File.WriteAllBytesAsync(file.FullName, bytes, ctx);
296+
return state;
276297
}
277298

278299
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
{
@@ -57,7 +62,36 @@ public async Task BuildAllAsync(FrozenDictionary<string, AssemblerDocumentationS
5762
await context.Collector.StopAsync(ctx);
5863
}
5964

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

72106
}

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
@@ -163,7 +163,7 @@ await Parallel.ForEachAsync(repositories,
163163
);
164164
var set = new DocumentationSet(context, logger);
165165
var generator = new DocumentationGenerator(set, logger, null, null, new NoopDocumentationFileExporter());
166-
await generator.GenerateAll(c);
166+
_ = await generator.GenerateAll(c);
167167

168168
IAmazonS3 s3Client = new AmazonS3Client();
169169
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
@@ -156,7 +156,7 @@ public async Task<int> Generate(
156156
var exporter = metadataOnly.HasValue && metadataOnly.Value ? new NoopDocumentationFileExporter() : null;
157157

158158
var generator = new DocumentationGenerator(set, logger, null, null, exporter);
159-
await generator.GenerateAll(ctx);
159+
_ = await generator.GenerateAll(ctx);
160160
await generator.StopDiagnosticCollection(ctx);
161161
if (runningOnCi)
162162
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
@@ -98,7 +98,7 @@ and MarkdownTestContext =
9898

9999
member this.Bootstrap () = backgroundTask {
100100
let! ctx = Async.CancellationToken
101-
do! this.Generator.GenerateAll(ctx)
101+
let! _ = this.Generator.GenerateAll(ctx)
102102
do! this.Generator.StopDiagnosticCollection(ctx)
103103

104104
let results =

0 commit comments

Comments
 (0)