From 37f951d3e842896ced6ad8c22aee000e2770144b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 16 Sep 2025 11:03:36 +0000
Subject: [PATCH 01/10] Initial plan
From 633e5172e892e7771ff4baa2fbd88d7f595064c9 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 16 Sep 2025 11:33:21 +0000
Subject: [PATCH 02/10] Implement centralized VS installation discovery
infrastructure
Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
---
.../FSharp.Editor.Tests.fsproj | 1 +
.../Helpers/AssemblyResolver.fs | 31 ++--
.../tests/Salsa/VisualFSharp.Salsa.fsproj | 1 +
vsintegration/tests/Salsa/VsMocks.fs | 22 +--
.../tests/TestHelpers/TestHelpers.fsproj | 32 ++++
.../tests/TestHelpers/VSInstallDiscovery.fs | 144 ++++++++++++++++++
.../tests/UnitTests/AssemblyResolver.fs | 23 +--
.../UnitTests/VisualFSharp.UnitTests.fsproj | 1 +
8 files changed, 224 insertions(+), 31 deletions(-)
create mode 100644 vsintegration/tests/TestHelpers/TestHelpers.fsproj
create mode 100644 vsintegration/tests/TestHelpers/VSInstallDiscovery.fs
diff --git a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj
index c084fc6f06..d0a264e868 100644
--- a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj
+++ b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj
@@ -105,6 +105,7 @@
+
diff --git a/vsintegration/tests/FSharp.Editor.Tests/Helpers/AssemblyResolver.fs b/vsintegration/tests/FSharp.Editor.Tests/Helpers/AssemblyResolver.fs
index f41f10fa13..98db3e27df 100644
--- a/vsintegration/tests/FSharp.Editor.Tests/Helpers/AssemblyResolver.fs
+++ b/vsintegration/tests/FSharp.Editor.Tests/Helpers/AssemblyResolver.fs
@@ -8,21 +8,26 @@ open System.Reflection
module AssemblyResolver =
open System.Globalization
+ open Microsoft.VisualStudio.FSharp.TestHelpers.VSInstallDiscovery
let vsInstallDir =
- // use the environment variable to find the VS installdir
- let vsvar =
- let var = Environment.GetEnvironmentVariable("VS170COMNTOOLS")
-
- if String.IsNullOrEmpty var then
- Environment.GetEnvironmentVariable("VSAPPIDDIR")
- else
- var
-
- if String.IsNullOrEmpty vsvar then
- failwith "VS170COMNTOOLS and VSAPPIDDIR environment variables not found."
-
- Path.Combine(vsvar, "..")
+ // Use centralized VS installation discovery with graceful fallback
+ match tryGetVSInstallDir () with
+ | Some dir -> dir
+ | None ->
+ // Fallback to legacy behavior for backward compatibility
+ let vsvar =
+ let var = Environment.GetEnvironmentVariable("VS170COMNTOOLS")
+
+ if String.IsNullOrEmpty var then
+ Environment.GetEnvironmentVariable("VSAPPIDDIR")
+ else
+ var
+
+ if String.IsNullOrEmpty vsvar then
+ failwith "VS170COMNTOOLS and VSAPPIDDIR environment variables not found."
+
+ Path.Combine(vsvar, "..")
let probingPaths =
[|
diff --git a/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj b/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
index e1e657a651..1e806e423b 100644
--- a/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
+++ b/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
@@ -34,6 +34,7 @@
+
diff --git a/vsintegration/tests/Salsa/VsMocks.fs b/vsintegration/tests/Salsa/VsMocks.fs
index 5189b7faec..ab8901fcb7 100644
--- a/vsintegration/tests/Salsa/VsMocks.fs
+++ b/vsintegration/tests/Salsa/VsMocks.fs
@@ -1651,15 +1651,19 @@ module internal VsActual =
member public _.JoinableTaskContext : JoinableTaskContext = jtc
let vsInstallDir =
- // use the environment variable to find the VS installdir
- let vsvar =
- let var = Environment.GetEnvironmentVariable("VS170COMNTOOLS")
- if String.IsNullOrEmpty var then
- Environment.GetEnvironmentVariable("VSAPPIDDIR")
- else
- var
- if String.IsNullOrEmpty vsvar then failwith "VS170COMNTOOLS and VSAPPIDDIR environment variables not found."
- Path.Combine(vsvar, "..")
+ // Use centralized VS installation discovery with graceful fallback
+ match Microsoft.VisualStudio.FSharp.TestHelpers.VSInstallDiscovery.tryGetVSInstallDir () with
+ | Some dir -> dir
+ | None ->
+ // Fallback to legacy behavior for backward compatibility
+ let vsvar =
+ let var = Environment.GetEnvironmentVariable("VS170COMNTOOLS")
+ if String.IsNullOrEmpty var then
+ Environment.GetEnvironmentVariable("VSAPPIDDIR")
+ else
+ var
+ if String.IsNullOrEmpty vsvar then failwith "VS170COMNTOOLS and VSAPPIDDIR environment variables not found."
+ Path.Combine(vsvar, "..")
let CreateEditorCatalog() =
let thisAssembly = Assembly.GetExecutingAssembly().Location
diff --git a/vsintegration/tests/TestHelpers/TestHelpers.fsproj b/vsintegration/tests/TestHelpers/TestHelpers.fsproj
new file mode 100644
index 0000000000..7ab4b20231
--- /dev/null
+++ b/vsintegration/tests/TestHelpers/TestHelpers.fsproj
@@ -0,0 +1,32 @@
+
+
+
+ Library
+ net472
+ $(NoWarn);44;45;47;52;58;75;1204
+ true
+ true
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vsintegration/tests/TestHelpers/VSInstallDiscovery.fs b/vsintegration/tests/TestHelpers/VSInstallDiscovery.fs
new file mode 100644
index 0000000000..2ae105db98
--- /dev/null
+++ b/vsintegration/tests/TestHelpers/VSInstallDiscovery.fs
@@ -0,0 +1,144 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+/// Test-only Visual Studio installation discovery infrastructure.
+/// Provides a centralized, robust, and graceful discovery mechanism for Visual Studio installations
+/// used by integration/editor/unit tests under vsintegration/tests.
+[]
+module Microsoft.VisualStudio.FSharp.TestHelpers.VSInstallDiscovery
+
+open System
+open System.IO
+open System.Diagnostics
+
+/// Result of VS installation discovery
+type VSInstallResult =
+ | Found of installPath: string * source: string
+ | NotFound of reason: string
+
+/// Attempts to find a Visual Studio installation using multiple fallback strategies
+let tryFindVSInstallation () : VSInstallResult =
+
+ /// Check if a path exists and looks like a valid VS installation
+ let validateVSPath path =
+ if String.IsNullOrEmpty(path) then false
+ else
+ try
+ let fullPath = Path.GetFullPath(path)
+ Directory.Exists(fullPath) &&
+ Directory.Exists(Path.Combine(fullPath, "IDE")) &&
+ (File.Exists(Path.Combine(fullPath, "IDE", "devenv.exe")) ||
+ File.Exists(Path.Combine(fullPath, "IDE", "VSIXInstaller.exe")))
+ with
+ | _ -> false
+
+ /// Strategy 1: FSHARP_VS_INSTALL_DIR (explicit override for tests)
+ let tryExplicitOverride () =
+ let envVar = Environment.GetEnvironmentVariable("FSHARP_VS_INSTALL_DIR")
+ if validateVSPath envVar then
+ Some (Found (Path.GetFullPath(envVar), "FSHARP_VS_INSTALL_DIR environment variable"))
+ else None
+
+ /// Strategy 2: VSAPPIDDIR (derive parent of Common7/IDE)
+ let tryVSAppIdDir () =
+ let envVar = Environment.GetEnvironmentVariable("VSAPPIDDIR")
+ if not (String.IsNullOrEmpty(envVar)) then
+ try
+ let parentPath = Path.Combine(envVar, "..")
+ if validateVSPath parentPath then
+ Some (Found (Path.GetFullPath(parentPath), "VSAPPIDDIR environment variable"))
+ else None
+ with
+ | _ -> None
+ else None
+
+ /// Strategy 3: Highest version among VS*COMNTOOLS environment variables
+ let tryVSCommonTools () =
+ let vsVersions = [
+ ("VS170COMNTOOLS", 17) // Visual Studio 2022
+ ("VS160COMNTOOLS", 16) // Visual Studio 2019
+ ("VS150COMNTOOLS", 15) // Visual Studio 2017
+ ("VS140COMNTOOLS", 14) // Visual Studio 2015
+ ("VS120COMNTOOLS", 12) // Visual Studio 2013
+ ]
+
+ vsVersions
+ |> List.tryPick (fun (envName, version) ->
+ let envVar = Environment.GetEnvironmentVariable(envName)
+ if not (String.IsNullOrEmpty(envVar)) then
+ try
+ let parentPath = Path.Combine(envVar, "..")
+ if validateVSPath parentPath then
+ Some (Found (Path.GetFullPath(parentPath), $"{envName} environment variable (VS version {version})"))
+ else None
+ with
+ | _ -> None
+ else None)
+
+ /// Strategy 4: vswhere.exe (Visual Studio Installer)
+ let tryVSWhere () =
+ try
+ let programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)
+ let vswherePath = Path.Combine(programFiles, "Microsoft Visual Studio", "Installer", "vswhere.exe")
+
+ if File.Exists(vswherePath) then
+ let startInfo = ProcessStartInfo(
+ FileName = vswherePath,
+ Arguments = "-latest -products * -requires Microsoft.Component.MSBuild -property installationPath",
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ CreateNoWindow = true
+ )
+
+ use proc = Process.Start(startInfo)
+ proc.WaitForExit(5000) |> ignore // 5 second timeout
+
+ if proc.ExitCode = 0 then
+ let output = proc.StandardOutput.ReadToEnd().Trim()
+ if validateVSPath output then
+ Some (Found (Path.GetFullPath(output), "vswhere.exe discovery"))
+ else None
+ else None
+ else None
+ with
+ | _ -> None
+
+ // Try each strategy in order of precedence
+ match tryExplicitOverride () with
+ | Some result -> result
+ | None ->
+ match tryVSAppIdDir () with
+ | Some result -> result
+ | None ->
+ match tryVSCommonTools () with
+ | Some result -> result
+ | None ->
+ match tryVSWhere () with
+ | Some result -> result
+ | None -> NotFound "No Visual Studio installation found using any discovery method"
+
+/// Gets the VS installation directory, with graceful fallback behavior.
+/// Returns None if no VS installation can be found, allowing callers to handle gracefully.
+let tryGetVSInstallDir () : string option =
+ match tryFindVSInstallation () with
+ | Found (path, _) -> Some path
+ | NotFound _ -> None
+
+/// Gets the VS installation directory with detailed logging.
+/// Useful for debugging installation discovery issues in tests.
+let getVSInstallDirWithLogging (logAction: string -> unit) : string option =
+ match tryFindVSInstallation () with
+ | Found (path, source) ->
+ logAction $"Visual Studio installation found at: {path} (via {source})"
+ Some path
+ | NotFound reason ->
+ logAction $"Visual Studio installation not found: {reason}"
+ None
+
+/// Legacy compatibility function that maintains the old behavior of hard-failing.
+/// Use this only for tests that must maintain the old behavior.
+[]
+let getVSInstallDirOrFail () : string =
+ match tryFindVSInstallation () with
+ | Found (path, _) -> path
+ | NotFound reason -> failwith $"VS170COMNTOOLS and VSAPPIDDIR environment variables not found. {reason}"
\ No newline at end of file
diff --git a/vsintegration/tests/UnitTests/AssemblyResolver.fs b/vsintegration/tests/UnitTests/AssemblyResolver.fs
index aab95cc46f..538fddb688 100644
--- a/vsintegration/tests/UnitTests/AssemblyResolver.fs
+++ b/vsintegration/tests/UnitTests/AssemblyResolver.fs
@@ -6,17 +6,22 @@ open System.Reflection
module AssemblyResolver =
open System.Globalization
+ open Microsoft.VisualStudio.FSharp.TestHelpers.VSInstallDiscovery
let vsInstallDir =
- // use the environment variable to find the VS installdir
- let vsvar =
- let var = Environment.GetEnvironmentVariable("VS170COMNTOOLS")
- if String.IsNullOrEmpty var then
- Environment.GetEnvironmentVariable("VSAPPIDDIR")
- else
- var
- if String.IsNullOrEmpty vsvar then failwith "VS170COMNTOOLS and VSAPPIDDIR environment variables not found."
- Path.Combine(vsvar, "..")
+ // Use centralized VS installation discovery with graceful fallback
+ match tryGetVSInstallDir () with
+ | Some dir -> dir
+ | None ->
+ // Fallback to legacy behavior for backward compatibility
+ let vsvar =
+ let var = Environment.GetEnvironmentVariable("VS170COMNTOOLS")
+ if String.IsNullOrEmpty var then
+ Environment.GetEnvironmentVariable("VSAPPIDDIR")
+ else
+ var
+ if String.IsNullOrEmpty vsvar then failwith "VS170COMNTOOLS and VSAPPIDDIR environment variables not found."
+ Path.Combine(vsvar, "..")
let probingPaths = [|
Path.Combine(vsInstallDir, @"IDE\CommonExtensions\Microsoft\Editor")
diff --git a/vsintegration/tests/UnitTests/VisualFSharp.UnitTests.fsproj b/vsintegration/tests/UnitTests/VisualFSharp.UnitTests.fsproj
index 96fde123dc..256e52d6f1 100644
--- a/vsintegration/tests/UnitTests/VisualFSharp.UnitTests.fsproj
+++ b/vsintegration/tests/UnitTests/VisualFSharp.UnitTests.fsproj
@@ -78,6 +78,7 @@
+
From 18b2cd8ce043662d6dbe3d01109b6c184ebe0304 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 16 Sep 2025 11:38:23 +0000
Subject: [PATCH 03/10] Complete VS installation discovery with tests and
validation
Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
---
.../tests/TestHelpers/TestHelpers.fsproj | 1 +
.../TestHelpers/VSInstallDiscoveryTests.fs | 84 +++++++++++++++++++
2 files changed, 85 insertions(+)
create mode 100644 vsintegration/tests/TestHelpers/VSInstallDiscoveryTests.fs
diff --git a/vsintegration/tests/TestHelpers/TestHelpers.fsproj b/vsintegration/tests/TestHelpers/TestHelpers.fsproj
index 7ab4b20231..3e4836b535 100644
--- a/vsintegration/tests/TestHelpers/TestHelpers.fsproj
+++ b/vsintegration/tests/TestHelpers/TestHelpers.fsproj
@@ -18,6 +18,7 @@
+
diff --git a/vsintegration/tests/TestHelpers/VSInstallDiscoveryTests.fs b/vsintegration/tests/TestHelpers/VSInstallDiscoveryTests.fs
new file mode 100644
index 0000000000..10a505d228
--- /dev/null
+++ b/vsintegration/tests/TestHelpers/VSInstallDiscoveryTests.fs
@@ -0,0 +1,84 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+/// Simple test to verify VS installation discovery functionality
+module Microsoft.VisualStudio.FSharp.TestHelpers.VSInstallDiscoveryTests
+
+open System
+open System.IO
+
+/// Test basic discovery functionality
+let testBasicDiscovery () =
+ printfn "Testing VS installation discovery..."
+
+ // Test the discovery process
+ let result = VSInstallDiscovery.tryFindVSInstallation ()
+ match result with
+ | VSInstallDiscovery.Found (path, source) ->
+ printfn $"✓ VS installation found at: {path}"
+ printfn $" Source: {source}"
+
+ // Validate that the path looks reasonable
+ if Directory.Exists(path) && Directory.Exists(Path.Combine(path, "IDE")) then
+ printfn " ✓ Path validation passed"
+ else
+ printfn " ✗ Path validation failed - directory structure not as expected"
+
+ | VSInstallDiscovery.NotFound reason ->
+ printfn $"✗ VS installation not found: {reason}"
+ printfn " This is expected if VS is not installed or environment variables are not set"
+
+ // Test the optional version
+ let optPath = VSInstallDiscovery.tryGetVSInstallDir ()
+ match optPath with
+ | Some path -> printfn $"✓ tryGetVSInstallDir returned: {path}"
+ | None -> printfn "✗ tryGetVSInstallDir returned None"
+
+ // Test the logging version
+ let logMessages = ResizeArray()
+ let logger msg = logMessages.Add(msg)
+ let pathWithLogging = VSInstallDiscovery.getVSInstallDirWithLogging logger
+
+ printfn "Logged messages:"
+ for msg in logMessages do
+ printfn $" LOG: {msg}"
+
+ printfn "✓ Basic discovery test completed"
+
+/// Test environment variable scenarios
+let testEnvironmentVariables () =
+ printfn "\nTesting environment variable scenarios..."
+
+ // Save original values
+ let originalVS170 = Environment.GetEnvironmentVariable("VS170COMNTOOLS")
+ let originalVSAPP = Environment.GetEnvironmentVariable("VSAPPIDDIR")
+ let originalFSHARP = Environment.GetEnvironmentVariable("FSHARP_VS_INSTALL_DIR")
+
+ try
+ // Test explicit override (highest priority)
+ Environment.SetEnvironmentVariable("FSHARP_VS_INSTALL_DIR", @"C:\TestPath")
+ Environment.SetEnvironmentVariable("VS170COMNTOOLS", @"C:\VS\Common7\Tools\")
+
+ let result = VSInstallDiscovery.tryFindVSInstallation ()
+ match result with
+ | VSInstallDiscovery.Found (path, source) when source.Contains("FSHARP_VS_INSTALL_DIR") ->
+ printfn "✓ FSHARP_VS_INSTALL_DIR override works correctly"
+ | _ ->
+ printfn "✗ FSHARP_VS_INSTALL_DIR override not working as expected"
+
+ // Clear explicit override to test VS170COMNTOOLS
+ Environment.SetEnvironmentVariable("FSHARP_VS_INSTALL_DIR", null)
+
+ printfn "✓ Environment variable scenario tests completed"
+
+ finally
+ // Restore original values
+ Environment.SetEnvironmentVariable("VS170COMNTOOLS", originalVS170)
+ Environment.SetEnvironmentVariable("VSAPPIDDIR", originalVSAPP)
+ Environment.SetEnvironmentVariable("FSHARP_VS_INSTALL_DIR", originalFSHARP)
+
+/// Run all tests
+let runTests () =
+ printfn "=== VS Installation Discovery Tests ==="
+ testBasicDiscovery ()
+ testEnvironmentVariables ()
+ printfn "=== Tests completed ==="
\ No newline at end of file
From 1aad0e2a06e688502805d7411af5b2255259f948 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 17 Sep 2025 10:22:25 +0000
Subject: [PATCH 04/10] Address feedback: Move to FSharp.Test.Utilities, remove
FSHARP_VS_INSTALL_DIR, add VS180COMNTOOLS support
Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
---
.../FSharp.Test.Utilities.fsproj | 3 +
.../VSInstallDiscovery.fs | 27 ++----
.../FSharp.Editor.Tests.fsproj | 1 -
.../Helpers/AssemblyResolver.fs | 2 +-
.../tests/Salsa/VisualFSharp.Salsa.fsproj | 1 -
vsintegration/tests/Salsa/VsMocks.fs | 2 +-
.../tests/TestHelpers/TestHelpers.fsproj | 33 --------
.../TestHelpers/VSInstallDiscoveryTests.fs | 84 -------------------
.../tests/UnitTests/AssemblyResolver.fs | 2 +-
.../UnitTests/VisualFSharp.UnitTests.fsproj | 1 -
10 files changed, 15 insertions(+), 141 deletions(-)
rename {vsintegration/tests/TestHelpers => tests/FSharp.Test.Utilities}/VSInstallDiscovery.fs (85%)
delete mode 100644 vsintegration/tests/TestHelpers/TestHelpers.fsproj
delete mode 100644 vsintegration/tests/TestHelpers/VSInstallDiscoveryTests.fs
diff --git a/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj b/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj
index 484f8acfbb..4431505152 100644
--- a/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj
+++ b/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj
@@ -33,6 +33,7 @@
+
@@ -80,6 +81,8 @@
+
+
diff --git a/vsintegration/tests/TestHelpers/VSInstallDiscovery.fs b/tests/FSharp.Test.Utilities/VSInstallDiscovery.fs
similarity index 85%
rename from vsintegration/tests/TestHelpers/VSInstallDiscovery.fs
rename to tests/FSharp.Test.Utilities/VSInstallDiscovery.fs
index 2ae105db98..1233c7e4b7 100644
--- a/vsintegration/tests/TestHelpers/VSInstallDiscovery.fs
+++ b/tests/FSharp.Test.Utilities/VSInstallDiscovery.fs
@@ -4,7 +4,7 @@
/// Provides a centralized, robust, and graceful discovery mechanism for Visual Studio installations
/// used by integration/editor/unit tests under vsintegration/tests.
[]
-module Microsoft.VisualStudio.FSharp.TestHelpers.VSInstallDiscovery
+module FSharp.Test.Utilities.VSInstallDiscovery
open System
open System.IO
@@ -31,14 +31,7 @@ let tryFindVSInstallation () : VSInstallResult =
with
| _ -> false
- /// Strategy 1: FSHARP_VS_INSTALL_DIR (explicit override for tests)
- let tryExplicitOverride () =
- let envVar = Environment.GetEnvironmentVariable("FSHARP_VS_INSTALL_DIR")
- if validateVSPath envVar then
- Some (Found (Path.GetFullPath(envVar), "FSHARP_VS_INSTALL_DIR environment variable"))
- else None
-
- /// Strategy 2: VSAPPIDDIR (derive parent of Common7/IDE)
+ /// Strategy 1: VSAPPIDDIR (derive parent of Common7/IDE)
let tryVSAppIdDir () =
let envVar = Environment.GetEnvironmentVariable("VSAPPIDDIR")
if not (String.IsNullOrEmpty(envVar)) then
@@ -51,9 +44,10 @@ let tryFindVSInstallation () : VSInstallResult =
| _ -> None
else None
- /// Strategy 3: Highest version among VS*COMNTOOLS environment variables
+ /// Strategy 2: Highest version among VS*COMNTOOLS environment variables
let tryVSCommonTools () =
let vsVersions = [
+ ("VS180COMNTOOLS", 18) // Visual Studio 2026
("VS170COMNTOOLS", 17) // Visual Studio 2022
("VS160COMNTOOLS", 16) // Visual Studio 2019
("VS150COMNTOOLS", 15) // Visual Studio 2017
@@ -74,7 +68,7 @@ let tryFindVSInstallation () : VSInstallResult =
| _ -> None
else None)
- /// Strategy 4: vswhere.exe (Visual Studio Installer)
+ /// Strategy 3: vswhere.exe (Visual Studio Installer)
let tryVSWhere () =
try
let programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)
@@ -104,18 +98,15 @@ let tryFindVSInstallation () : VSInstallResult =
| _ -> None
// Try each strategy in order of precedence
- match tryExplicitOverride () with
+ match tryVSAppIdDir () with
| Some result -> result
| None ->
- match tryVSAppIdDir () with
+ match tryVSCommonTools () with
| Some result -> result
| None ->
- match tryVSCommonTools () with
+ match tryVSWhere () with
| Some result -> result
- | None ->
- match tryVSWhere () with
- | Some result -> result
- | None -> NotFound "No Visual Studio installation found using any discovery method"
+ | None -> NotFound "No Visual Studio installation found using any discovery method"
/// Gets the VS installation directory, with graceful fallback behavior.
/// Returns None if no VS installation can be found, allowing callers to handle gracefully.
diff --git a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj
index d0a264e868..c084fc6f06 100644
--- a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj
+++ b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj
@@ -105,7 +105,6 @@
-
diff --git a/vsintegration/tests/FSharp.Editor.Tests/Helpers/AssemblyResolver.fs b/vsintegration/tests/FSharp.Editor.Tests/Helpers/AssemblyResolver.fs
index 98db3e27df..9f5faafd7e 100644
--- a/vsintegration/tests/FSharp.Editor.Tests/Helpers/AssemblyResolver.fs
+++ b/vsintegration/tests/FSharp.Editor.Tests/Helpers/AssemblyResolver.fs
@@ -8,7 +8,7 @@ open System.Reflection
module AssemblyResolver =
open System.Globalization
- open Microsoft.VisualStudio.FSharp.TestHelpers.VSInstallDiscovery
+ open FSharp.Test.Utilities.VSInstallDiscovery
let vsInstallDir =
// Use centralized VS installation discovery with graceful fallback
diff --git a/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj b/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
index 1e806e423b..e1e657a651 100644
--- a/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
+++ b/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
@@ -34,7 +34,6 @@
-
diff --git a/vsintegration/tests/Salsa/VsMocks.fs b/vsintegration/tests/Salsa/VsMocks.fs
index ab8901fcb7..9caa86e9e1 100644
--- a/vsintegration/tests/Salsa/VsMocks.fs
+++ b/vsintegration/tests/Salsa/VsMocks.fs
@@ -1652,7 +1652,7 @@ module internal VsActual =
let vsInstallDir =
// Use centralized VS installation discovery with graceful fallback
- match Microsoft.VisualStudio.FSharp.TestHelpers.VSInstallDiscovery.tryGetVSInstallDir () with
+ match FSharp.Test.Utilities.VSInstallDiscovery.tryGetVSInstallDir () with
| Some dir -> dir
| None ->
// Fallback to legacy behavior for backward compatibility
diff --git a/vsintegration/tests/TestHelpers/TestHelpers.fsproj b/vsintegration/tests/TestHelpers/TestHelpers.fsproj
deleted file mode 100644
index 3e4836b535..0000000000
--- a/vsintegration/tests/TestHelpers/TestHelpers.fsproj
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
- Library
- net472
- $(NoWarn);44;45;47;52;58;75;1204
- true
- true
- true
- false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/vsintegration/tests/TestHelpers/VSInstallDiscoveryTests.fs b/vsintegration/tests/TestHelpers/VSInstallDiscoveryTests.fs
deleted file mode 100644
index 10a505d228..0000000000
--- a/vsintegration/tests/TestHelpers/VSInstallDiscoveryTests.fs
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
-
-/// Simple test to verify VS installation discovery functionality
-module Microsoft.VisualStudio.FSharp.TestHelpers.VSInstallDiscoveryTests
-
-open System
-open System.IO
-
-/// Test basic discovery functionality
-let testBasicDiscovery () =
- printfn "Testing VS installation discovery..."
-
- // Test the discovery process
- let result = VSInstallDiscovery.tryFindVSInstallation ()
- match result with
- | VSInstallDiscovery.Found (path, source) ->
- printfn $"✓ VS installation found at: {path}"
- printfn $" Source: {source}"
-
- // Validate that the path looks reasonable
- if Directory.Exists(path) && Directory.Exists(Path.Combine(path, "IDE")) then
- printfn " ✓ Path validation passed"
- else
- printfn " ✗ Path validation failed - directory structure not as expected"
-
- | VSInstallDiscovery.NotFound reason ->
- printfn $"✗ VS installation not found: {reason}"
- printfn " This is expected if VS is not installed or environment variables are not set"
-
- // Test the optional version
- let optPath = VSInstallDiscovery.tryGetVSInstallDir ()
- match optPath with
- | Some path -> printfn $"✓ tryGetVSInstallDir returned: {path}"
- | None -> printfn "✗ tryGetVSInstallDir returned None"
-
- // Test the logging version
- let logMessages = ResizeArray()
- let logger msg = logMessages.Add(msg)
- let pathWithLogging = VSInstallDiscovery.getVSInstallDirWithLogging logger
-
- printfn "Logged messages:"
- for msg in logMessages do
- printfn $" LOG: {msg}"
-
- printfn "✓ Basic discovery test completed"
-
-/// Test environment variable scenarios
-let testEnvironmentVariables () =
- printfn "\nTesting environment variable scenarios..."
-
- // Save original values
- let originalVS170 = Environment.GetEnvironmentVariable("VS170COMNTOOLS")
- let originalVSAPP = Environment.GetEnvironmentVariable("VSAPPIDDIR")
- let originalFSHARP = Environment.GetEnvironmentVariable("FSHARP_VS_INSTALL_DIR")
-
- try
- // Test explicit override (highest priority)
- Environment.SetEnvironmentVariable("FSHARP_VS_INSTALL_DIR", @"C:\TestPath")
- Environment.SetEnvironmentVariable("VS170COMNTOOLS", @"C:\VS\Common7\Tools\")
-
- let result = VSInstallDiscovery.tryFindVSInstallation ()
- match result with
- | VSInstallDiscovery.Found (path, source) when source.Contains("FSHARP_VS_INSTALL_DIR") ->
- printfn "✓ FSHARP_VS_INSTALL_DIR override works correctly"
- | _ ->
- printfn "✗ FSHARP_VS_INSTALL_DIR override not working as expected"
-
- // Clear explicit override to test VS170COMNTOOLS
- Environment.SetEnvironmentVariable("FSHARP_VS_INSTALL_DIR", null)
-
- printfn "✓ Environment variable scenario tests completed"
-
- finally
- // Restore original values
- Environment.SetEnvironmentVariable("VS170COMNTOOLS", originalVS170)
- Environment.SetEnvironmentVariable("VSAPPIDDIR", originalVSAPP)
- Environment.SetEnvironmentVariable("FSHARP_VS_INSTALL_DIR", originalFSHARP)
-
-/// Run all tests
-let runTests () =
- printfn "=== VS Installation Discovery Tests ==="
- testBasicDiscovery ()
- testEnvironmentVariables ()
- printfn "=== Tests completed ==="
\ No newline at end of file
diff --git a/vsintegration/tests/UnitTests/AssemblyResolver.fs b/vsintegration/tests/UnitTests/AssemblyResolver.fs
index 538fddb688..a2839358e5 100644
--- a/vsintegration/tests/UnitTests/AssemblyResolver.fs
+++ b/vsintegration/tests/UnitTests/AssemblyResolver.fs
@@ -6,7 +6,7 @@ open System.Reflection
module AssemblyResolver =
open System.Globalization
- open Microsoft.VisualStudio.FSharp.TestHelpers.VSInstallDiscovery
+ open FSharp.Test.Utilities.VSInstallDiscovery
let vsInstallDir =
// Use centralized VS installation discovery with graceful fallback
diff --git a/vsintegration/tests/UnitTests/VisualFSharp.UnitTests.fsproj b/vsintegration/tests/UnitTests/VisualFSharp.UnitTests.fsproj
index 256e52d6f1..96fde123dc 100644
--- a/vsintegration/tests/UnitTests/VisualFSharp.UnitTests.fsproj
+++ b/vsintegration/tests/UnitTests/VisualFSharp.UnitTests.fsproj
@@ -78,7 +78,6 @@
-
From 478dc9038c494cb693d41e28dc97292ae1779c5f Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 19 Sep 2025 09:10:38 +0000
Subject: [PATCH 05/10] Fix namespace conflict and formatting issues
Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
---
tests/FSharp.Test.Utilities/VSInstallDiscovery.fs | 4 +++-
.../tests/FSharp.Editor.Tests/Helpers/AssemblyResolver.fs | 4 ++--
vsintegration/tests/Salsa/VsMocks.fs | 2 +-
vsintegration/tests/UnitTests/AssemblyResolver.fs | 2 +-
4 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/tests/FSharp.Test.Utilities/VSInstallDiscovery.fs b/tests/FSharp.Test.Utilities/VSInstallDiscovery.fs
index 1233c7e4b7..5ceb041798 100644
--- a/tests/FSharp.Test.Utilities/VSInstallDiscovery.fs
+++ b/tests/FSharp.Test.Utilities/VSInstallDiscovery.fs
@@ -1,10 +1,12 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+namespace FSharp.Test
+
/// Test-only Visual Studio installation discovery infrastructure.
/// Provides a centralized, robust, and graceful discovery mechanism for Visual Studio installations
/// used by integration/editor/unit tests under vsintegration/tests.
[]
-module FSharp.Test.Utilities.VSInstallDiscovery
+module VSInstallDiscovery =
open System
open System.IO
diff --git a/vsintegration/tests/FSharp.Editor.Tests/Helpers/AssemblyResolver.fs b/vsintegration/tests/FSharp.Editor.Tests/Helpers/AssemblyResolver.fs
index 9f5faafd7e..78a5779351 100644
--- a/vsintegration/tests/FSharp.Editor.Tests/Helpers/AssemblyResolver.fs
+++ b/vsintegration/tests/FSharp.Editor.Tests/Helpers/AssemblyResolver.fs
@@ -8,13 +8,13 @@ open System.Reflection
module AssemblyResolver =
open System.Globalization
- open FSharp.Test.Utilities.VSInstallDiscovery
+ open FSharp.Test.VSInstallDiscovery
let vsInstallDir =
// Use centralized VS installation discovery with graceful fallback
match tryGetVSInstallDir () with
| Some dir -> dir
- | None ->
+ | None ->
// Fallback to legacy behavior for backward compatibility
let vsvar =
let var = Environment.GetEnvironmentVariable("VS170COMNTOOLS")
diff --git a/vsintegration/tests/Salsa/VsMocks.fs b/vsintegration/tests/Salsa/VsMocks.fs
index 9caa86e9e1..6551206fde 100644
--- a/vsintegration/tests/Salsa/VsMocks.fs
+++ b/vsintegration/tests/Salsa/VsMocks.fs
@@ -1652,7 +1652,7 @@ module internal VsActual =
let vsInstallDir =
// Use centralized VS installation discovery with graceful fallback
- match FSharp.Test.Utilities.VSInstallDiscovery.tryGetVSInstallDir () with
+ match FSharp.Test.VSInstallDiscovery.tryGetVSInstallDir () with
| Some dir -> dir
| None ->
// Fallback to legacy behavior for backward compatibility
diff --git a/vsintegration/tests/UnitTests/AssemblyResolver.fs b/vsintegration/tests/UnitTests/AssemblyResolver.fs
index a2839358e5..38b5ee4529 100644
--- a/vsintegration/tests/UnitTests/AssemblyResolver.fs
+++ b/vsintegration/tests/UnitTests/AssemblyResolver.fs
@@ -6,7 +6,7 @@ open System.Reflection
module AssemblyResolver =
open System.Globalization
- open FSharp.Test.Utilities.VSInstallDiscovery
+ open FSharp.Test.VSInstallDiscovery
let vsInstallDir =
// Use centralized VS installation discovery with graceful fallback
From f35a2819b1b0af3b2986e8590d37a11c98718304 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 19 Sep 2025 14:11:19 +0000
Subject: [PATCH 06/10] Fix indentation in VSInstallDiscovery module to resolve
syntax errors
Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
---
.../VSInstallDiscovery.fs | 210 +++++++++---------
1 file changed, 105 insertions(+), 105 deletions(-)
diff --git a/tests/FSharp.Test.Utilities/VSInstallDiscovery.fs b/tests/FSharp.Test.Utilities/VSInstallDiscovery.fs
index 5ceb041798..4c14435d4a 100644
--- a/tests/FSharp.Test.Utilities/VSInstallDiscovery.fs
+++ b/tests/FSharp.Test.Utilities/VSInstallDiscovery.fs
@@ -8,130 +8,130 @@ namespace FSharp.Test
[]
module VSInstallDiscovery =
-open System
-open System.IO
-open System.Diagnostics
+ open System
+ open System.IO
+ open System.Diagnostics
-/// Result of VS installation discovery
-type VSInstallResult =
- | Found of installPath: string * source: string
- | NotFound of reason: string
+ /// Result of VS installation discovery
+ type VSInstallResult =
+ | Found of installPath: string * source: string
+ | NotFound of reason: string
-/// Attempts to find a Visual Studio installation using multiple fallback strategies
-let tryFindVSInstallation () : VSInstallResult =
-
- /// Check if a path exists and looks like a valid VS installation
- let validateVSPath path =
- if String.IsNullOrEmpty(path) then false
- else
- try
- let fullPath = Path.GetFullPath(path)
- Directory.Exists(fullPath) &&
- Directory.Exists(Path.Combine(fullPath, "IDE")) &&
- (File.Exists(Path.Combine(fullPath, "IDE", "devenv.exe")) ||
- File.Exists(Path.Combine(fullPath, "IDE", "VSIXInstaller.exe")))
- with
- | _ -> false
-
- /// Strategy 1: VSAPPIDDIR (derive parent of Common7/IDE)
- let tryVSAppIdDir () =
- let envVar = Environment.GetEnvironmentVariable("VSAPPIDDIR")
- if not (String.IsNullOrEmpty(envVar)) then
- try
- let parentPath = Path.Combine(envVar, "..")
- if validateVSPath parentPath then
- Some (Found (Path.GetFullPath(parentPath), "VSAPPIDDIR environment variable"))
- else None
- with
- | _ -> None
- else None
-
- /// Strategy 2: Highest version among VS*COMNTOOLS environment variables
- let tryVSCommonTools () =
- let vsVersions = [
- ("VS180COMNTOOLS", 18) // Visual Studio 2026
- ("VS170COMNTOOLS", 17) // Visual Studio 2022
- ("VS160COMNTOOLS", 16) // Visual Studio 2019
- ("VS150COMNTOOLS", 15) // Visual Studio 2017
- ("VS140COMNTOOLS", 14) // Visual Studio 2015
- ("VS120COMNTOOLS", 12) // Visual Studio 2013
- ]
+ /// Attempts to find a Visual Studio installation using multiple fallback strategies
+ let tryFindVSInstallation () : VSInstallResult =
- vsVersions
- |> List.tryPick (fun (envName, version) ->
- let envVar = Environment.GetEnvironmentVariable(envName)
+ /// Check if a path exists and looks like a valid VS installation
+ let validateVSPath path =
+ if String.IsNullOrEmpty(path) then false
+ else
+ try
+ let fullPath = Path.GetFullPath(path)
+ Directory.Exists(fullPath) &&
+ Directory.Exists(Path.Combine(fullPath, "IDE")) &&
+ (File.Exists(Path.Combine(fullPath, "IDE", "devenv.exe")) ||
+ File.Exists(Path.Combine(fullPath, "IDE", "VSIXInstaller.exe")))
+ with
+ | _ -> false
+
+ /// Strategy 1: VSAPPIDDIR (derive parent of Common7/IDE)
+ let tryVSAppIdDir () =
+ let envVar = Environment.GetEnvironmentVariable("VSAPPIDDIR")
if not (String.IsNullOrEmpty(envVar)) then
try
let parentPath = Path.Combine(envVar, "..")
if validateVSPath parentPath then
- Some (Found (Path.GetFullPath(parentPath), $"{envName} environment variable (VS version {version})"))
+ Some (Found (Path.GetFullPath(parentPath), "VSAPPIDDIR environment variable"))
else None
with
| _ -> None
- else None)
+ else None
- /// Strategy 3: vswhere.exe (Visual Studio Installer)
- let tryVSWhere () =
- try
- let programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)
- let vswherePath = Path.Combine(programFiles, "Microsoft Visual Studio", "Installer", "vswhere.exe")
+ /// Strategy 2: Highest version among VS*COMNTOOLS environment variables
+ let tryVSCommonTools () =
+ let vsVersions = [
+ ("VS180COMNTOOLS", 18) // Visual Studio 2026
+ ("VS170COMNTOOLS", 17) // Visual Studio 2022
+ ("VS160COMNTOOLS", 16) // Visual Studio 2019
+ ("VS150COMNTOOLS", 15) // Visual Studio 2017
+ ("VS140COMNTOOLS", 14) // Visual Studio 2015
+ ("VS120COMNTOOLS", 12) // Visual Studio 2013
+ ]
- if File.Exists(vswherePath) then
- let startInfo = ProcessStartInfo(
- FileName = vswherePath,
- Arguments = "-latest -products * -requires Microsoft.Component.MSBuild -property installationPath",
- UseShellExecute = false,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- CreateNoWindow = true
- )
-
- use proc = Process.Start(startInfo)
- proc.WaitForExit(5000) |> ignore // 5 second timeout
+ vsVersions
+ |> List.tryPick (fun (envName, version) ->
+ let envVar = Environment.GetEnvironmentVariable(envName)
+ if not (String.IsNullOrEmpty(envVar)) then
+ try
+ let parentPath = Path.Combine(envVar, "..")
+ if validateVSPath parentPath then
+ Some (Found (Path.GetFullPath(parentPath), $"{envName} environment variable (VS version {version})"))
+ else None
+ with
+ | _ -> None
+ else None)
+
+ /// Strategy 3: vswhere.exe (Visual Studio Installer)
+ let tryVSWhere () =
+ try
+ let programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)
+ let vswherePath = Path.Combine(programFiles, "Microsoft Visual Studio", "Installer", "vswhere.exe")
- if proc.ExitCode = 0 then
- let output = proc.StandardOutput.ReadToEnd().Trim()
- if validateVSPath output then
- Some (Found (Path.GetFullPath(output), "vswhere.exe discovery"))
+ if File.Exists(vswherePath) then
+ let startInfo = ProcessStartInfo(
+ FileName = vswherePath,
+ Arguments = "-latest -products * -requires Microsoft.Component.MSBuild -property installationPath",
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ CreateNoWindow = true
+ )
+
+ use proc = Process.Start(startInfo)
+ proc.WaitForExit(5000) |> ignore // 5 second timeout
+
+ if proc.ExitCode = 0 then
+ let output = proc.StandardOutput.ReadToEnd().Trim()
+ if validateVSPath output then
+ Some (Found (Path.GetFullPath(output), "vswhere.exe discovery"))
+ else None
else None
else None
- else None
- with
- | _ -> None
+ with
+ | _ -> None
- // Try each strategy in order of precedence
- match tryVSAppIdDir () with
- | Some result -> result
- | None ->
- match tryVSCommonTools () with
+ // Try each strategy in order of precedence
+ match tryVSAppIdDir () with
| Some result -> result
| None ->
- match tryVSWhere () with
+ match tryVSCommonTools () with
| Some result -> result
- | None -> NotFound "No Visual Studio installation found using any discovery method"
+ | None ->
+ match tryVSWhere () with
+ | Some result -> result
+ | None -> NotFound "No Visual Studio installation found using any discovery method"
-/// Gets the VS installation directory, with graceful fallback behavior.
-/// Returns None if no VS installation can be found, allowing callers to handle gracefully.
-let tryGetVSInstallDir () : string option =
- match tryFindVSInstallation () with
- | Found (path, _) -> Some path
- | NotFound _ -> None
+ /// Gets the VS installation directory, with graceful fallback behavior.
+ /// Returns None if no VS installation can be found, allowing callers to handle gracefully.
+ let tryGetVSInstallDir () : string option =
+ match tryFindVSInstallation () with
+ | Found (path, _) -> Some path
+ | NotFound _ -> None
-/// Gets the VS installation directory with detailed logging.
-/// Useful for debugging installation discovery issues in tests.
-let getVSInstallDirWithLogging (logAction: string -> unit) : string option =
- match tryFindVSInstallation () with
- | Found (path, source) ->
- logAction $"Visual Studio installation found at: {path} (via {source})"
- Some path
- | NotFound reason ->
- logAction $"Visual Studio installation not found: {reason}"
- None
+ /// Gets the VS installation directory with detailed logging.
+ /// Useful for debugging installation discovery issues in tests.
+ let getVSInstallDirWithLogging (logAction: string -> unit) : string option =
+ match tryFindVSInstallation () with
+ | Found (path, source) ->
+ logAction $"Visual Studio installation found at: {path} (via {source})"
+ Some path
+ | NotFound reason ->
+ logAction $"Visual Studio installation not found: {reason}"
+ None
-/// Legacy compatibility function that maintains the old behavior of hard-failing.
-/// Use this only for tests that must maintain the old behavior.
-[]
-let getVSInstallDirOrFail () : string =
- match tryFindVSInstallation () with
- | Found (path, _) -> path
- | NotFound reason -> failwith $"VS170COMNTOOLS and VSAPPIDDIR environment variables not found. {reason}"
\ No newline at end of file
+ /// Legacy compatibility function that maintains the old behavior of hard-failing.
+ /// Use this only for tests that must maintain the old behavior.
+ []
+ let getVSInstallDirOrFail () : string =
+ match tryFindVSInstallation () with
+ | Found (path, _) -> path
+ | NotFound reason -> failwith $"VS170COMNTOOLS and VSAPPIDDIR environment variables not found. {reason}"
\ No newline at end of file
From 86ec73c6057b59d8be405781fe6fd7f03460a17e Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 25 Sep 2025 13:05:18 +0000
Subject: [PATCH 07/10] Fix FS1204 compiler error and missing project reference
for Salsa
Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
---
tests/FSharp.Test.Utilities/VSInstallDiscovery.fs | 1 -
vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj | 1 +
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/FSharp.Test.Utilities/VSInstallDiscovery.fs b/tests/FSharp.Test.Utilities/VSInstallDiscovery.fs
index 4c14435d4a..c61fd39cb6 100644
--- a/tests/FSharp.Test.Utilities/VSInstallDiscovery.fs
+++ b/tests/FSharp.Test.Utilities/VSInstallDiscovery.fs
@@ -5,7 +5,6 @@ namespace FSharp.Test
/// Test-only Visual Studio installation discovery infrastructure.
/// Provides a centralized, robust, and graceful discovery mechanism for Visual Studio installations
/// used by integration/editor/unit tests under vsintegration/tests.
-[]
module VSInstallDiscovery =
open System
diff --git a/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj b/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
index e1e657a651..a27ab2aca1 100644
--- a/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
+++ b/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
@@ -34,6 +34,7 @@
+
From 2e17a0657cd8e45d8af3fd5623995b43abe74d39 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 17 Oct 2025 13:14:11 +0000
Subject: [PATCH 08/10] Revert Salsa project changes to avoid
Microsoft.CodeAnalysis version conflicts
Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
---
.../FSharp.Test.Utilities.fsproj | 1 -
.../tests/Salsa/VisualFSharp.Salsa.fsproj | 14 ++++++++++--
vsintegration/tests/Salsa/VsMocks.fs | 22 ++++++++-----------
3 files changed, 21 insertions(+), 16 deletions(-)
diff --git a/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj b/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj
index da3b9a2ccd..7bc4f6e058 100644
--- a/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj
+++ b/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj
@@ -95,7 +95,6 @@
-
diff --git a/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj b/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
index ca18bd89fc..e1e657a651 100644
--- a/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
+++ b/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
@@ -16,7 +16,7 @@
-
+
CompilerLocation.fs
@@ -34,7 +34,6 @@
-
@@ -52,11 +51,22 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vsintegration/tests/Salsa/VsMocks.fs b/vsintegration/tests/Salsa/VsMocks.fs
index 6551206fde..5189b7faec 100644
--- a/vsintegration/tests/Salsa/VsMocks.fs
+++ b/vsintegration/tests/Salsa/VsMocks.fs
@@ -1651,19 +1651,15 @@ module internal VsActual =
member public _.JoinableTaskContext : JoinableTaskContext = jtc
let vsInstallDir =
- // Use centralized VS installation discovery with graceful fallback
- match FSharp.Test.VSInstallDiscovery.tryGetVSInstallDir () with
- | Some dir -> dir
- | None ->
- // Fallback to legacy behavior for backward compatibility
- let vsvar =
- let var = Environment.GetEnvironmentVariable("VS170COMNTOOLS")
- if String.IsNullOrEmpty var then
- Environment.GetEnvironmentVariable("VSAPPIDDIR")
- else
- var
- if String.IsNullOrEmpty vsvar then failwith "VS170COMNTOOLS and VSAPPIDDIR environment variables not found."
- Path.Combine(vsvar, "..")
+ // use the environment variable to find the VS installdir
+ let vsvar =
+ let var = Environment.GetEnvironmentVariable("VS170COMNTOOLS")
+ if String.IsNullOrEmpty var then
+ Environment.GetEnvironmentVariable("VSAPPIDDIR")
+ else
+ var
+ if String.IsNullOrEmpty vsvar then failwith "VS170COMNTOOLS and VSAPPIDDIR environment variables not found."
+ Path.Combine(vsvar, "..")
let CreateEditorCatalog() =
let thisAssembly = Assembly.GetExecutingAssembly().Location
From 23f564a7c4c3277caf577f915835d57df3416553 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 17 Oct 2025 13:54:53 +0000
Subject: [PATCH 09/10] Reduce Salsa project package references to match main
branch
Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
---
vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj | 11 -----------
1 file changed, 11 deletions(-)
diff --git a/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj b/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
index e1e657a651..f741021443 100644
--- a/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
+++ b/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
@@ -51,22 +51,11 @@
-
-
-
-
-
-
-
-
-
-
-
From 4354e4f42a7629635bcc21c85ed0450170da9735 Mon Sep 17 00:00:00 2001
From: Tomas Grosup
Date: Thu, 6 Nov 2025 15:52:46 +0100
Subject: [PATCH 10/10] Apply suggestion from @T-Gro
---
tests/FSharp.Test.Utilities/VSInstallDiscovery.fs | 8 --------
1 file changed, 8 deletions(-)
diff --git a/tests/FSharp.Test.Utilities/VSInstallDiscovery.fs b/tests/FSharp.Test.Utilities/VSInstallDiscovery.fs
index c61fd39cb6..e491ea329b 100644
--- a/tests/FSharp.Test.Utilities/VSInstallDiscovery.fs
+++ b/tests/FSharp.Test.Utilities/VSInstallDiscovery.fs
@@ -126,11 +126,3 @@ module VSInstallDiscovery =
| NotFound reason ->
logAction $"Visual Studio installation not found: {reason}"
None
-
- /// Legacy compatibility function that maintains the old behavior of hard-failing.
- /// Use this only for tests that must maintain the old behavior.
- []
- let getVSInstallDirOrFail () : string =
- match tryFindVSInstallation () with
- | Found (path, _) -> path
- | NotFound reason -> failwith $"VS170COMNTOOLS and VSAPPIDDIR environment variables not found. {reason}"
\ No newline at end of file