Skip to content
21 changes: 21 additions & 0 deletions .github/workflows/preview-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ jobs:
outputs:
any_modified: ${{ steps.check-files.outputs.any_modified }}
all_changed_files: ${{ steps.check-files.outputs.all_changed_files }}
added_files: ${{ steps.check-files.outputs.added_files }}
modified_files: ${{ steps.check-files.outputs.modified_files }}
deleted_files: ${{ steps.check-files.outputs.deleted_files }}
renamed_files: ${{ steps.check-files.outputs.renamed_files }}
steps:
- name: Checkout
if: contains(fromJSON('["push", "merge_group", "workflow_dispatch"]'), github.event_name)
Expand Down Expand Up @@ -149,6 +153,10 @@ jobs:
env:
GITHUB_PR_REF_NAME: ${{ github.event.pull_request.head.ref }}
MATCH: ${{ needs.match.outputs.content-source-match }}
ADDED_FILES: ${{ needs.check.outputs.added_files }}
MODIFIED_FILES: ${{ needs.check.outputs.modified_files }}
DELETED_FILES: ${{ needs.check.outputs.deleted_files }}
RENAMED_FILES: ${{ needs.check.outputs.renamed_files }}
needs:
- check
- match
Expand Down Expand Up @@ -234,6 +242,19 @@ jobs:
&& steps.deployment.outputs.result
uses: elastic/docs-builder/.github/actions/bootstrap@main

- name: 'Validate redirect rules'
if: >
env.MATCH == 'true'
&& (
steps.deployment.outputs.result
|| (
needs.check.outputs.any_modified == 'true'
&& github.event_name == 'merge_group'
)
)
run: |
dotnet run --project src/tooling/docs-builder -- diff validate

# we run our artifact directly, please use the prebuild
# elastic/docs-builder@main GitHub Action for all other repositories!
- name: Build documentation
Expand Down
14 changes: 11 additions & 3 deletions src/tooling/docs-builder/Cli/DiffCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ internal sealed class DiffCommands(
IConfigurationContext configurationContext
)
{
private readonly ILogger<Program> _log = logFactory.CreateLogger<Program>();

/// <summary>
/// Validates redirect updates in the current branch using the redirect file against changes reported by git.
/// </summary>
Expand All @@ -31,6 +33,7 @@ IConfigurationContext configurationContext
[Command("validate")]
public async Task<int> ValidateRedirects([Argument] string? path = null, Cancel ctx = default)
{
var runningOnCi = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("GITHUB_ACTIONS"));
path ??= "docs";

await using var collector = new ConsoleDiagnosticsCollector(logFactory, githubActionsService).StartAsync(ctx);
Expand All @@ -53,16 +56,21 @@ public async Task<int> ValidateRedirects([Argument] string? path = null, Cancel
return collector.Errors;
}

var tracker = new LocalGitRepositoryTracker(collector, root);
var changed = tracker.GetChangedFiles(path);
IRepositoryTracker tracker = runningOnCi ? new IntegrationGitRepositoryTracker(path) : new LocalGitRepositoryTracker(collector, root, path);
var changed = tracker.GetChangedFiles() as GitChange[] ?? [];

if (changed.Length > 0)
_log.LogInformation($"Found {changed.Length} changes to files related to documentation in the current branch.");

foreach (var notFound in changed.DistinctBy(c => c.FilePath).Where(c => c.ChangeType is GitChangeType.Deleted or GitChangeType.Renamed
&& !redirects.ContainsKey(c is RenamedGitChange renamed ? renamed.OldFilePath : c.FilePath)))
{
if (notFound is RenamedGitChange renamed)
{
collector.EmitError(redirectFileInfo.Name,
$"File '{renamed.OldFilePath}' was renamed to '{renamed.NewFilePath}' but it has no redirect configuration set.");
runningOnCi
? $"A file was renamed to '{renamed.NewFilePath}' but it has no redirect configuration set."
: $"File '{renamed.OldFilePath}' was renamed to '{renamed.NewFilePath}' but it has no redirect configuration set.");
}
else if (notFound.ChangeType is GitChangeType.Deleted)
{
Expand Down
5 changes: 4 additions & 1 deletion src/tooling/docs-builder/Tracking/IRepositoryTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ public enum GitChangeType
Other
}

public record GitChange(string FilePath, GitChangeType ChangeType);
public record RenamedGitChange(string OldFilePath, string NewFilePath, GitChangeType ChangeType) : GitChange(OldFilePath, ChangeType);

public interface IRepositoryTracker
{
IEnumerable<GitChange> GetChangedFiles(string lookupPath);
IEnumerable<GitChange> GetChangedFiles();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// 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 Documentation.Builder.Tracking;

public class IntegrationGitRepositoryTracker(string lookupPath) : IRepositoryTracker
{
private string LookupPath { get; } = $"{lookupPath}/";
public IEnumerable<GitChange> GetChangedFiles()
{
var deletedFiles = Environment.GetEnvironmentVariable("DELETED_FILES") ?? string.Empty;
if (!string.IsNullOrEmpty(deletedFiles))
{
foreach (var file in deletedFiles.Split(' ', StringSplitOptions.RemoveEmptyEntries).Where(f => f.StartsWith(LookupPath)))
yield return new GitChange(file, GitChangeType.Deleted);
}

var addedFiles = Environment.GetEnvironmentVariable("ADDED_FILES");
if (!string.IsNullOrEmpty(addedFiles))
{
foreach (var file in addedFiles.Split(' ', StringSplitOptions.RemoveEmptyEntries).Where(f => f.StartsWith(LookupPath)))
yield return new GitChange(file, GitChangeType.Added);
}

var modifiedFiles = Environment.GetEnvironmentVariable("MODIFIED_FILES");
if (!string.IsNullOrEmpty(modifiedFiles))
{
foreach (var file in modifiedFiles.Split(' ', StringSplitOptions.RemoveEmptyEntries).Where(f => f.StartsWith(LookupPath)))
yield return new GitChange(file, GitChangeType.Modified);
}

var renamedFiles = Environment.GetEnvironmentVariable("RENAMED_FILES");
if (!string.IsNullOrEmpty(renamedFiles))
{
foreach (var file in renamedFiles.Split(' ', StringSplitOptions.RemoveEmptyEntries).Where(f => f.StartsWith(LookupPath)))
yield return new RenamedGitChange(string.Empty, file, GitChangeType.Renamed);
}
}
}
13 changes: 6 additions & 7 deletions src/tooling/docs-builder/Tracking/LocalGitRepositoryTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,16 @@

namespace Documentation.Builder.Tracking;

public record GitChange(string FilePath, GitChangeType ChangeType);
public record RenamedGitChange(string OldFilePath, string NewFilePath, GitChangeType ChangeType) : GitChange(OldFilePath, ChangeType);

public class LocalGitRepositoryTracker(DiagnosticsCollector collector, IDirectoryInfo workingDirectory) : ExternalCommandExecutor(collector, workingDirectory), IRepositoryTracker
public class LocalGitRepositoryTracker(DiagnosticsCollector collector, IDirectoryInfo workingDirectory, string lookupPath) : ExternalCommandExecutor(collector, workingDirectory), IRepositoryTracker
{
public IEnumerable<GitChange> GetChangedFiles(string lookupPath)
private string LookupPath { get; } = lookupPath;

public IEnumerable<GitChange> GetChangedFiles()
{
var defaultBranch = GetDefaultBranch();
var commitChanges = CaptureMultiple("git", "diff", "--name-status", $"{defaultBranch}...HEAD", "--", $"./{lookupPath}");
var commitChanges = CaptureMultiple("git", "diff", "--name-status", $"{defaultBranch}...HEAD", "--", $"./{LookupPath}");
var localChanges = CaptureMultiple("git", "status", "--porcelain");
ExecInSilent([], "git", "stash", "push", "--", $"./{lookupPath}");
ExecInSilent([], "git", "stash", "push", "--", $"./{LookupPath}");
var localUnstagedChanges = CaptureMultiple("git", "stash", "show", "--name-status", "-u");
ExecInSilent([], "git", "stash", "pop");

Expand Down
Loading