fix: prevent hanging tests and optimize CI builds - #27
Merged
Conversation
HelloThisWorld
marked this pull request as ready for review
August 2, 2026 05:03
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Prevent Debug TAEF suites from hanging for hours and make native validation an explicit, label-gated operation. The Release delivery path now builds the package-capable source graph once and reuses it for compiled tests, unpackaged staging, Setup, Portable, lifecycle tests, and downloadable artifacts.
Related issues
N/A
Detailed changes
Debug hang root cause and code fix
The non-terminating executable was the shared TAEF runner for
unitControlloadingControl.Unit.Tests.dll.CommandTimelineTests::NativeOscLifecycleFeedsPaneTimelineresized a test-ownedControlCorewithout opting into its synchronous unit-test notification path. The resize queued a throttled scrollbar callback on a UI dispatcher that TAEF does not pump, and Debug teardown could wait indefinitely for that pending callback.The prior Command Timeline fix sets
ControlCore::_inUnitTestsbefore initialization. This PR makes teardown deterministic as well: a scope guard always callsClose()and releases the core, mock connection, settings, renderer, terminal state, event revokers, and WinRT references before TAEF advances or unloads the module.Bounded compiled tests and diagnostics
scripts/winterm/test.ps1now launches the exact TAEF runner for each Relevant suite independently:unitSettingsModel: isolatedbin\x64\<Configuration>\UnitTests_SettingsModel\te.exeterminalApp: repository TAEF plusTerminal.App.Unit.Tests.dllunitControl: repository TAEF plusControl.Unit.Tests.dllEach suite has a 20-minute process timeout. Timeout handling terminates the runner and all descendants, returns failure, and records configuration, suite, executable, binary, command, timestamps, timeout, status, and exit code. Stdout, stderr, and diagnostic files are uploaded with
if: always().Workflow structure
Previous delivery validation built both Debug and Release, then checked out the repository in a separate package job and rebuilt the Release package graph through
build-unpackaged.ps1.The new modes are:
build: one package-capable x64 Release build, Release compiled tests, unpackaged/Setup/Portable creation, lifecycle tests, and downloadable artifacts. Debug is skipped.delivery: everything inbuild, plus x64 Debug build/tests in parallel with Release delivery.ci:full: compatibility alias fordelivery.Manual
quick,build, anddeliverymodes are available; legacyfastandfullmap tobuildanddelivery. The finalci-gaterejects failed, cancelled, missing, or unexpectedly executed jobs.The Release job calls
build.ps1 -GeneratePackage -IncludeTestsonce, then callsbuild-unpackaged.ps1 -SkipBuild; installer and portable builders also reuse that stage with-SkipBuild.Build performance and safety
The package/WinMD/shared-PDB dependency graph remains serialized with
/m:1. The solution-level restore performed by the package build is reused, while the three independent test projects build sequentially as projects with normal MSBuild/msupport and no per-project/restore.Job limits are 20 minutes for quick validation, 120 minutes for Debug, 120 minutes for Release delivery, 20 minutes per compiled suite, and 5 minutes for the final gate.
Validation performed
Passed locally:
.github/workflows/winterm-validation.yml.powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/winterm/test-ci-classification.ps1.powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/winterm/test-release-workflow.ps1.Control.UnitTests.vcxprojbuilds with MSBuild/m.Status=passedandExitCode=0.git diff --check.Local limitations:
Compatibility.ps1during the standalone shell-integration invocation withScriptContainedMaliciousContent; no security policy was bypassed. The same shell-integration step passed in every GitHub Actions Quick job.GitHub Actions verification:
ci-gateran, while Debug and Release were skipped.buildrun 30733431814: success; one Release delivery graph ran, Debug was skipped, lifecycle tests passed, and Release diagnostics plus the distribution artifact were uploaded.deliveryrun 30734447222: success; Debug and Release started in parallel at05:38:10Z, Debug completed in 22m34s, its three bounded suites completed in 38 seconds, Release completed in 29m02s, and the final gate passed.winTerm-x64-Debug-compiled-test-diagnostics,winTerm-x64-Release-compiled-test-diagnostics, andwinTerm-1.2.1-x64-distributionsartifacts. The distribution artifact was downloaded and verified to containwinTerm-1.2.1-setup-x64.exeandwinTerm-1.2.1-portable-x64.zip.buildrun 30732852166 was automatically cancelled when the PR changed from draft to ready-for-review and its replacement run started; its cancelled gate was expected and is superseded by the successful runs above.Checklist
winterm.exe, and Microsoft Terminal coexistence remain isolated.