From 8c9d19db2f3712cb96d37b2025124f16be08c086 Mon Sep 17 00:00:00 2001 From: "Jeremy D. Miller" Date: Sun, 8 Nov 2026 11:00:01 -0600 Subject: [PATCH 1/2] Run the unit test suites on a Windows runner in CI Linux CI cannot catch platform assumptions such as the '/'-only path check in AssemblyFinder (#1143). The new `windows` job runs the same test targets as the Linux `build` job through build.ps1, with the committed line endings kept on checkout. The CLI and AOT smoke tests stay Linux-only. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/dotnet.yml | 75 ++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 57f3726b..5094f1d6 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -33,6 +33,81 @@ env: NUKE_TELEMETRY_OPTOUT: true jobs: + # The unit test suites again on Windows. Linux CI cannot catch path-separator and other + # platform assumptions, such as AssemblyFinder skipping runtimes/native folders only for '/' + # (jasperfx#1143). This runs the same suites as the Linux `build` job; the CLI and AOT smoke + # tests stay Linux-only. + windows: + runs-on: windows-latest + timeout-minutes: 40 + + steps: + # The Windows runner's git converts to CRLF on checkout. Keep the committed line endings so + # tests that compare generated code with committed fixtures behave as they do on Linux. + - name: Keep committed line endings + run: git config --global core.autocrlf false + + - uses: actions/checkout@v7 + + - name: Install .NET 9.0.x + uses: actions/setup-dotnet@v6 + with: + dotnet-version: 9.0.x + + - name: Install .NET 10.0.x + uses: actions/setup-dotnet@v6 + with: + dotnet-version: 10.0.x + + - name: compile + run: ./build.ps1 compile + shell: pwsh + + - name: test-core + if: ${{ success() || failure() }} + run: ./build.ps1 test-core + shell: pwsh + + - name: test-codegen + if: ${{ success() || failure() }} + run: ./build.ps1 test-codegen + shell: pwsh + + - name: test-codegen-fsharp + if: ${{ success() || failure() }} + run: ./build.ps1 test-codegen-fsharp + shell: pwsh + + - name: test-command-line + if: ${{ success() || failure() }} + run: ./build.ps1 test-command-line + shell: pwsh + + - name: test-events + if: ${{ success() || failure() }} + run: ./build.ps1 test-events + shell: pwsh + + - name: test-event-store + if: ${{ success() || failure() }} + run: ./build.ps1 test-event-store + shell: pwsh + + - name: test-source-generators + if: ${{ success() || failure() }} + run: ./build.ps1 test-source-generators + shell: pwsh + + - name: test-aspire + if: ${{ success() || failure() }} + run: ./build.ps1 test-aspire + shell: pwsh + + - name: test-microsoft-extensions-ai + if: ${{ success() || failure() }} + run: ./build.ps1 test-microsoft-extensions-ai + shell: pwsh + build: runs-on: ubuntu-latest timeout-minutes: 20 From a62ad61bae134c0636a5b7020121a2ce2c58912e Mon Sep 17 00:00:00 2001 From: "Jeremy D. Miller" Date: Sun, 8 Nov 2026 11:11:10 -0600 Subject: [PATCH 2/2] Point the content-root override test at a folder that exists on Windows override_the_content_root used "/bin", which exists on Linux and macOS but resolves to a missing D:\bin\ on the Windows runner, where the host's PhysicalFileProvider throws DirectoryNotFoundException. Use a fresh temp directory instead. This was the only failure in the first Windows CI run. Co-Authored-By: Claude Opus 5.5 --- .../run_command_compliance.cs | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/CommandLineTests/run_command_compliance.cs b/src/CommandLineTests/run_command_compliance.cs index 13b57451..d6b1c5f7 100644 --- a/src/CommandLineTests/run_command_compliance.cs +++ b/src/CommandLineTests/run_command_compliance.cs @@ -156,14 +156,25 @@ public void override_the_environment_name() [Fact] public void override_the_content_root() { - var input = new RunInput + // The host builds a PhysicalFileProvider over the content root, so the folder has to exist. + // "/bin" did on Linux and macOS, but resolves to a missing D:\bin\ on Windows. + var contentRoot = Directory.CreateTempSubdirectory("jasperfx-content-root-").FullName; + + try { - ContentRootFlag = "/bin", - HostBuilder = Host.CreateDefaultBuilder() - }; - - var host = input.BuildHost(); - host.Services.GetRequiredService().ContentRootPath.ShouldBe("/bin"); + var input = new RunInput + { + ContentRootFlag = contentRoot, + HostBuilder = Host.CreateDefaultBuilder() + }; + + using var host = input.BuildHost(); + host.Services.GetRequiredService().ContentRootPath.ShouldBe(contentRoot); + } + finally + { + Directory.Delete(contentRoot, true); + } } [Fact]