Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
c08687a
Enable VS integration tests on CI
abonie Jun 10, 2026
33c46fd
Use xunit.console.exe to run integration tests
abonie Jun 10, 2026
1c638d2
Refactor to use helper Get-PackageVersion
abonie Jun 10, 2026
534e1c8
Copy test dll config to build output
abonie Jun 11, 2026
ee4a258
Bump vs-extensibility-testing
abonie Jun 11, 2026
37d91f4
Use dotnet new for test projects
abonie Jun 11, 2026
9c6c136
Get correct dll location
abonie Jun 11, 2026
c5c5ba3
Drop VS2022 integration tests
abonie Jun 11, 2026
63f64bf
Fix tests regressions
abonie Jun 11, 2026
c805d38
Add wait for gotodefinition tests
abonie Jun 11, 2026
28ae1d6
Poll and retry for lightbulb tests
abonie Jun 11, 2026
5fbaa7f
More telemetry for debugging tests
abonie Jun 11, 2026
2458906
Rework waiting for lightbulb
abonie Jun 11, 2026
e796b9e
Revert "Rework waiting for lightbulb"
abonie Jun 12, 2026
ccf8c32
Revert "Poll and retry for lightbulb tests"
abonie Jun 12, 2026
b3d0b5b
Temp skip other tests
abonie Jun 12, 2026
c25d3d7
Revert "Temp skip other tests"
abonie Jun 12, 2026
8051911
Change test proj to net10
abonie Jun 12, 2026
765e43c
Merge branch 'main' into enable-integration-tests
abonie Jun 12, 2026
a52be95
Fix GoToDefinition integration tests: poll for async navigation
abonie Jun 12, 2026
4d4cba8
Build the project in GoesToDefinition before navigating
abonie Jun 13, 2026
125a96a
Re-open source file after build in GoesToDefinition
abonie Jun 13, 2026
d9eada8
Replace GoToDefinition retry loop with a single invoke + wait for nav…
abonie Jun 13, 2026
64d1247
Move session ownership to the helper
abonie Jun 13, 2026
94e3db3
Revert "single invoke + wait" for GoToDefinition; retry is required
abonie Jun 13, 2026
6268a59
Experiment: settle delay + single GoToDefn invocation (no retry)
abonie Jun 14, 2026
8ebed6a
Make GoesToDefinition open a fresh file; drop retry and settle
abonie Jun 15, 2026
676215d
Do not use Immutable.Array directly
abonie Jun 15, 2026
c1b7655
Fix CodeAction integration tests: drive lightbulb via reflection to a…
abonie Jun 15, 2026
3ba13fe
Drive lightbulb via the command-created session + event, reading item…
abonie Jun 15, 2026
293bca7
Wait for F# diagnostics before invoking the lightbulb; lengthen per-a…
abonie Jun 15, 2026
a989169
Query suggested-action sources directly instead of driving the lightb…
abonie Jun 15, 2026
3b112b8
Drive code-fix sources via GetSuggestedActionCategoriesAsync, not Has…
abonie Jun 15, 2026
14751ed
Read code actions from the lightbulb session's populate result via re…
abonie Jun 15, 2026
175f9c8
Drive code actions through the producer-agnostic lightbulb broker ses…
abonie Jun 16, 2026
582b83c
Expand the session
abonie Jun 16, 2026
995eea3
Investigation: dump Error List contents when a code-action test fails
abonie Jun 16, 2026
9333d76
Wait quietly for F# document diagnostics before invoking the lightbulb
abonie Jun 16, 2026
4133bca
EXPERIMENT: 2-minute quiet settle before invoking the lightbulb
abonie Jun 16, 2026
799196c
Wait on IsLightBulbSessionActive instead of the Error List before inv…
abonie Jun 17, 2026
7a11506
Restore 2-minute settle; skip the error-list wait for unused-opens
abonie Jun 17, 2026
9e97da5
Make CodeAction integration tests deterministic via Roslyn async-oper…
abonie Jun 17, 2026
c1c9963
Read the editor's real lightbulb session instead of a broker-owned one
abonie Jun 17, 2026
2f3b887
Add producer-agnostic probe of broker-available actions to failure dump
abonie Jun 19, 2026
9fb09a3
Stabilize code-action tests: retry, re-analysis trigger, quarantine u…
abonie Jun 22, 2026
06bd617
Remove MaxAttempts: incompatible with xunit.console -xml reporter
abonie Jun 22, 2026
e34305e
Re-force F# diagnostics periodically inside the code-action retry loop
abonie Jun 22, 2026
dbc6c27
Run inttests_release VS on an interactive desktop session (Roslyn-sty…
abonie Jun 22, 2026
658c8d5
Add diagnostic tracing to UnusedOpens pipeline for CI investigation
abonie Jun 23, 2026
7e82cf8
Merge remote-tracking branch 'upstream/main' into enable-integration-…
abonie Jun 23, 2026
e2b130a
Apply fantomas formatting to UnusedOpens diagnostic tracing
abonie Jun 23, 2026
e9d5d8f
Trigger reanalysis once, not periodically, so slow unused-opens analy…
abonie Jun 23, 2026
8475d0d
Separate produce from read: wait for a fix to be offered before invok…
abonie Jun 23, 2026
42debbe
Add spaced fallback read for gate-blind fixes (F# ErrorFix)
abonie Jun 24, 2026
c899537
Run inttests via VSTest to enable MaxAttempts retry; pure B+ gate
abonie Jun 24, 2026
88ec329
Quarantine UnusedOpenDeclarations: flaky F# unused-opens diagnostic p…
abonie Jun 24, 2026
1afa66a
Revert VSTest+MaxAttempts; restore the fallback-read state where AddM…
abonie Jun 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions azure-pipelines-PR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -436,22 +436,28 @@ stages:
coreclr_release:
_configuration: Release
_testKind: testCoreclr
prepareMachineArg: ''
transparentCompiler: # Empty display name part.
vs_release:
_configuration: Release
_testKind: testVs
setupVsHive: true
FSharp_CacheEvictionImmediate: true
prepareMachineArg: ''
transparentCompiler:
transparent_compiler_release:
_configuration: Release
_testKind: testCoreclr
TEST_TRANSPARENT_COMPILER: 1 # Pipeline variable will map to env var.
prepareMachineArg: ''
transparentCompiler: TransparentCompiler
# inttests_release:
# _configuration: Release
# _testKind: testIntegration
# setupVsHive: true
inttests_release:
_configuration: Release
_testKind: testIntegration
setupVsHive: true
# Enables on-exit devenv cleanup; the integration leg also runs VS on an
# interactive desktop session (Setup-IntegrationTestRun in eng\Build.ps1).
prepareMachineArg: -prepareMachine
steps:
- checkout: self
clean: true
Expand All @@ -460,14 +466,26 @@ stages:
displayName: Setup VS Hive
condition: eq(variables.setupVsHive, 'true')

- script: eng\CIBuildNoPublish.cmd -compressallmetadata -configuration $(_configuration) -$(_testKind)
- script: eng\CIBuildNoPublish.cmd -compressallmetadata -configuration $(_configuration) -$(_testKind) $(prepareMachineArg)
env:
DOTNET_DbgEnableMiniDump: 1
DOTNET_DbgMiniDumpType: 2 # 1=mini, 2=heap, 3=triage, 4=full. Heap dumps include managed object data for debugging.
DOTNET_DbgMiniDumpName: $(Build.SourcesDirectory)\artifacts\log\$(_configuration)\$(Build.BuildId)-%e-%p-%t.dmp
NativeToolsOnMachine: true
displayName: Build and Test $(_testKind) $(transparentCompiler)

# Publish the integration-test startup screenshot to prove devenv ran on a live
# interactive desktop session (captured by Setup-IntegrationTestRun).
- task: PublishBuildArtifacts@1
displayName: Publish Integration Test Screenshot
condition: and(always(), eq(variables._testKind, 'testIntegration'))
continueOnError: true
inputs:
PathToPublish: '$(Build.SourcesDirectory)\artifacts\log\$(_configuration)\StartingBuild.png'
ArtifactName: 'Windows $(_configuration) $(_testKind) screenshot'
ArtifactType: Container
parallel: true

- task: PublishTestResults@2
displayName: Publish Test Results
inputs:
Expand Down
98 changes: 96 additions & 2 deletions eng/Build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,90 @@ function TestUsingMSBuild([string] $testProject, [string] $targetFramework, [str
Exec-Console $dotnetExe $test_args
}

# Runs a test assembly via the xUnit v2 console runner, bypassing `dotnet test` (and therefore
# the repo-wide Microsoft.Testing.Platform gate declared in global.json). Used only for projects
# whose harness cannot run under MTP -- today that is FSharp.Editor.IntegrationTests, which
# depends on Microsoft.VisualStudio.Extensibility.Testing.Xunit (VS-hive launcher, xUnit-v2-locked).
# The runner is restored via a <PackageDownload Include="xunit.runner.console" .../> on the
# test project, so it is present in the NuGet global packages folder after a normal slnx restore.
function TestUsingXUnitConsole([string] $testProject, [string] $targetFramework) {

$projectName = [System.IO.Path]::GetFileNameWithoutExtension($testProject)
$assemblyPath = "$ArtifactsDir\bin\$projectName\$configuration\$targetFramework\$projectName.dll"
if (-not (Test-Path $assemblyPath)) {
throw "Test assembly not found at $assemblyPath. Was $projectName built before -testIntegration was invoked?"
}

# Get-PackageVersion (eng\build-utils.ps1) reads <XunitRunnerConsoleV2Version> from eng\Versions.props,
# and Get-PackageDir resolves the NuGet cache path. Defensive Trim() covers accidental whitespace in the value.
$runnerVersion = (Get-PackageVersion "XunitRunnerConsoleV2").Trim()
$xunitConsole = Join-Path (Get-PackageDir "xunit.runner.console" $runnerVersion) "tools\net472\xunit.console.exe"
if (-not (Test-Path $xunitConsole)) {
throw "xunit.console.exe not found at $xunitConsole. Ensure restore of $projectName ran first (PackageDownload of xunit.runner.console v$runnerVersion)."
}

$testResultsDir = "$ArtifactsDir\TestResults\$configuration"
Create-Directory $testResultsDir
$jobName = if ($env:SYSTEM_JOBNAME) { $env:SYSTEM_JOBNAME } else { "local" }
$resultsXml = Join-Path $testResultsDir "$projectName.$targetFramework.$jobName.xml"

# -parallel none / -noshadow mirror the project's xunit.runner.json (parallelizeTestCollections=false, shadowCopy=false).
$xunit_args = """$assemblyPath"" -xml ""$resultsXml"" -parallel none -noshadow -nologo"

Write-Host("$xunitConsole $xunit_args")

Exec-Console $xunitConsole $xunit_args
}

# Sets up the CI machine for running our VS integration tests, mirroring dotnet/roslyn's
# Setup-IntegrationTestRun (eng\build.ps1). The VS editor's view-driven diagnostic producers
# (e.g. the error-squiggle tagger) only run reliably with a realized, visible desktop, so we
# ensure devenv runs on an interactive session: probe by taking a screenshot, and if that fails
# reconnect the session to the physical console via tscon, then re-capture (fail-fast otherwise).
function Setup-IntegrationTestRun() {
# Ensure leftover devenv instances are cleaned up on exit (honored when -ci -prepareMachine).
$script:processesToStopOnExit += "devenv"

$screenshotPath = (Join-Path $LogDir "StartingBuild.png")
try {
Capture-Screenshot $screenshotPath
}
catch {
Write-Host "Screenshot failed; attempting to connect to the console"

# Keep the session open so we have a UI to interact with
$quserItems = ((quser $env:USERNAME | Select-Object -Skip 1) -split '\s+')
$sessionid = $quserItems[2]
if ($sessionid -eq 'Disc') {
# When the session isn't connected, the third value is 'Disc' instead of the ID
$sessionid = $quserItems[1]
}

if ($quserItems[1] -eq 'console') {
Write-Host "Disconnecting from console before attempting reconnection"
try {
tsdiscon
} catch {
# ignore
}

# Disconnection is asynchronous, so wait a few seconds for it to complete
Start-Sleep -Seconds 3
query user
}

Write-Host "tscon $sessionid /dest:console"
tscon $sessionid /dest:console

# Connection is asynchronous, so wait a few seconds for it to complete
Start-Sleep 3
query user

# Make sure we can capture a screenshot. An exception at this point will fail-fast the build.
Capture-Screenshot $screenshotPath
}
}

function Prepare-TempDir() {
Copy-Item (Join-Path $RepoRoot "tests\Resources\Directory.Build.props") $TempDir
Copy-Item (Join-Path $RepoRoot "tests\Resources\Directory.Build.targets") $TempDir
Expand Down Expand Up @@ -529,6 +613,7 @@ try {
Process-Arguments

. (Join-Path $PSScriptRoot "build-utils.ps1")
. (Join-Path $PSScriptRoot "build-utils-win.ps1")

Update-Arguments

Expand All @@ -544,6 +629,15 @@ try {
if ($ci) {
Prepare-TempDir
EnablePreviewSdks

if ($testIntegration -and -not $noVisualStudio) {
# Minimize all windows to avoid interference during integration test runs, then ensure
# devenv has an interactive desktop session (see Setup-IntegrationTestRun).
$shell = New-Object -ComObject "Shell.Application"
$shell.MinimizeAll()

Setup-IntegrationTestRun
}
}

$buildTool = InitializeBuildTool
Expand Down Expand Up @@ -665,8 +759,8 @@ try {
TestUsingMSBuild -testProject "$RepoRoot\vsintegration\tests\UnitTests\VisualFSharp.UnitTests.fsproj" -targetFramework $script:desktopTargetFramework
}

if ($testIntegration) {
TestUsingMSBuild -testProject "$RepoRoot\vsintegration\tests\FSharp.Editor.IntegrationTests\FSharp.Editor.IntegrationTests.csproj" -targetFramework $script:desktopTargetFramework
if ($testIntegration -and -not $noVisualStudio) {
TestUsingXUnitConsole -testProject "$RepoRoot\vsintegration\tests\FSharp.Editor.IntegrationTests\FSharp.Editor.IntegrationTests.csproj" -targetFramework $script:desktopTargetFramework
}

if ($testAOT) {
Expand Down
26 changes: 26 additions & 0 deletions eng/SetupVSHive.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,32 @@ $vsRegEdit = Join-Path (Join-Path (Join-Path $vsDir 'Common7') 'IDE') 'VSRegEdit
$hive = "RoslynDev"
&$vsRegEdit set "$vsDir" $hive HKCU "Roslyn\Internal\OnOff\Features" OOP64Bit dword 0

# VS/UI hardening for headless integration test runs, ported from dotnet/roslyn eng\build.ps1.
# These reduce interference (toasts, dialogs, roaming) that can disrupt the editor and the
# error list / light bulb during code-action tests.

# Disable roaming settings to avoid interference from the online user profile
&$vsRegEdit set "$vsDir" $hive HKCU "ApplicationPrivateSettings\Microsoft\VisualStudio" RoamingEnabled string "1*System.Boolean*False"

# Disable IntelliCode line completions to avoid interference with completion testing
&$vsRegEdit set "$vsDir" $hive HKCU "ApplicationPrivateSettings\Microsoft\VisualStudio\IntelliCode" wholeLineCompletions string "0*System.Int32*2"

# Disable IntelliCode RepositoryAttachedModels since it requires authentication which can fail in CI
&$vsRegEdit set "$vsDir" $hive HKCU "ApplicationPrivateSettings\Microsoft\VisualStudio\IntelliCode" repositoryAttachedModels string "0*System.Int32*2"

# Disable background download UI to avoid toasts
&$vsRegEdit set "$vsDir" $hive HKCU "FeatureFlags\Setup\BackgroundDownload" Value dword 0

# Disable text spell checker to avoid spurious warnings in the error list
&$vsRegEdit set "$vsDir" $hive HKCU "FeatureFlags\Editor\EnableSpellChecker" Value dword 0

# Disable text editor error reporting because it pops up a dialog. We want to fail fast or
# fail silently and continue testing, never block on a modal dialog.
&$vsRegEdit set "$vsDir" $hive HKCU "Text Editor" "Report Exceptions" dword 0

# Disable targeted notifications (does not work via vsregedit, so set the registry directly)
reg add hkcu\Software\Microsoft\VisualStudio\RemoteSettings /f /t REG_DWORD /v TurnOffSwitch /d 1

Write-Host "-- VS Info --"
$isolationIni = Join-Path (Join-Path (Join-Path $vsDir 'Common7') 'IDE') 'devenv.isolation.ini'
Get-Content $isolationIni | Write-Host
Expand Down
4 changes: 3 additions & 1 deletion eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@
<MicrosoftVisualStudioPlatformVSEditorVersion>$(VisualStudioEditorPackagesVersion)</MicrosoftVisualStudioPlatformVSEditorVersion>
<MicrosoftVisualStudioTextUIWpfVersion>$(VisualStudioEditorPackagesVersion)</MicrosoftVisualStudioTextUIWpfVersion>
<NuGetVisualStudioVersion>17.14.0</NuGetVisualStudioVersion>
<MicrosoftVisualStudioExtensibilityTestingVersion>0.1.800-beta</MicrosoftVisualStudioExtensibilityTestingVersion>
<MicrosoftVisualStudioExtensibilityTestingVersion>5.3.0-2.26055.8</MicrosoftVisualStudioExtensibilityTestingVersion>
<MicrosoftVisualStudioExtensibilityTestingSourceGeneratorVersion>$(MicrosoftVisualStudioExtensibilityTestingVersion)</MicrosoftVisualStudioExtensibilityTestingSourceGeneratorVersion>

<!-- Visual Studio Threading packages -->
Expand Down Expand Up @@ -161,6 +161,8 @@
<NewtonsoftJsonVersion>13.0.4</NewtonsoftJsonVersion>
<XunitVersion>3.2.2</XunitVersion>
<XunitRunnerConsoleVersion>3.2.2</XunitRunnerConsoleVersion>
<!-- xUnit v2 runner, only consumed by FSharp.Editor.IntegrationTests (VS-hive harness is xUnit-v2-locked). -->
<XunitRunnerConsoleV2Version>2.9.3</XunitRunnerConsoleV2Version>
<XunitXmlTestLoggerVersion>8.0.0</XunitXmlTestLoggerVersion>
<!-- -->
</PropertyGroup>
Expand Down
34 changes: 34 additions & 0 deletions eng/build-utils-win.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

# Collection of Windows-only PowerShell build utility functions used by our CI scripts.
# Ported from dotnet/roslyn eng\build-utils-win.ps1 to support running the VS integration
# tests on an interactive desktop session (screenshot probe + tscon reconnect).

Set-StrictMode -version 2.0
$ErrorActionPreference = "Stop"

Add-Type -AssemblyName 'System.Drawing'
Add-Type -AssemblyName 'System.Windows.Forms'
function Capture-Screenshot($path) {
$width = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Width
$height = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Height

$bitmap = New-Object System.Drawing.Bitmap $width, $height
try {
$graphics = [System.Drawing.Graphics]::FromImage($bitmap)
try {
$graphics.CopyFromScreen( `
[System.Windows.Forms.Screen]::PrimaryScreen.Bounds.X, `
[System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Y, `
0, `
0, `
$bitmap.Size, `
[System.Drawing.CopyPixelOperation]::SourceCopy)
} finally {
$graphics.Dispose()
}

$bitmap.Save($path, [System.Drawing.Imaging.ImageFormat]::Png)
} finally {
$bitmap.Dispose()
}
}
38 changes: 34 additions & 4 deletions src/Compiler/Service/ServiceAnalysis.fs
Original file line number Diff line number Diff line change
Expand Up @@ -304,19 +304,49 @@ module UnusedOpens =
async {
use! _holder = Cancellable.UseToken()

System.Diagnostics.Trace.TraceInformation(
"[UnusedOpens] getUnusedOpens called. OpenDeclarations.Length={0}",
checkFileResults.OpenDeclarations.Length
)

if checkFileResults.OpenDeclarations.Length = 0 then
System.Diagnostics.Trace.TraceInformation("[UnusedOpens] No open declarations, returning empty")
return []
else
let! ct = Async.CancellationToken
let symbolUses = checkFileResults.GetAllUsesOfAllSymbolsInFile(ct)
let symbolUses = filterSymbolUses getSourceLineStr symbolUses
let symbolUses = splitSymbolUses symbolUses
let allSymbolUses = checkFileResults.GetAllUsesOfAllSymbolsInFile(ct)

let filteredSymbolUses = filterSymbolUses getSourceLineStr allSymbolUses
let symbolUses1, symbolUses2 = splitSymbolUses filteredSymbolUses
let openStatements = getOpenStatements checkFileResults.OpenDeclarations

System.Diagnostics.Trace.TraceInformation(
"[UnusedOpens] filteredSymbolUses={0}, symbolUses1={1}, symbolUses2={2}, openStatements={3}",
filteredSymbolUses.Length,
symbolUses1.Length,
symbolUses2.Length,
openStatements.Length
)

for os in openStatements do
System.Diagnostics.Trace.TraceInformation(
"[UnusedOpens] openStatement range={0}, openedGroups={1}",
os.Range,
os.OpenedGroups.Length
)

if openStatements.Length = 0 then
System.Diagnostics.Trace.TraceInformation("[UnusedOpens] No open statements, returning empty")
return []
else
return! filterOpenStatements symbolUses openStatements
let! result = filterOpenStatements (symbolUses1, symbolUses2) openStatements

System.Diagnostics.Trace.TraceInformation("[UnusedOpens] Result: {0} unused opens", result.Length)

for r in result do
System.Diagnostics.Trace.TraceInformation("[UnusedOpens] unused: {0}", r)

return result
}

module SimplifyNames =
Expand Down
Loading
Loading