-
Notifications
You must be signed in to change notification settings - Fork 42
Expand file tree
/
Copy pathLocalChangesService.cs
More file actions
99 lines (87 loc) · 4.48 KB
/
LocalChangesService.cs
File metadata and controls
99 lines (87 loc) · 4.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// 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.IO.Abstractions;
using Elastic.Documentation.Configuration;
using Elastic.Documentation.Configuration.Builder;
using Elastic.Documentation.Diagnostics;
using Elastic.Documentation.Extensions;
using Elastic.Documentation.Services;
using Microsoft.Extensions.Logging;
using Nullean.ScopedFileSystem;
namespace Elastic.Documentation.Refactor.Tracking;
public class LocalChangeTrackingService(
ILoggerFactory logFactory,
IConfigurationContext configurationContext
) : IService
{
private readonly ILogger _logger = logFactory.CreateLogger<LocalChangeTrackingService>();
public Task<bool> ValidateRedirects(IDiagnosticsCollector collector, string? path, ScopedFileSystem fs)
{
var runningOnCi = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("GITHUB_ACTIONS"));
var buildContext = new BuildContext(collector, fs, fs, configurationContext, ExportOptions.MetadataOnly, path, null);
var redirectFile = new RedirectFile(buildContext);
if (!redirectFile.Source.Exists)
{
_logger.LogInformation("Redirect file {RedirectFile} does not exist, no redirects to validate.", redirectFile.Source);
return Task.FromResult(true);
}
var redirects = redirectFile.Redirects;
if (redirects is null)
{
collector.EmitError(redirectFile.Source, "It was not possible to parse the redirects file.");
return Task.FromResult(false);
}
var root = Paths.FindGitRoot(buildContext.DocumentationSourceDirectory);
if (root is null)
{
collector.EmitError(redirectFile.Source, $"Unable to determine the root of the source directory {buildContext.DocumentationSourceDirectory}.");
return Task.FromResult(false);
}
var relativePath = Path.GetRelativePath(root.FullName, buildContext.DocumentationSourceDirectory.FullName);
_logger.LogInformation("Using relative path {RelativePath} for validating changes", relativePath);
IRepositoryTracker tracker = runningOnCi
? new IntegrationGitRepositoryTracker(relativePath)
: new LocalGitRepositoryTracker(logFactory, collector, root, relativePath);
var changed = tracker.GetChangedFiles()
.Where(c =>
{
var fi = fs.FileInfo.New(c.FilePath);
return fi.Extension is ".md" && !fi.HasParent("_snippets");
})
.ToArray();
if (changed.Length != 0)
_logger.LogInformation("Found {Count} changes to files related to documentation in the current branch.", changed.Length);
var deletedAndRenamed = changed.Where(c => c.ChangeType is GitChangeType.Deleted or GitChangeType.Renamed).ToArray();
var missingCount = 0;
foreach (var change in deletedAndRenamed)
{
var lookupPath = change is RenamedGitChange renamed ? renamed.OldFilePath : change.FilePath;
// Normalize separators to '/' on Windows: redirects.yml keys and the configured
// excludes are always forward-slash, but Path.GetRelativePath returns '\' on Windows.
var docSetRelativePath = Path.GetRelativePath(buildContext.DocumentationSourceDirectory.FullName, Path.Join(root.FullName, lookupPath)).OptionalWindowsReplace();
var rootRelativePath = Path.GetRelativePath(root.FullName, Path.Join(root.FullName, lookupPath)).OptionalWindowsReplace();
if (buildContext.Configuration.IsExcluded(docSetRelativePath))
continue;
if (redirects.ContainsKey(docSetRelativePath))
continue;
if (redirects.ContainsKey(rootRelativePath))
{
collector.EmitError(redirectFile.Source,
$"Redirect contains path relative to root '{rootRelativePath}' but should be relative to the documentation set '{docSetRelativePath}'");
continue;
}
missingCount++;
if (change is RenamedGitChange rename)
collector.EmitError(redirectFile.Source, $"Missing '{docSetRelativePath}' in redirects.yml. '{rename.OldFilePath}' was renamed to '{rename.NewFilePath}' but it has no redirect configuration set.");
else if (change.ChangeType is GitChangeType.Deleted)
collector.EmitError(redirectFile.Source, $"Missing '{docSetRelativePath}' in redirects.yml. '{change.FilePath}' was deleted but it has no redirect targets. This will lead to broken links.");
}
if (missingCount != 0)
{
var relativeRedirectFile = Path.GetRelativePath(root.FullName, redirectFile.Source.FullName);
_logger.LogInformation("Found {Count} changes that still require updates to: {RedirectFile}", missingCount, relativeRedirectFile);
}
return Task.FromResult(collector.Errors == 0);
}
}