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

Properly reject NuGet newline-only changes. #10332

Merged
merged 7 commits into from
Aug 1, 2024

Conversation

brettfo
Copy link
Contributor

@brettfo brettfo commented Jul 31, 2024

An update to #10324, but since I didn't have permissions to update that fork/branch, I've created a new PR here with the same commit history.

Fixes #10323

Thanks to @rhyskoedijk for identifying the issue and figuring out a solution.

A short description of the original problem

The NuGet updater attempts to detect newline-only changes and reject them, but the logic for that detection was flawed. An example of this was a file in a repo with a trailing newline where the contents were updated and the trailing newline was deleted. This was erroneously determined to be a newline-only change and wasn't included in the PR.

What to do about it

The fix is to compare the original and updated lines, ignoring blank lines and whitespace, and if there are no differences, reject the change, otherwise keep them.

There was also a rearranging in the product code to enable direct testing of the relevant method, along with a bunch of test cases.

@brettfo brettfo requested a review from a team as a code owner July 31, 2024 21:57
@github-actions github-actions bot added the L: dotnet:nuget NuGet packages via nuget or dotnet label Jul 31, 2024
@brettfo brettfo changed the title Dev/brettfo/nuget reject whitespace changes Properly reject NuGet newline-only changes. Jul 31, 2024
@brettfo brettfo force-pushed the dev/brettfo/nuget-reject-whitespace-changes branch from 208ae8f to f834d5c Compare July 31, 2024 22:19

it "does not update the project" do
run_update_test do |updater|
expect(updater.updated_dependency_files.map(&:name)).to be_empty
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test case was wrong; it was the case where a file was updated and a trailing newline was removed and it was erroneously detected as just deleting the trailing newline, which wasn't correct because the contents actually changed. This scenario is covered in the new tests below.

Copy link
Contributor

@rhyskoedijk rhyskoedijk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this makes sense to me and fixes my problem. thanks.

I raised one comment to double check that the original scenario hasn't regressed as my understanding of the code isn't super great. I might just be misunderstanding that particular problem.

@@ -45,7 +59,7 @@ def updated_dependency_files
normalized_content = normalize_content(f, updated_content)
next if normalized_content == f.content

next if only_deleted_lines?(f.content, normalized_content)
next unless FileUpdater.differs_in_more_than_blank_lines?(f.content, normalized_content)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the original scenario (#9162) still pass here?

If the updated content has less lines than the original content, then a package has been removed somewhere and we likely don't want to create a pull request.

Maybe there needs to be a test for this as well, unless there are other checks elsewhere to deal with this problem now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, that was a test case I missed. I just pushed a commit that adds this test case if you want to double check I understood the issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reading your comment I think there is a separate issue to address; what if a package is removed? I think that should be handled in the C# code that actually checks the file content. This part of the code is to handle silliness around empty lines. There's likely a bigger work item to ensure that a dependency isn't removed, but we have better unit tests in the C# code for that. Do you have a scenario where a package was removed?

Copy link
Contributor

@rhyskoedijk rhyskoedijk Jul 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding of the description in #9162 is that if you had a project like this:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net461</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="DependencyA" Version="1.0.0" />
  </ItemGroup>
</Project>

And NuGetUpdater attempted to update "DependencyA" to "2.0.0" but failed and rolled back e.g.

WARNING: Install failed. Rolling back...

It would remove the dependency entirely and result in a project file like:

~~~
@@ -2,7 +2,4 @@
   <PropertyGroup>
     <TargetFramework>net461</TargetFramework>
   </PropertyGroup>
-  <ItemGroup>
-    <PackageReference Include="DependencyA" Version="1.0.0" />
-  </ItemGroup>
 </Project>
\ No newline at end of file

In this scenario, the file is different, but it is different in a way that the PR should not be created because the change isn't desired. I could be misunderstanding this problem though.

Maybe the original issue shouldn't have been solved in file_updater and instead the "rollback" warning should be escalated as an error by the native NuGet updater instead? Maybe this scenario isn't even valid anymore, in which case, ignore me.

I'll let you decide what is correct here as you understand this all better than me.
Ultimately this change solves my specific problem, so I'm happy with it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say the scenario you presented should be handled purely in C#. Let's take this PR as is, because it does fix a class of errors that we're currently seeing and I'll look at the rollback scenario tomorrow and see if I can nail down what might cause that. There appears to be enough information in the linked issue to sort it out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rhyskoedijk I filed issue #10342 to track this other scenario and I'm working on it now. Rough ETA, sometime next week. I think the best mechanism to prevent this kind of error is to only report available package upgrades if all transitive dependencies can be resolved so that we never try to update when it's not fully resolvable (the base scenario that #9162 was trying to address).

@abdulapopoola abdulapopoola merged commit 8070e76 into main Aug 1, 2024
67 checks passed
@abdulapopoola abdulapopoola deleted the dev/brettfo/nuget-reject-whitespace-changes branch August 1, 2024 01:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
L: dotnet:nuget NuGet packages via nuget or dotnet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Updates to dotnet-tools.json with white-space lines cause "Passed nil into T.must" errors
4 participants