diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/CreateSecurityUpdatePullRequestHandlerTests.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/CreateSecurityUpdatePullRequestHandlerTests.cs index 6d6093811a4..3834b950e12 100644 --- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/CreateSecurityUpdatePullRequestHandlerTests.cs +++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/CreateSecurityUpdatePullRequestHandlerTests.cs @@ -763,4 +763,97 @@ await TestAsync( ] ); } + + [Fact] + public async Task ErrantFileUpdatesDoNotCauseCallToCreatePullRequest() + { + // if an external tool inadvertently updates files on disk without reporting any update operations, don't try + // to create a PR + await TestAsync( + job: new Job() + { + Dependencies = ["Some.Dependency"], + SecurityAdvisories = [new() { DependencyName = "Some.Dependency", AffectedVersions = [Requirement.Parse("= 1.0.0")] }], + SecurityUpdatesOnly = true, + Source = CreateJobSource("/src"), + }, + files: [ + ("src/project.csproj", "initial project contents"), + ("src/packages.config", "initial packages contents"), + ], + discoveryWorker: TestDiscoveryWorker.FromResults( + ("/src", new WorkspaceDiscoveryResult() + { + Path = "/src", + Projects = [ + new() + { + FilePath = "project.csproj", + Dependencies = [ + new("Some.Dependency", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net9.0"]), + ], + ImportedFiles = [], + AdditionalFiles = ["packages.config"], + } + ], + }) + ), + analyzeWorker: new TestAnalyzeWorker(async input => + { + var repoRoot = input.Item1; + var discovery = input.Item2; + var dependencyInfo = input.Item3; + if (dependencyInfo.Name != "Some.Dependency") + { + throw new NotImplementedException($"Test didn't expect to update dependency {dependencyInfo.Name}"); + } + + // no update possible but a file was touched on disk + var projectPath = Path.Join(repoRoot, discovery.Path, discovery.Projects.Single().FilePath); + var packagesConfigPath = Path.Join(Path.GetDirectoryName(projectPath), "packages.config"); + await File.WriteAllTextAsync(packagesConfigPath, "updated packages contents"); + + return new AnalysisResult() + { + CanUpdate = false, + UpdatedVersion = "1.0.0", + UpdatedDependencies = [], + }; + }), + updaterWorker: new TestUpdaterWorker(async input => + { + return new UpdateOperationResult() + { + UpdateOperations = [], + }; + }), + expectedUpdateHandler: CreateSecurityUpdatePullRequestHandler.Instance, + expectedApiMessages: [ + new UpdatedDependencyList() + { + Dependencies = [ + new() + { + Name = "Some.Dependency", + Version = "1.0.0", + Requirements = [ + new() { Requirement = "1.0.0", File = "/src/project.csproj", Groups = ["dependencies"] }, + ], + }, + ], + DependencyFiles = ["/src/packages.config", "/src/project.csproj"], + }, + new IncrementMetric() + { + Metric = "updater.started", + Tags = new() + { + ["operation"] = "create_security_pr", + } + }, + new SecurityUpdateNotFound("Some.Dependency", "1.0.0"), + new MarkAsProcessed("TEST-COMMIT-SHA"), + ] + ); + } } diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/CreateSecurityUpdatePullRequestHandler.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/CreateSecurityUpdatePullRequestHandler.cs index ee1616e290a..441077d9a25 100644 --- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/CreateSecurityUpdatePullRequestHandler.cs +++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/CreateSecurityUpdatePullRequestHandler.cs @@ -157,7 +157,7 @@ public async Task HandleAsync(Job job, DirectoryInfo originalRepoContentsPath, D } } - if (updatedDependencyFiles.Length > 0) + if (updateOperationsPerformed.Count > 0 && updatedDependencyFiles.Length > 0) { var commitMessage = PullRequestTextGenerator.GetPullRequestCommitMessage(job, [.. updateOperationsPerformed], null); var prTitle = PullRequestTextGenerator.GetPullRequestTitle(job, [.. updateOperationsPerformed], null);