Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NuGet] Add Analyze command to NuGetUpdater #9493

Closed
wants to merge 13 commits into from
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System.Text;

using NuGetUpdater.Core.Test.Analyze;

namespace NuGetUpdater.Cli.Test;

using TestFile = (string Path, string Content);

public partial class EntryPointTests
{
public class Analyze : AnalyzeWorkerTestBase
{
private static async Task Run(Func<string, string[]> getArgs, string dependencyName, TestFile[] initialFiles, ExpectedAnalysisResult expectedResult)
{
var actualResult = await RunAnalyzerAsync(dependencyName, initialFiles, async path =>
{
var sb = new StringBuilder();
var writer = new StringWriter(sb);

var originalOut = Console.Out;
var originalErr = Console.Error;
Console.SetOut(writer);
Console.SetError(writer);

try
{
var args = getArgs(path);
var result = await Program.Main(args);
if (result != 0)
{
throw new Exception($"Program exited with code {result}.\nOutput:\n\n{sb}");
}
}
finally
{
Console.SetOut(originalOut);
Console.SetError(originalErr);
}
});

ValidateAnalysisResult(expectedResult, actualResult);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Collections.Immutable;
using System.Text;

using NuGetUpdater.Core;
using NuGetUpdater.Core.Discover;
using NuGetUpdater.Core.Test.Discover;

using Xunit;
Expand All @@ -25,6 +25,8 @@ await RunAsync(path =>
path,
"--workspace",
path,
"--output",
Path.Combine(path, DiscoveryWorker.DiscoveryResultFileName)
],
new[]
{
Expand Down Expand Up @@ -77,7 +79,7 @@ await RunAsync(path =>
},
expectedResult: new()
{
FilePath = "",
Path = "",
Projects = [
new()
{
Expand Down Expand Up @@ -107,6 +109,8 @@ await RunAsync(path =>
path,
"--workspace",
path,
"--output",
Path.Combine(path, DiscoveryWorker.DiscoveryResultFileName)
],
new[]
{
Expand Down Expand Up @@ -136,7 +140,7 @@ await RunAsync(path =>
},
expectedResult: new()
{
FilePath = "",
Path = "",
Projects = [
new()
{
Expand Down Expand Up @@ -166,6 +170,8 @@ await RunAsync(path =>
path,
"--workspace",
Path.Combine(path, workspacePath),
"--output",
Path.Combine(path, DiscoveryWorker.DiscoveryResultFileName)
],
new[]
{
Expand Down Expand Up @@ -195,7 +201,7 @@ await RunAsync(path =>
},
expectedResult: new()
{
FilePath = workspacePath,
Path = workspacePath,
Projects = [
new()
{
Expand All @@ -221,6 +227,8 @@ private static async Task RunAsync(
{
var actualResult = await RunDiscoveryAsync(initialFiles, async path =>
{
expectedResult = expectedResult with { Path = Path.Combine(path, expectedResult.Path) };

var sb = new StringBuilder();
var writer = new StringWriter(sb);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

using Xunit;

namespace NuGetUpdater.Cli.Test;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;

using NuGetUpdater.Core;
using NuGetUpdater.Core.Test;
Expand Down Expand Up @@ -235,7 +232,7 @@ await Run(path =>
"""),
("other-dir/Directory.Build.props", """
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<ItemGroup>
<PackageReference Include="NuGet.Versioning" Version="6.1.0" />
</ItemGroup>
Expand All @@ -254,7 +251,7 @@ await Run(path =>
</Project>
"""),
("some-dir/project1/project.csproj",
"""
"""
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
Expand Down Expand Up @@ -282,7 +279,7 @@ await Run(path =>
"""),
("other-dir/Directory.Build.props", """
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<ItemGroup>
<PackageReference Include="NuGet.Versioning" Version="6.1.0" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.CommandLine;

using NuGetUpdater.Core;
using NuGetUpdater.Core.Analyze;

namespace NuGetUpdater.Cli.Commands;

internal static class AnalyzeCommand
{
internal static readonly Option<FileInfo> DependencyFilePathOption = new("--dependency-file-path") { IsRequired = true };
internal static readonly Option<FileInfo> DiscoveryFilePathOption = new("--discovery-file-path") { IsRequired = true };
internal static readonly Option<DirectoryInfo> AnalysisFolderOption = new("--analysis-folder-path") { IsRequired = true };
internal static readonly Option<bool> VerboseOption = new("--verbose", getDefaultValue: () => false);

internal static Command GetCommand(Action<int> setExitCode)
{
Command command = new("analyze", "Determines how to update a dependency based on the workspace discovery information.")
{
DependencyFilePathOption,
DiscoveryFilePathOption,
AnalysisFolderOption,
VerboseOption
};

command.TreatUnmatchedTokensAsErrors = true;

command.SetHandler(async (discoveryPath, dependencyPath, analysisDirectory, verbose) =>
{
var worker = new AnalyzeWorker(new Logger(verbose));
await worker.RunAsync(discoveryPath.FullName, dependencyPath.FullName, analysisDirectory.FullName);
}, DiscoveryFilePathOption, DependencyFilePathOption, AnalysisFolderOption, VerboseOption);

return command;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ namespace NuGetUpdater.Cli.Commands;

internal static class DiscoverCommand
{
internal static readonly Option<DirectoryInfo> RepoRootOption = new("--repo-root", () => new DirectoryInfo(Environment.CurrentDirectory)) { IsRequired = false };
internal static readonly Option<DirectoryInfo> RepoRootOption = new("--repo-root") { IsRequired = true };
internal static readonly Option<FileSystemInfo> WorkspaceOption = new("--workspace") { IsRequired = true };
internal static readonly Option<string> OutputOption = new("--output", () => DiscoveryWorker.DiscoveryResultFileName) { IsRequired = false };
internal static readonly Option<FileInfo> OutputOption = new("--output") { IsRequired = true };
internal static readonly Option<bool> VerboseOption = new("--verbose", getDefaultValue: () => false);

internal static Command GetCommand(Action<int> setExitCode)
Expand All @@ -27,7 +27,7 @@ internal static Command GetCommand(Action<int> setExitCode)
command.SetHandler(async (repoRoot, workspace, outputPath, verbose) =>
{
var worker = new DiscoveryWorker(new Logger(verbose));
await worker.RunAsync(repoRoot.FullName, workspace.FullName, outputPath);
await worker.RunAsync(repoRoot.FullName, workspace.FullName, outputPath.FullName);
}, RepoRootOption, WorkspaceOption, OutputOption, VerboseOption);

return command;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ internal static async Task<int> Main(string[] args)
{
FrameworkCheckCommand.GetCommand(setExitCode),
DiscoverCommand.GetCommand(setExitCode),
AnalyzeCommand.GetCommand(setExitCode),
UpdateCommand.GetCommand(setExitCode),
};
command.TreatUnmatchedTokensAsErrors = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using System.Collections.Immutable;
using System.Text.Json;

using NuGetUpdater.Core.Analyze;
using NuGetUpdater.Core.Discover;
using NuGetUpdater.Core.Test.Utilities;

using Xunit;

namespace NuGetUpdater.Core.Test.Analyze;

using TestFile = (string Path, string Content);

public class AnalyzeWorkerTestBase
{
protected static async Task TestAnalyzeAsync(
WorkspaceDiscoveryResult discovery,
DependencyInfo dependencyInfo,
ExpectedAnalysisResult expectedResult)
{
var relativeDependencyPath = $"./dependabot/dependency/{dependencyInfo.Name}.json";

TestFile[] files = [
(DiscoveryWorker.DiscoveryResultFileName, JsonSerializer.Serialize(discovery, AnalyzeWorker.SerializerOptions)),
(relativeDependencyPath, JsonSerializer.Serialize(dependencyInfo, AnalyzeWorker.SerializerOptions)),
];

var actualResult = await RunAnalyzerAsync(dependencyInfo.Name, files, async directoryPath =>
{
var discoveryPath = Path.GetFullPath(DiscoveryWorker.DiscoveryResultFileName, directoryPath);
var dependencyPath = Path.GetFullPath(relativeDependencyPath, directoryPath);
var analysisPath = Path.GetFullPath(AnalyzeWorker.AnalysisDirectoryName, directoryPath);

var worker = new AnalyzeWorker(new Logger(verbose: true));
await worker.RunAsync(discoveryPath, dependencyPath, analysisPath);
});

ValidateAnalysisResult(expectedResult, actualResult);
}

protected static void ValidateAnalysisResult(ExpectedAnalysisResult expectedResult, AnalysisResult actualResult)
{
Assert.NotNull(actualResult);
Assert.Equal(expectedResult.UpdatedVersion, actualResult.UpdatedVersion);
Assert.Equal(expectedResult.CanUpdate, actualResult.CanUpdate);
Assert.Equal(expectedResult.VersionComesFromMultiDependencyProperty, actualResult.VersionComesFromMultiDependencyProperty);
ValidateDependencies(expectedResult.UpdatedDependencies, actualResult.UpdatedDependencies);
Assert.Equal(expectedResult.ExpectedUpdatedDependenciesCount ?? expectedResult.UpdatedDependencies.Length, actualResult.UpdatedDependencies.Length);

return;

void ValidateDependencies(ImmutableArray<Dependency> expectedDependencies, ImmutableArray<Dependency> actualDependencies)
{
if (expectedDependencies.IsDefault)
{
return;
}

foreach (var expectedDependency in expectedDependencies)
{
var actualDependency = actualDependencies.Single(d => d.Name == expectedDependency.Name);
Assert.Equal(expectedDependency.Name, actualDependency.Name);
Assert.Equal(expectedDependency.Version, actualDependency.Version);
Assert.Equal(expectedDependency.Type, actualDependency.Type);
AssertEx.Equal(expectedDependency.TargetFrameworks, actualDependency.TargetFrameworks);
Assert.Equal(expectedDependency.IsDirect, actualDependency.IsDirect);
Assert.Equal(expectedDependency.IsTransitive, actualDependency.IsTransitive);
}
}
}

protected static async Task<AnalysisResult> RunAnalyzerAsync(string dependencyName, TestFile[] files, Func<string, Task> action)
{
// write initial files
using var temporaryDirectory = await TemporaryDirectory.CreateWithContentsAsync(files);

// run discovery
await action(temporaryDirectory.DirectoryPath);

// gather results
var resultPath = Path.Join(temporaryDirectory.DirectoryPath, AnalyzeWorker.AnalysisDirectoryName, $"{dependencyName}.json");
var resultJson = await File.ReadAllTextAsync(resultPath);
return JsonSerializer.Deserialize<AnalysisResult>(resultJson, DiscoveryWorker.SerializerOptions)!;
}
}
Loading
Loading