start-vs-VisualFSharpSln.ps1: build against a locally built hive Roslyn from its own packages - #20528
xperiandri wants to merge 3 commits into
Conversation
F5 loads the extension into a hive (RootSuffix), and that hive's own deployed Roslyn wins over the installed VS's when one is present: a locally built Roslyn deployed there stamps itself 42.42.42.42 and redirects every reference to itself via a hive-level binding redirect. The script detected the installed VS's Roslyn version and overrode the repo's packages to match it unconditionally, which built against the wrong version whenever the target hive carried its own Roslyn - RoslynDev in particular, the hive this repo's own DEVGUIDE points contributors at. It now reads devenv.isolation.ini to find the hive's own Extensions folder first, and only falls back to the installed VS's Roslyn when the hive has none of its own. A new -RootSuffix parameter names the hive (default RoslynDev, matching the VisualFSharpDebug launch profile). When the detected version's minor matches what the repo's Version.Details.props already flows, no override is written at all - the common case for a hive built from this same source - and a locally built hive Roslyn with no package version at all now fails fast asking for one instead of silently building against packages that do not match what will actually load. The override file also moves to its own path (RoslynOverride.start-vs.props) so a build-vs-VisualFSharpSln.ps1 run in the same session cannot silently overwrite it, since a long-lived VS process restores against whatever CustomAfterMicrosoftCommonProps last pointed at. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
-RootSuffix only chose which hive to read the Roslyn version from: the VSIX projects hard-coded VSRootSuffix to RoslynDev, and that is both the hive F5 deploys into and the /rootsuffix launchSettings passes, so -RootSuffix Foo built against Foo's Roslyn and then ran in RoslynDev. VSRootSuffix now defaults to RoslynDev only when nothing set it, and the script hands its suffix to the Visual Studio it launches, whose builds read it from the environment. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A Roslyn built locally and deployed into the hive is there because its API surface differs from the flowed package: it is where an ExternalAccess contract lives before it flows. Matching the minor the repo flows therefore says nothing about whether the flowed packages will do, and refusing the dev version left no way to build against the Roslyn F5 actually runs. A dev version now always overrides, and the override adds the package folders of that Roslyn build to RestoreAdditionalProjectSources, since no feed carries its version. -RoslynRepo names the repository, next to this one by default, and the script checks that it actually holds the package before restore fails halfway with NU1101. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
✅ No release notes required |
This comment has been minimized.
This comment has been minimized.
|
🔍 Tooling Safety Check — Affects-Build-Infra, Affects-Restore
|
T-Gro
left a comment
There was a problem hiding this comment.
🤖 🕵️ AI review — verify independently.
| # RestoreAdditionalProjectSources has to arrive through the props import rather than on the command | ||
| # line: Microsoft.FSharp.NetSdk.targets declares it TreatAsLocalProperty and appends to it. | ||
| $sources = | ||
| if ($feeds) { "<RestoreAdditionalProjectSources>`$(RestoreAdditionalProjectSources);$($feeds -join ';')</RestoreAdditionalProjectSources>" } |
There was a problem hiding this comment.
🤖 🕵️ [P2] Repacked Roslyn packages ignored when the -dev version is unchanged: restore succeeds with the previous contents from NuGet's global-packages cache, despite the updated local feed.
.\start-vs-VisualFSharpSln.ps1 -RoslynVersion 5.10.0-dev -RoslynRepo 'C:\src\roslyn'
# Change Roslyn APIs, rebuild and repack as the same 5.10.0-dev version.
.\start-vs-VisualFSharpSln.ps1 -RoslynVersion 5.10.0-dev -RoslynRepo 'C:\src\roslyn'
# Still consumes the first build's packages until their cache entries are removed.| throw "$RootSuffix runs a locally built Roslyn $version, which only its own packages provide, but there is no repository at $repo; pass -RoslynRepo." | ||
| } | ||
|
|
||
| $feeds = 'Shipping', 'NonShipping' | ForEach-Object { Join-Path $repo "artifacts\packages\Release\$_" } |
There was a problem hiding this comment.
🤖 🕵️ [P2] Valid relative repository passes validation but nested projects fail restore with NU1301: NuGet resolves the emitted relative sources against each project directory, not the launcher's working directory.
# From the F# checkout, with packed Roslyn packages in the sibling checkout:
.\start-vs-VisualFSharpSln.ps1 -RoslynVersion 5.12.0-dev -RoslynRepo '..\roslyn'| # RestoreAdditionalProjectSources has to arrive through the props import rather than on the command | ||
| # line: Microsoft.FSharp.NetSdk.targets declares it TreatAsLocalProperty and appends to it. | ||
| $sources = | ||
| if ($feeds) { "<RestoreAdditionalProjectSources>`$(RestoreAdditionalProjectSources);$($feeds -join ';')</RestoreAdditionalProjectSources>" } |
There was a problem hiding this comment.
🤖 🕵️ [P2] & in an existing repository path makes the generated override invalid XML; restore stops with MSB4024 while parsing the unescaped feed path.
.\start-vs-VisualFSharpSln.ps1 -RoslynVersion 5.12.0-dev -RoslynRepo 'C:\src\roslyn&tree'| # less about that than a message here does. | ||
| function Get-RoslynDevFeeds([string]$repo, [string]$version) { | ||
| if (-not $repo) { $repo = Join-Path (Split-Path $PSScriptRoot) 'roslyn' } | ||
| if (-not (Test-Path $repo)) { |
There was a problem hiding this comment.
🤖 🕵️ [P2] Existing roslyn[1] repository rejected as nonexistent: both new Test-Path checks interpret brackets as wildcards instead of literal path characters.
.\start-vs-VisualFSharpSln.ps1 -RoslynVersion 5.12.0-dev -RoslynRepo 'C:\src\roslyn[1]'
Description
Depends on #20467, which is the base of this branch. Only the last commit, "Build against a locally built hive Roslyn from its own packages", belongs to this pull request; please review it after #20467 merges.
#20467 teaches the script to read the Roslyn deployed in the target hive. When that Roslyn is a local build (a
-devversion), it either matched the minor the repo flows and wrote no override, or stopped and asked for-RoslynVersion. Neither builds against the Roslyn F5 actually runs.A Roslyn is built locally and deployed into a hive because its API surface differs from the flowed package: it is where an ExternalAccess contract lives before it flows. So a matching minor says nothing about whether the flowed packages will do, and asking for a published version gives up on the one that differs.
With this change:
-devversion always overrides the flowed packages.RestoreAdditionalProjectSources, because no feed carries its version. This has to go through the props import:Microsoft.FSharp.NetSdk.targetsdeclares the propertyTreatAsLocalPropertyand appends to it, so a command-line value would not survive.-RoslynReponames the Roslyn repository, defaulting to aroslynfolder next to this one. The script checks that it holds the package for that version and says so, instead of restore failing halfway with NU1101.Shipped Roslyn versions behave as in #20467.
Checked with
-DryRun:RoslynDevShippingandNonShippingpackage foldersFooRoslynDevwith-RoslynRepo C:\no-such-roslynTooling only; no compiler or IDE code path changes, so no release notes entry.
Checklist
🤖 Generated with Claude Code