Skip to content

Commit ecd2f26

Browse files
Merge pull request #1848 from PowerShell/andschwa/ci-stability
Improve CI stability
2 parents bd4f5b0 + 80ab5a4 commit ecd2f26

23 files changed

+225
-266
lines changed

PowerShellEditorServices.build.ps1

+41-40
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@ param(
1111

1212
[string]$DefaultModuleRepository = "PSGallery",
1313

14+
[string[]]$VerbosityArgs = @("--verbosity", "quiet", "--nologo"),
15+
1416
# See: https://docs.microsoft.com/en-us/dotnet/core/testing/selective-unit-tests
1517
[string]$TestFilter = '',
1618

1719
# See: https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-test
18-
# E.g. use @("--logger", "console;verbosity=detailed") for detailed console output instead
19-
[string[]]$TestArgs = @("--logger", "trx")
20+
[string[]]$TestArgs = $VerbosityArgs + @("--logger", "console;verbosity=normal", "--logger", "trx")
2021
)
2122

2223
#Requires -Modules @{ModuleName="InvokeBuild"; ModuleVersion="5.0.0"}
@@ -38,9 +39,9 @@ $script:BuildInfoPath = [System.IO.Path]::Combine($PSScriptRoot, "src", "PowerSh
3839
$script:PsesCommonProps = [xml](Get-Content -Raw "$PSScriptRoot/PowerShellEditorServices.Common.props")
3940

4041
$script:NetRuntime = @{
41-
PS7 = 'netcoreapp3.1'
42-
PS72 = 'net6.0'
43-
Desktop = 'net462'
42+
PS7 = 'netcoreapp3.1'
43+
PS72 = 'net6.0'
44+
Desktop = 'net462'
4445
Standard = 'netstandard2.0'
4546
}
4647

@@ -54,31 +55,31 @@ if (Get-Command git -ErrorAction SilentlyContinue) {
5455
git update-index --assume-unchanged "$PSScriptRoot/src/PowerShellEditorServices.Hosting/BuildInfo.cs"
5556
}
5657

57-
task FindDotNet {
58-
assert (Get-Command dotnet -ErrorAction SilentlyContinue) "dotnet not found, please install it: https://aka.ms/dotnet-cli"
58+
Task FindDotNet {
59+
Assert (Get-Command dotnet -ErrorAction SilentlyContinue) "dotnet not found, please install it: https://aka.ms/dotnet-cli"
5960

6061
# Strip out semantic version metadata so it can be cast to `Version`
6162
$existingVersion, $null = (dotnet --version) -split '-'
62-
assert ([Version]$existingVersion -ge [Version]("6.0")) ".NET SDK 6.0 or higher is required, please update it: https://aka.ms/dotnet-cli"
63+
Assert ([Version]$existingVersion -ge [Version]("6.0")) ".NET SDK 6.0 or higher is required, please update it: https://aka.ms/dotnet-cli"
6364

6465
# Anywhere other than on a Mac with an M1 processor, we additionally
6566
# need the .NET 3.1 runtime for our netcoreapp3.1 framework.
6667
if (-not $script:IsAppleM1 -and -not $script:IsArm64) {
6768
$runtimes = dotnet --list-runtimes
68-
assert ($runtimes -match "Microsoft.NETCore.App 3.1") ".NET Runtime 3.1 required but not found!"
69+
Assert ($runtimes -match "Microsoft.NETCore.App 3.1") ".NET Runtime 3.1 required but not found!"
6970
}
7071

7172
Write-Host "Using dotnet v$(dotnet --version) at path $((Get-Command dotnet).Source)" -ForegroundColor Green
7273
}
7374

74-
task BinClean {
75+
Task BinClean {
7576
Remove-Item $PSScriptRoot\.tmp -Recurse -Force -ErrorAction Ignore
7677
Remove-Item $PSScriptRoot\module\PowerShellEditorServices\bin -Recurse -Force -ErrorAction Ignore
7778
Remove-Item $PSScriptRoot\module\PowerShellEditorServices.VSCode\bin -Recurse -Force -ErrorAction Ignore
7879
}
7980

80-
task Clean FindDotNet, BinClean, {
81-
exec { & dotnet clean }
81+
Task Clean FindDotNet, BinClean, {
82+
Exec { & dotnet clean $VerbosityArgs }
8283
Get-ChildItem -Recurse $PSScriptRoot\src\*.nupkg | Remove-Item -Force -ErrorAction Ignore
8384
Get-ChildItem $PSScriptRoot\PowerShellEditorServices*.zip | Remove-Item -Force -ErrorAction Ignore
8485
Get-ChildItem $PSScriptRoot\module\PowerShellEditorServices\Commands\en-US\*-help.xml | Remove-Item -Force -ErrorAction Ignore
@@ -93,7 +94,7 @@ task Clean FindDotNet, BinClean, {
9394
}
9495
}
9596

96-
task CreateBuildInfo {
97+
Task CreateBuildInfo {
9798
$buildVersion = "<development-build>"
9899
$buildOrigin = "Development"
99100
$buildCommit = git rev-parse HEAD
@@ -147,77 +148,77 @@ namespace Microsoft.PowerShell.EditorServices.Hosting
147148
"@
148149

149150
if (Compare-Object $buildInfoContents.Split([Environment]::NewLine) (Get-Content $script:BuildInfoPath)) {
150-
Write-Host "Updating Build Info"
151+
Write-Host "Updating build info."
151152
Set-Content -LiteralPath $script:BuildInfoPath -Value $buildInfoContents -Force
152153
}
153154
}
154155

155-
task SetupHelpForTests {
156+
Task SetupHelpForTests {
156157
if (-not (Get-Help Write-Host).Examples) {
157-
Write-Host "Updating help for tests"
158+
Write-Host "Updating help for tests."
158159
Update-Help -Module Microsoft.PowerShell.Utility -Force -Scope CurrentUser
159160
}
160161
}
161162

162163
Task Build FindDotNet, CreateBuildInfo, {
163-
exec { & dotnet restore }
164-
exec { & dotnet publish -c $Configuration .\src\PowerShellEditorServices\PowerShellEditorServices.csproj -f $script:NetRuntime.Standard }
165-
exec { & dotnet publish -c $Configuration .\src\PowerShellEditorServices.Hosting\PowerShellEditorServices.Hosting.csproj -f $script:NetRuntime.PS7 }
164+
Exec { & dotnet restore $VerbosityArgs }
165+
Exec { & dotnet publish $VerbosityArgs -c $Configuration .\src\PowerShellEditorServices\PowerShellEditorServices.csproj -f $script:NetRuntime.Standard }
166+
Exec { & dotnet publish $VerbosityArgs -c $Configuration .\src\PowerShellEditorServices.Hosting\PowerShellEditorServices.Hosting.csproj -f $script:NetRuntime.PS7 }
166167
if (-not $script:IsNix) {
167-
exec { & dotnet publish -c $Configuration .\src\PowerShellEditorServices.Hosting\PowerShellEditorServices.Hosting.csproj -f $script:NetRuntime.Desktop }
168+
Exec { & dotnet publish $VerbosityArgs -c $Configuration .\src\PowerShellEditorServices.Hosting\PowerShellEditorServices.Hosting.csproj -f $script:NetRuntime.Desktop }
168169
}
169170

170171
# Build PowerShellEditorServices.VSCode module
171-
exec { & dotnet publish -c $Configuration .\src\PowerShellEditorServices.VSCode\PowerShellEditorServices.VSCode.csproj -f $script:NetRuntime.Standard }
172+
Exec { & dotnet publish $VerbosityArgs -c $Configuration .\src\PowerShellEditorServices.VSCode\PowerShellEditorServices.VSCode.csproj -f $script:NetRuntime.Standard }
172173
}
173174

174-
task Test TestServer, TestE2E
175+
Task Test TestServer, TestE2E
175176

176-
task TestServer TestServerWinPS, TestServerPS7, TestServerPS72
177+
Task TestServer TestServerWinPS, TestServerPS7, TestServerPS72
177178

178179
Task TestServerWinPS -If (-not $script:IsNix) Build, SetupHelpForTests, {
179180
Set-Location .\test\PowerShellEditorServices.Test\
180181
# TODO: See https://github.com/dotnet/sdk/issues/18353 for x64 test host
181182
# that is debuggable! If architecture is added, the assembly path gets an
182183
# additional folder, necesstiating fixes to find the commands definition
183184
# file and test files.
184-
exec { & dotnet $script:dotnetTestArgs $script:NetRuntime.Desktop }
185+
Exec { & dotnet $script:dotnetTestArgs $script:NetRuntime.Desktop }
185186
}
186187

187-
task TestServerPS7 -If (-not $script:IsAppleM1 -and -not $script:IsArm64) Build, SetupHelpForTests, {
188+
Task TestServerPS7 -If (-not $script:IsAppleM1 -and -not $script:IsArm64) Build, SetupHelpForTests, {
188189
Set-Location .\test\PowerShellEditorServices.Test\
189-
exec { & dotnet $script:dotnetTestArgs $script:NetRuntime.PS7 }
190+
Exec { & dotnet $script:dotnetTestArgs $script:NetRuntime.PS7 }
190191
}
191192

192-
task TestServerPS72 Build, SetupHelpForTests, {
193+
Task TestServerPS72 Build, SetupHelpForTests, {
193194
Set-Location .\test\PowerShellEditorServices.Test\
194-
exec { & dotnet $script:dotnetTestArgs $script:NetRuntime.PS72 }
195+
Exec { & dotnet $script:dotnetTestArgs $script:NetRuntime.PS72 }
195196
}
196197

197-
task TestE2E Build, SetupHelpForTests, {
198+
Task TestE2E Build, SetupHelpForTests, {
198199
Set-Location .\test\PowerShellEditorServices.Test.E2E\
199200

200201
$env:PWSH_EXE_NAME = if ($IsCoreCLR) { "pwsh" } else { "powershell" }
201202
$NetRuntime = if ($IsAppleM1 -or $script:IsArm64) { $script:NetRuntime.PS72 } else { $script:NetRuntime.PS7 }
202-
exec { & dotnet $script:dotnetTestArgs $NetRuntime }
203+
Exec { & dotnet $script:dotnetTestArgs $NetRuntime }
203204

204-
# Run E2E tests in ConstrainedLanguage mode.
205205
if (!$script:IsNix) {
206206
if (-not [Security.Principal.WindowsIdentity]::GetCurrent().Owner.IsWellKnown("BuiltInAdministratorsSid")) {
207-
Write-Warning 'Skipping E2E CLM tests as they must be ran in an elevated process.'
207+
Write-Warning "Skipping Constrained Language Mode tests as they must be ran in an elevated process."
208208
return
209209
}
210210

211211
try {
212+
Write-Host "Running end-to-end tests in Constrained Language Mode."
212213
[System.Environment]::SetEnvironmentVariable("__PSLockdownPolicy", "0x80000007", [System.EnvironmentVariableTarget]::Machine);
213-
exec { & dotnet $script:dotnetTestArgs $script:NetRuntime.PS7 }
214+
Exec { & dotnet $script:dotnetTestArgs $script:NetRuntime.PS7 }
214215
} finally {
215216
[System.Environment]::SetEnvironmentVariable("__PSLockdownPolicy", $null, [System.EnvironmentVariableTarget]::Machine);
216217
}
217218
}
218219
}
219220

220-
task LayoutModule -After Build {
221+
Task LayoutModule -After Build {
221222
$modulesDir = "$PSScriptRoot/module"
222223
$psesVSCodeBinOutputPath = "$modulesDir/PowerShellEditorServices.VSCode/bin"
223224
$psesOutputPath = "$modulesDir/PowerShellEditorServices"
@@ -226,8 +227,8 @@ task LayoutModule -After Build {
226227
$psesCoreHostPath = "$psesBinOutputPath/Core"
227228
$psesDeskHostPath = "$psesBinOutputPath/Desktop"
228229

229-
foreach ($dir in $psesDepsPath,$psesCoreHostPath,$psesDeskHostPath,$psesVSCodeBinOutputPath) {
230-
New-Item -Force -Path $dir -ItemType Directory
230+
foreach ($dir in $psesDepsPath, $psesCoreHostPath, $psesDeskHostPath, $psesVSCodeBinOutputPath) {
231+
New-Item -Force -Path $dir -ItemType Directory | Out-Null
231232
}
232233

233234
# Copy Third Party Notices.txt to module folder
@@ -310,7 +311,7 @@ task RestorePsesModules -After Build {
310311
# Save each module in the modules.json file
311312
foreach ($moduleName in $moduleInfos.Keys) {
312313
if (Test-Path -Path (Join-Path -Path $submodulePath -ChildPath $moduleName)) {
313-
Write-Host "`tModule '${moduleName}' already detected. Skipping"
314+
Write-Host "`tModule '${moduleName}' already detected, skipping!"
314315
continue
315316
}
316317

@@ -331,9 +332,9 @@ task RestorePsesModules -After Build {
331332
}
332333

333334
Task BuildCmdletHelp -After LayoutModule {
334-
New-ExternalHelp -Path $PSScriptRoot\module\docs -OutputPath $PSScriptRoot\module\PowerShellEditorServices\Commands\en-US -Force
335-
New-ExternalHelp -Path $PSScriptRoot\module\PowerShellEditorServices.VSCode\docs -OutputPath $PSScriptRoot\module\PowerShellEditorServices.VSCode\en-US -Force
335+
New-ExternalHelp -Path $PSScriptRoot\module\docs -OutputPath $PSScriptRoot\module\PowerShellEditorServices\Commands\en-US -Force | Out-Null
336+
New-ExternalHelp -Path $PSScriptRoot\module\PowerShellEditorServices.VSCode\docs -OutputPath $PSScriptRoot\module\PowerShellEditorServices.VSCode\en-US -Force | Out-Null
336337
}
337338

338339
# The default task is to run the entire CI build
339-
task . Clean, Build, Test
340+
Task . Clean, Build, Test

src/PowerShellEditorServices/Server/PsesServiceCollectionExtensions.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ public static IServiceCollection AddPsesLanguageServices(
4848
// is ready, it will be available. NOTE: We cannot await this because it
4949
// uses a lazy initialization to avoid a race with the dependency injection
5050
// framework, see the EditorObject class for that!
51+
#pragma warning disable VSTHRD110
5152
extensionService.InitializeAsync();
52-
53+
#pragma warning restore VSTHRD110
5354
return extensionService;
5455
})
5556
.AddSingleton<AnalysisService>();

src/PowerShellEditorServices/Services/DebugAdapter/DebugEventHandlerService.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ private void OnRunspaceChanged(object sender, RunspaceChangedEventArgs e)
101101
// Sends the InitializedEvent so that the debugger will continue
102102
// sending configuration requests
103103
_debugStateService.WaitingForAttach = false;
104-
_debugStateService.ServerStarted.SetResult(true);
104+
_debugStateService.ServerStarted.TrySetResult(true);
105105
}
106106
return;
107107

src/PowerShellEditorServices/Services/DebugAdapter/Handlers/LaunchAndAttachHandler.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ public async Task<LaunchResponse> Handle(PsesLaunchRequestArguments request, Can
210210

211211
// Sends the InitializedEvent so that the debugger will continue
212212
// sending configuration requests
213-
_debugStateService.ServerStarted.SetResult(true);
213+
_debugStateService.ServerStarted.TrySetResult(true);
214214

215215
return new LaunchResponse();
216216
}
@@ -440,7 +440,7 @@ await _executionService.ExecutePSCommandAsync(
440440

441441
if (runspaceVersion.Version.Major >= 7)
442442
{
443-
_debugStateService.ServerStarted.SetResult(true);
443+
_debugStateService.ServerStarted.TrySetResult(true);
444444
}
445445
return new AttachResponse();
446446
}
@@ -453,7 +453,7 @@ await _executionService.ExecutePSCommandAsync(
453453
// PSES sends the initialized event at the end of the Launch/Attach handler
454454

455455
// The way that the Omnisharp server works is that this OnStarted handler runs after OnInitialized
456-
// (after the Initialize DAP response is sent to the client) but before the _Initalized_ DAP event
456+
// (after the Initialize DAP response is sent to the client) but before the _Initialized_ DAP event
457457
// gets sent to the client. Because of the way PSES handles breakpoints,
458458
// we can't send the Initialized event until _after_ we finish the Launch/Attach handler.
459459
// The flow above depicts this. To achieve this, we wait until _debugStateService.ServerStarted

src/PowerShellEditorServices/Services/PowerShell/Context/PowerShellContextFrame.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ protected virtual void Dispose(bool disposing)
7979
public void Dispose()
8080
{
8181
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
82-
Dispose(disposing: true);
82+
Dispose(true);
8383
GC.SuppressFinalize(this);
8484
}
8585

src/PowerShellEditorServices/Services/PowerShell/Context/PowerShellVersionDetails.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4-
using Microsoft.Extensions.Logging;
5-
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Utility;
64
using System;
75
using System.Collections;
86
using System.Linq;
7+
using Microsoft.Extensions.Logging;
8+
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Utility;
99

1010
namespace Microsoft.PowerShell.EditorServices.Services.PowerShell.Context
1111
{
@@ -91,7 +91,7 @@ public PowerShellVersionDetails(
9191
/// Gets the PowerShell version details for the given runspace.
9292
/// </summary>
9393
/// <param name="logger">An ILogger implementation used for writing log messages.</param>
94-
/// <param name="pwsh">The PowerShell instance for which to to get the version.</param>
94+
/// <param name="pwsh">The PowerShell instance for which to get the version.</param>
9595
/// <returns>A new PowerShellVersionDetails instance.</returns>
9696
public static PowerShellVersionDetails GetVersionDetails(ILogger logger, PowerShell pwsh)
9797
{

src/PowerShellEditorServices/Services/PowerShell/Debugging/PowerShellDebugContext.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ public void ProcessDebuggerResult(DebuggerCommandResults debuggerResult)
187187
RaiseDebuggerResumingEvent(new DebuggerResumingEventArgs(debuggerResult.ResumeAction.Value));
188188

189189
// The Terminate exception is used by the engine for flow control
190-
// when it needs to unwind the callstack out of the debugger.
190+
// when it needs to unwind the call stack out of the debugger.
191191
if (debuggerResult.ResumeAction is DebuggerResumeAction.Stop)
192192
{
193193
throw new TerminateException();

src/PowerShellEditorServices/Services/PowerShell/Handlers/IGetPSHostProcessesHandler.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
namespace Microsoft.PowerShell.EditorServices.Handlers
88
{
99
[Serial, Method("powerShell/getPSHostProcesses")]
10-
internal interface IGetPSHostProcessesHandler : IJsonRpcRequestHandler<GetPSHostProcesssesParams, PSHostProcessResponse[]> { }
10+
internal interface IGetPSHostProcessesHandler : IJsonRpcRequestHandler<GetPSHostProcessesParams, PSHostProcessResponse[]> { }
1111

12-
internal class GetPSHostProcesssesParams : IRequest<PSHostProcessResponse[]> { }
12+
internal class GetPSHostProcessesParams : IRequest<PSHostProcessResponse[]> { }
1313

1414
internal class PSHostProcessResponse
1515
{

src/PowerShellEditorServices/Services/PowerShell/Handlers/PSHostProcessAndRunspaceHandlers.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99

1010
namespace Microsoft.PowerShell.EditorServices.Handlers
1111
{
12-
using Microsoft.PowerShell.EditorServices.Services.PowerShell;
1312
using System.Management.Automation;
13+
using Microsoft.PowerShell.EditorServices.Services.PowerShell;
1414

1515
internal class PSHostProcessAndRunspaceHandlers : IGetPSHostProcessesHandler, IGetRunspaceHandler
1616
{
@@ -23,7 +23,7 @@ public PSHostProcessAndRunspaceHandlers(ILoggerFactory factory, IInternalPowerSh
2323
_executionService = executionService;
2424
}
2525

26-
public Task<PSHostProcessResponse[]> Handle(GetPSHostProcesssesParams request, CancellationToken cancellationToken)
26+
public Task<PSHostProcessResponse[]> Handle(GetPSHostProcessesParams request, CancellationToken cancellationToken)
2727
{
2828
List<PSHostProcessResponse> psHostProcesses = new();
2929

src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs

+1-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) Microsoft Corporation.
1+
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

44
using System;
@@ -291,11 +291,6 @@ public void TriggerShutdown()
291291
if (Interlocked.Exchange(ref _shuttingDown, 1) == 0)
292292
{
293293
_cancellationContext.CancelCurrentTaskStack();
294-
// NOTE: This is mostly for sanity's sake, as during debugging of tests I became
295-
// concerned that the repeated creation and disposal of the host was not also
296-
// joining and disposing this thread, leaving the tests in a weird state. Because
297-
// the tasks have been canceled, we should be able to join this thread.
298-
_pipelineThread.Join();
299294
}
300295
}
301296

src/PowerShellEditorServices/Services/PowerShell/Utility/CancellationContext.cs

+12-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,18 @@ internal CancellationScope(
103103

104104
public CancellationToken CancellationToken => _cancellationSource.Token;
105105

106-
public void Cancel() => _cancellationSource.Cancel();
106+
public void Cancel()
107+
{
108+
try
109+
{
110+
_cancellationSource.Cancel();
111+
}
112+
catch (ObjectDisposedException)
113+
{
114+
// We don't want this race condition to cause flaky tests.
115+
// TODO: Find out the cause of the race!
116+
}
117+
}
107118

108119
public bool IsIdleScope { get; }
109120

test/PowerShellEditorServices.Test.E2E/DebugAdapterClientExtensions.cs

+1-4
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using Microsoft.PowerShell.EditorServices.Handlers;
77
using OmniSharp.Extensions.DebugAdapter.Client;
88
using OmniSharp.Extensions.DebugAdapter.Protocol.Requests;
9-
using System.Threading;
109

1110
namespace PowerShellEditorServices.Test.E2E
1211
{
@@ -29,9 +28,7 @@ public static async Task LaunchScript(this DebugAdapterClient debugAdapterClient
2928
}
3029

3130
// This will check to see if we received the Initialized event from the server.
32-
await Task.Run(
33-
async () => await started.Task.ConfigureAwait(true),
34-
new CancellationTokenSource(2000).Token).ConfigureAwait(true);
31+
await started.Task.ConfigureAwait(true);
3532
}
3633
}
3734
}

0 commit comments

Comments
 (0)