Repository navigation
Fix vendored NuGet revert on CRLF checkouts (#537) - #1342
Mikola Lysenko (mikolalysenko) wants to merge 7 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
Vendored NuGet now reads the source keys and finds the <packageSources>, <packageSourceMapping> and <configuration> anchors through formats::nuget::parse_config, the reader that hosted, upstream restore and VEX already use. The private substring scanner (blank_comments, parse_config_source_keys, attr_value, self_closing_package_sources, insert_at_line) is deleted. User impact: - A close tag written with whitespace (</packageSources >) is now the section that gets extended; vendor used to append a second section NuGet ignores, so restore failed NU1100/NU1403 (#685). - An empty <packageSourceMapping /> is expanded in place instead of left beside a second mapping section. - A section opened and closed on one line receives the source inside it, not before its open tag. - Catch-all keys are written XML-encoded, so a key with & or a quote keeps its identity. - Malformed XML or a repeated section is refused with "malformed XML or a repeated section; not wired" instead of being spliced at the first substring match, as hosted already does. Output bytes for well-formed configs are unchanged. Fixes #685 Refs #594 Assisted-by: Claude Code:claude-opus-5-5
…-config' into agent/v5-nuget-crlf-revert
Draft placeholder while the fix is written. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
After a core.autocrlf checkout (Git for Windows' default) nuget.config comes back CRLF. vendor --revert, remove and rollback compared it with the LF text vendor recorded, treated it as drift and left it wired, but had already put packages.lock.json back to the upstream contentHash, so every later restore failed NU1403 while --revert exited 0. The config restore now compares and excises line-ending-insensitively and writes the original back in the checkout's line endings. And the lock pin is only reverted when the config stops routing to the vendored feed: a drift-kept config keeps its lock pin too, so the project stays consistently vendored instead of half-reverted. Fixes #537. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
BugBot review |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issue.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit fb711df. Configure here.
| let mapping_block = excise_source_mapping(&live, source_key); | ||
| let nl = terminator(&live); | ||
| let source_add = format!(" <add key=\"{source_key}\" value=\"{uuid_dir_rel}\" />{nl}"); | ||
| let mapping_block = excise_source_mapping(&live, source_key, nl); |
There was a problem hiding this comment.
Revert misses mixed-EOL fragments
Medium Severity
Fragment revert now searches for terminator spellings of the source <add> and mapping block, but build_config_edit still inserts those elements with \n. An existing CRLF nuget.config therefore becomes mixed, so a later sibling vendor or edit takes the fragment path, the CRLF-majority search misses the LF fragments, and --revert drift-keeps the package.
Additional Locations (2)
Triggered by learned rule: CRLF-aware regexes when matching user workspace file content
Reviewed by Cursor Bugbot for commit fb711df. Configure here.
There was a problem hiding this comment.
[agent] Fixed in 5eebde2: the excision tries the LF spelling vendor writes first, then the file's own terminator. New test revert_excises_lf_fragments_from_a_mixed_crlf_config (CRLF config with a mapping, vendored, CRLF sibling added, revert clean with no drift warning).
| // source key (the mapping `<packageSource>`). | ||
| let source_add = format!(" <add key=\"{source_key}\" value=\"{uuid_dir_rel}\" />\n"); | ||
| let mapping_block = excise_source_mapping(&live, source_key); | ||
| let nl = terminator(&live); |
There was a problem hiding this comment.
[agent] The forward pass (build_config_edit) always inserts LF fragments, even into a CRLF nuget.config, but the revert now looks for them spelled in terminator(&live), which is the majority ending for a mixed file. Scenario: Windows autocrlf tree with an existing CRLF nuget.config; vendor package A, then the file changes before any git round-trip (a second vendored package or a user edit adds CRLF lines), which sends A's revert down the fragment path. The original CRLF lines outnumber our LF ones, so our <add> / <packageSource> aren't found → false drift: config stays wired, lock pin and artifact kept, vendor_lock_entry_drifted + vendor_artifact_kept. I reproduced it with an 11-line CRLF config that already has a mapping section, vendoring once, adding a CRLF sibling <add key="corp">, then reverting. On fb711df^ it reverts cleanly (byte-correct CRLF file, lock reverted, artifact removed); on fb711df it's left wired with warnings. Nothing is corrupted, but it's a regression in the setting this PR targets. Trying the LF spelling (what the forward pass writes) first and falling back to terminator(&live), in both the source_add excision here and excise_source_mapping (~L1234-1240), plus a mixed-file sibling test, would fix it.
There was a problem hiding this comment.
[agent] Fixed in 5eebde2: the excision tries the LF spelling vendor writes first, then the file's own terminator. New test revert_excises_lf_fragments_from_a_mixed_crlf_config (CRLF config with a mapping, vendored, CRLF sibling added, revert clean with no drift warning).
Vendor inserts LF lines even into a CRLF nuget.config, which stays mixed until git converts it. A sibling edit then sent the revert down the excision path, where the CRLF-majority spelling missed our LF fragments and drift-kept the package (review on #1342). The excision now tries the LF spelling first, then the file's own terminator. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>


LLM Description written by Claude Code:claude-opus-5-5
Fixes #537
Summary
vendor --revert,removeandrollbackof a vendored NuGet package now fully revert bothnuget.configandpackages.lock.jsonon acore.autocrlfcheckout. They also never leave the project half-reverted.Root cause
nuget.config. After an autocrlf checkout the file is CRLF, and the revert's whole-file fast path (w.new == live) and its fragment excision (LF-anchored<add …/>\nand<packageSource …>\n) both missed. The config was treated as drift and left wired.contentHash, under a config that still maps the id exclusively to the vendored feed. Every restore then failed NU1403, whilevendor --revertexited 0.Fix
revert_config_recordcompares withutils::line_endings::eol_eq. When the checkout changed the line endings, the original is restored spelled in the live file's endings (respell+terminator). The excision looks for our fragments in the file's own terminator.revert_nuget_optsfirst previews the config restore (read-only). If the config will be drift-kept and still names the vendored feed dir, the lock pin is kept too (vendor_lock_entry_drifted: "… still routes … so its packages.lock.json pin is kept"). The package stays consistently vendored, and the existing drift-keep keeps the artifact. The lock still reverts first otherwise, so a lock I/O failure still leaves the config wired for a retry (fifo_lockfile_fails_fast_in_revertunchanged).vendor --revertdrift rules.Per-issue tests (vendor::nuget_feed::tests)
revert_on_an_autocrlf_checkout_restores_config_and_lock: pre-existing config. After CRLF conversion of both files, revert restores both in CRLF with no warnings, and the feed is removed.revert_on_an_autocrlf_checkout_deletes_a_created_configrevert_excises_our_crlf_fragments_beside_a_siblingdrift_kept_config_keeps_the_lock_pin: the half-revert guard.Red→green: before the fix, the first three fail with
vendor_lock_entry_drifted/ config left wired, and the last shows the lock reverted under a wired config.Commands run
cargo test -p socket-patch-core --lib nuget_feed(96) and--lib nuget: green (the only failures are 2crawlers::nuget_crawlertests that pick up this machine's real~/.nuget/packages, also failing on main locally)cargo test -p socket-patch-cli --all-features --test e2e_nuget(21) and--test e2e_nuget_dotnet_build -- --ignored(2, local SDK 8.0.129): greencargo clippy --workspace --all-features -- -D warnings: clean.cargo fmt --check: clean for touched files.Includes #1288's commits (approved, about to merge).
🤖 Generated with Claude Code
Note
Medium Risk
Changes NuGet vendor revert and
nuget.configmutation paths that affect restore correctness; behavior is guarded by extensive new tests but mistakes could break revert or lock/config consistency.Overview
NuGet vendor revert now treats
nuget.configas unchanged when only line endings differ (core.autocrlf/ CRLF checkouts), restoring the original config in the checkout’s EOL and matching fragment excision to the live file’s terminators instead of falsely marking drift (#537).When revert would drift-keep a config that still routes a package id to the vendored feed,
packages.lock.jsonpins are kept too (vendor_lock_entry_drifted), avoiding a half-revert that reverted the lock under a still-wired feed (NU1403).Config wiring/editing drops comment-blanking and string scans in favor of the shared
formats::nuget::parse_configreader (with refusal on malformed/repeated sections), plusinsert_children/insert_before_closeandxml_attributefor round-tripping source keys. In-sync detection uses the same parser. CLI_CONTRACT.md documents the NuGet revert drift rules for v5.0.Reviewed by Cursor Bugbot for commit fb711df. Configure here.