Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion actions/docs-verifier/nuget.config
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
<add key="FeedProxy" value="https://packagefeedproxy.microsoft.io/nuget/v3/index.json" />
</packageSources>
</configuration>
27 changes: 4 additions & 23 deletions actions/docs-verifier/src/ActionRunner/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@

if (queryOrHeadingIndex > -1)
{
newLink += linkError.Link.Substring(queryOrHeadingIndex);
newLink += linkError.Link[queryOrHeadingIndex..];
}

file = file.Insert(linkError.UrlSpan.Start, newLink);
Expand All @@ -106,14 +106,10 @@
IEnumerable<Matcher> matchers = await docfxConfigurationReader.MapConfigurationAsync();
IEnumerable<PullRequestFile> pullRequestFiles = await GitHubPullRequest.GetPullRequestFilesAsync(pullRequestNumber);

WhatsNewConfigurationReader whatsNewConfigurationReader = new();
string? whatsNewPath = await whatsNewConfigurationReader.MapConfigurationAsync();

List<PullRequestFile> files =
pullRequestFiles.Where(f => IsRedirectableFile(f, matchers, whatsNewPath)).ToList();
[.. pullRequestFiles.Where(f => IsRedirectableFile(f, matchers))];

// We should only ever fail on MD and YML files, no other files require redirection.
// Also, filter out files that are part of the "What's new" directory - as they shouldn't require redirects.
foreach (PullRequestFile file in files)
{
// Changing the extension from .yml to .md or the opposite doesn't require a redirection.
Expand All @@ -137,7 +133,7 @@
return returnCode;

static bool IsRedirectableFile(
PullRequestFile file, IEnumerable<Matcher> matchers, string? whatsNewPath)
PullRequestFile file, IEnumerable<Matcher> matchers)
{
string? deletedFileName = file.IsRenamed()
? file.PreviousFileName
Expand All @@ -149,27 +145,12 @@ static bool IsRedirectableFile(
// A deleted toc.yml doesn't need redirection.
// Also, don't require a redirection for file patterns specified as "exclude"s in docfx config file.
return !isDeletedToc && IsYmlOrMarkdownFile(deletedFileName)
&& !IsInWhatsNewDirectory(deletedFileName, whatsNewPath) &&
matchers.Any(m => m.Match(deletedFileName).HasMatches);
&& matchers.Any(m => m.Match(deletedFileName).HasMatches);
}

static bool IsYmlOrMarkdownFile([NotNullWhen(true)] string? fileName) =>
Path.GetExtension(fileName) is ".yml" or ".md";

static bool IsInWhatsNewDirectory(string fileName, string? whatsNewPath)
{
if (whatsNewPath is { Length: > 0 })
{
// Example:
// file.FileName: docs/whats-new/2021-03.md
// whatsNewPath: docs/whats-new

return fileName.StartsWith(whatsNewPath, StringComparison.OrdinalIgnoreCase);
}

return false;
}

static bool IsExtensionChangeOnly(string file1, string file2) =>
RemoveExtension(file1).Equals(RemoveExtension(file2), StringComparison.OrdinalIgnoreCase);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ public abstract class BaseConfigurationReader<TConfigurationFile>
/// </summary>
public string? ConfigurationFileName { get; set; }

/// <summary>
/// The directory containing the configuration file, or null if at root.
/// For example, if ConfigurationFileName is "docs/docfx.json", this will be "docs".
/// </summary>
public string? ConfigurationDirectory { get; private set; }

/// <summary>
/// Reads (or returns the cached) <typeparamref name="TConfigurationFile"/> file.
/// </summary>
Expand All @@ -36,6 +42,7 @@ public abstract class BaseConfigurationReader<TConfigurationFile>
{
if (File.Exists($"{dir}/{ConfigurationFileName}"))
{
ConfigurationDirectory = dir.TrimStart('.', '/', '\\');
ConfigurationFileName = $"{dir}/{ConfigurationFileName}";
_fileExists = true;
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ private IEnumerable<DocfxContent> GetDocfxContents()
return Build.Contents.Where(content => content.Source is null or "." or "docs");
}

public IEnumerable<Matcher> GetMatchers()
public IEnumerable<Matcher> GetMatchers(string? configDirectory = null)
{
if (_matchers is null)
{
Expand All @@ -33,11 +33,15 @@ public IEnumerable<Matcher> GetMatchers()
foreach (DocfxContent content in contents)
{
var matcher = new Matcher(StringComparison.OrdinalIgnoreCase);

// Adjust the source path based on where docfx.json was found
string effectiveSource = GetEffectiveSource(content.Source, configDirectory);

if (content.Files is not null)
{
Comment thread
gewarren marked this conversation as resolved.
foreach (string includePattern in content.Files)
{
matcher.AddInclude($"{content.Source}/{includePattern}");
matcher.AddInclude($"{effectiveSource}/{includePattern}");
}
}
else
Expand All @@ -61,6 +65,25 @@ public IEnumerable<Matcher> GetMatchers()

return _matchers;
}

private static string GetEffectiveSource(string? source, string? configDirectory)
{
// If no config directory (docfx.json at root), use source as-is
if (string.IsNullOrEmpty(configDirectory))
{
return source ?? ".";
}

// If source is "." or null, it means the content is relative to where docfx.json is
// So we need to prepend the config directory
if (source is null or ".")
{
return configDirectory;
}

// Otherwise, combine config directory with the specified source
return $"{configDirectory}/{source}";
}
}

public sealed record DocfxBuild(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ public DocfxConfigurationReader()
public override async ValueTask<IEnumerable<Matcher>> MapConfigurationAsync()
{
DocfxConfiguration? configuration = await ReadConfigurationAsync();
return AdjustMatchers(configuration?.GetMatchers());
return AdjustMatchers(configuration?.GetMatchers(ConfigurationDirectory));
}

private static IEnumerable<Matcher> AdjustMatchers(IEnumerable<Matcher>? matchers)
=> (matchers is null || !matchers.Any())
? new[] { s_matchAllMatcher }
? [s_matchAllMatcher]
: matchers;
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public OpenPublishingConfigReader()
public override async ValueTask<ImmutableArray<string>?> MapConfigurationAsync()
{
OpenPublishingConfig? configuration = await ReadConfigurationAsync();
if (configuration is { RedirectionFiles: { Length: > 0 } })
if (configuration is { RedirectionFiles.Length: > 0 })
{
return configuration.RedirectionFiles;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public OpenPublishingRedirectionReader(string configFileName)
public override async ValueTask<ImmutableArray<Redirection>> MapConfigurationAsync()
{
OpenPublishingRedirections? configuration = await ReadConfigurationAsync();
if (configuration is { Redirections: { Length: > 0 } })
if (configuration is { Redirections.Length: > 0 })
{
return configuration.Redirections;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,9 @@ public static class RedirectionHelpers

public static async Task<ImmutableArray<string>> GetRedirectionFileNames()
{
ImmutableArray<string>? redirectionFileNames = await GetRedirectionFilesAsync();

// If no redirection files are found in the OPS config, just use the default name.
if (redirectionFileNames == null)
redirectionFileNames = ImmutableArray.Create(".openpublishing.redirection.json");

ImmutableArray<string>? redirectionFileNames = await GetRedirectionFilesAsync() ??
[".openpublishing.redirection.json"];
Console.WriteLine($"The following {redirectionFileNames.Value.Length} redirection files are registered:");
foreach (string filename in redirectionFileNames)
{
Comment thread
gewarren marked this conversation as resolved.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" Version="10.0.11" />
<PackageReference Include="Octokit" Version="14.0.0" />
</ItemGroup>
Comment thread
gewarren marked this conversation as resolved.
<ItemGroup>
<ProjectReference Include="..\BuildVerifier.IO.Abstractions\BuildVerifier.IO.Abstractions.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@
public static class RedirectionsVerifier
{
/// <summary>
/// Verifies a redirection for the given source path, and write logs (using GitHub-specific syntax) to a text writer.
/// Verifies a redirection for the given source path,
/// and write logs (using GitHub-specific syntax) to a text writer.
/// </summary>
Comment thread
gewarren marked this conversation as resolved.
/// <returns>Returns <see langword="true"/> for a valid redirection; <see langword="false"/> otherwise.</returns>
/// <returns><see langword="true"/> for a valid redirection; <see langword="false"/> otherwise.</returns>
public static async Task<bool> WriteResultsAsync(
TextWriter writer, string sourcePath, IEnumerable<Redirection> redirections)
{
ArgumentNullException.ThrowIfNull(writer, nameof(writer));

List<Redirection> foundRedirections =
redirections.Where(redirection => redirection.MatchesSourcePath(sourcePath)).ToList();
[.. redirections.Where(redirection => redirection.MatchesSourcePath(sourcePath))];
if (foundRedirections.Count == 0)
{
await writer.WriteLineAsync($"::error::No redirection is found for '{sourcePath}'.");
Expand All @@ -32,7 +33,8 @@ public static async Task<bool> WriteResultsAsync(
return false;
}

// TODO: Verify file existence if it starts with "/<our_docset>". Will this require setting the docset as an env variable?.
// TODO: Verify file existence if it starts with "/<our_docset>".
// Will this require setting the docset as an env variable?.
return true;
}
}

This file was deleted.

This file was deleted.

Loading