Skip to content

Commit

Permalink
consolidate exception error creation
Browse files Browse the repository at this point in the history
  • Loading branch information
brettfo committed Jan 22, 2025
1 parent 6b32887 commit 4307515
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using System.Collections.Immutable;
using System.Text.Json;

using NuGet.Build.Tasks;

using NuGetUpdater.Core.Run;
using NuGetUpdater.Core.Run.ApiModel;
using NuGetUpdater.Core.Test.Update;

using Xunit;
Expand Down Expand Up @@ -1366,6 +1367,75 @@ await File.WriteAllTextAsync(projectPath, """
}
#endregion

[Theory]
[MemberData(nameof(GenerateErrorFromToolOutputTestData))]
public async Task GenerateErrorFromToolOutput(string output, JobErrorBase? expectedError)
{
Exception? exception = null;
try
{
MSBuildHelper.ThrowOnError(output);
}
catch (Exception ex)
{
exception = ex;
}

if (expectedError is null)
{
Assert.Null(exception);
}
else
{
Assert.NotNull(exception);
using var tempDir = await TemporaryDirectory.CreateWithContentsAsync([("NuGet.Config", """
<configuration>
<packageSources>
<clear />
<add key="test-feed" value="http://localhost/test-feed" />
</packageSources>
</configuration>
""")]);
var actualError = JobErrorBase.ErrorFromException(exception, "TEST-JOB-ID", tempDir.DirectoryPath);
if (actualError is DependencyFileNotFound notFound)
{
// normalize default message for the test
actualError = new DependencyFileNotFound(notFound.Details["file-path"].ToString()!, "test message");
}

var actualErrorJson = JsonSerializer.Serialize(actualError, RunWorker.SerializerOptions);
var expectedErrorJson = JsonSerializer.Serialize(expectedError, RunWorker.SerializerOptions);
Assert.Equal(expectedErrorJson, actualErrorJson);
}
}

public static IEnumerable<object[]> GenerateErrorFromToolOutputTestData()
{
yield return
[
// output
"Response status code does not indicate success: 403",
// expectedError
new PrivateSourceAuthenticationFailure(["http://localhost/test-feed"]),
];

yield return
[
// output
"The imported file \"some.file\" does not exist",
// expectedError
new DependencyFileNotFound("some.file", "test message"),
];

yield return
[
// output
"Package 'Some.Package' is not found on source",
// expectedError
new UpdateNotPossible(["Some.Package"]),
];
}

public static IEnumerable<object[]> GetTopLevelPackageDependencyInfosTestData()
{
// simple case
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public static async Task<ImmutableArray<ProjectDiscoveryResult>> DiscoverWithBin
var (exitCode, stdOut, stdErr) = await ProcessEx.RunDotnetWithoutMSBuildEnvironmentVariablesAsync(args, startingProjectDirectory, experimentsManager);
return (exitCode, stdOut, stdErr);
}, logger, retainMSBuildSdks: true);
MSBuildHelper.ThrowOnUnauthenticatedFeed(stdOut);
MSBuildHelper.ThrowOnError(stdOut);
if (stdOut.Contains("""error MSB4057: The target "GenerateBuildDependencyFile" does not exist in the project."""))
{
// this can happen if it's a non-SDK-style project; totally normal, not worth examining the binlog
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ await MSBuildHelper.HandleGlobalJsonAsync(projectDirectory, repoRootPath, experi
projectDirectory,
experimentsManager
);
MSBuildHelper.ThrowOnUnauthenticatedFeed(stdout);
MSBuildHelper.ThrowOnError(stdout);
if (exitCode != 0)
{
logger.Warn($" Transitive dependency [{dependencyName}/{newDependencyVersion}] was not added.\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,18 +148,15 @@ private static void RunNugetUpdate(List<string> updateArgs, List<string> restore

if (exitCodeAgain != 0)
{
MSBuildHelper.ThrowOnMissingFile(fullOutput);
MSBuildHelper.ThrowOnMissingFile(restoreOutput);
MSBuildHelper.ThrowOnMissingPackages(restoreOutput);
MSBuildHelper.ThrowOnError(fullOutput);
MSBuildHelper.ThrowOnError(restoreOutput);
throw new Exception($"Unable to restore.\nOutput:\n${restoreOutput}\n");
}

goto doRestore;
}

MSBuildHelper.ThrowOnUnauthenticatedFeed(fullOutput);
MSBuildHelper.ThrowOnMissingFile(fullOutput);
MSBuildHelper.ThrowOnMissingPackages(fullOutput);
MSBuildHelper.ThrowOnError(fullOutput);
throw new Exception(fullOutput);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -903,21 +903,6 @@ ILogger logger
}
}

internal static void ThrowOnUnauthenticatedFeed(string stdout)
{
var unauthorizedMessageSnippets = new string[]
{
"The plugin credential provider could not acquire credentials",
"401 (Unauthorized)",
"error NU1301: Unable to load the service index for source",
"Response status code does not indicate success: 403",
};
if (unauthorizedMessageSnippets.Any(stdout.Contains))
{
throw new HttpRequestException(message: stdout, inner: null, statusCode: System.Net.HttpStatusCode.Unauthorized);
}
}

internal static string? GetMissingFile(string output)
{
var missingFilePatterns = new[]
Expand All @@ -934,7 +919,29 @@ internal static void ThrowOnUnauthenticatedFeed(string stdout)
return null;
}

internal static void ThrowOnMissingFile(string output)
internal static void ThrowOnError(string output)
{
ThrowOnUnauthenticatedFeed(output);
ThrowOnMissingFile(output);
ThrowOnMissingPackages(output);
}

private static void ThrowOnUnauthenticatedFeed(string stdout)
{
var unauthorizedMessageSnippets = new string[]
{
"The plugin credential provider could not acquire credentials",
"401 (Unauthorized)",
"error NU1301: Unable to load the service index for source",
"Response status code does not indicate success: 403",
};
if (unauthorizedMessageSnippets.Any(stdout.Contains))
{
throw new HttpRequestException(message: stdout, inner: null, statusCode: System.Net.HttpStatusCode.Unauthorized);
}
}

private static void ThrowOnMissingFile(string output)
{
var missingFile = GetMissingFile(output);
if (missingFile is not null)
Expand All @@ -943,9 +950,9 @@ internal static void ThrowOnMissingFile(string output)
}
}

internal static void ThrowOnMissingPackages(string output)
private static void ThrowOnMissingPackages(string output)
{
var missingPackagesPattern = new Regex(@"Package '(?<PackageName>[^'].*)' is not found on source");
var missingPackagesPattern = new Regex(@"Package '(?<PackageName>[^']*)' is not found on source");
var matchCollection = missingPackagesPattern.Matches(output);
var missingPackages = matchCollection.Select(m => m.Groups["PackageName"].Value).Distinct().ToArray();
if (missingPackages.Length > 0)
Expand Down

0 comments on commit 4307515

Please sign in to comment.