Build, test and package on Windows, Linux and macOS in CI - #3
Conversation
Nothing built the solution outside a developer machine, and nothing produced a runnable artifact. One workflow now does both on each OS's native runner: a zip for win-x64 and linux-x64, an unsigned, unnotarized dmg for osx-arm64. The publish is framework-dependent on purpose. The app needs an installed .NET SDK at runtime regardless - Roslyn's MSBuild workspace, MSBuildLocator, dotnet build and test - so a bundled runtime would only grow the artifact. The .app is assembled by an MSBuild target rather than in the workflow, so a plain dotnet publish -r osx-arm64 reproduces what CI ships. deb/rpm, a Homebrew cask, signing and versioned artifact names, which ILSpy's pipeline carries, are left out until there is a release process to need them. Assisted-by: Claude:claude-fable-5:Claude Code
Three things the suite assumed about its host turned out to be Linux-only. git writes loose objects read-only, and on Windows Directory.Delete refuses a read-only file, so every fixture's TearDown threw past the IOException it caught. One helper clears the flag first and treats cleanup as best effort; a leaked temp directory is not a verdict on what the test asserted. git prints worktree paths in its own form - forward slashes on Windows, the symlink-resolved /private/var on macOS - and the service passes that form on unchanged. The three assertions that compared it with the path the test built now ask git how it spells that path instead of assuming it matches. A raw string literal carries the line endings of the checkout, which with autocrlf is CRLF on Windows; the diff builder speaks LF. The literals are normalised once instead of the repository dictating line endings for everyone. Assisted-by: Claude:claude-fable-5:Claude Code
What the first CI run revealed, and how it was fixed (96548e4)The workflow's first run was green on Linux and red on Windows (37 failures) and macOS (3 failures). None of it was caused by the workflow; the suite had only ever run on Linux and carried three host assumptions. Fixed in the tests, not the product. 1. Windows: TearDown threw on git's read-only objects (33 tests)git writes loose objects read-only, and on Windows Fix: 2. Windows + macOS: worktree paths in git's spelling (3 tests)
Fix: the tests ask git how it spells the directory ( 3. Windows: a CRLF raw string literal (1 test)
Fix: the two literals are Not fixed on purpose
Second run: all three legs green; artifacts checked (exec bit preserved in the Linux zip, dmg mounts with |
Why
Nothing built the solution outside a developer machine, and nothing produced a runnable artifact. One workflow now builds
Stampeded.slnx, runs the tests and publishes a Release build on each OS's native runner: a zip for win-x64 and linux-x64, an unsigned, unnotarized dmg for osx-arm64.What
.github/workflows/build.yml: matrix overwindows-latest/ubuntu-latest/macos-latest(arm64). Build, test, framework-dependent RID-specific publish, then package. Info-ZIP on Linux so the execute bit survives;hdiutilfor the dmg.src/Stampeded/Stampeded.csproj:BuildMacAppBundletarget assemblesStampeded.appon anyosx-*publish, sodotnet publish -r osx-arm64reproduces what CI ships.src/Stampeded/Assets/macos/Info.plist: minimal bundle manifest (no icon - there is no.icnsyet).Framework-dependent on purpose: the app needs an installed .NET SDK at runtime anyway (Roslyn MSBuild workspace, MSBuildLocator,
dotnet build/test).Modeled on icsharpcode/ILSpy#3768, minus deb/rpm, Homebrew, signing and pwsh packaging scripts, which wait for a release process.
Verified locally
dotnet publish -r osx-arm64(cross-published from Windows) writespublish/osx-arm64/Stampeded.app/Contents/{Info.plist,MacOS/Stampeded}with all 116 publish files and is idempotent;-r win-x64yieldsStampeded.exe. CI on this PR is the first run of the workflow itself.🤖 Generated with Claude Code
https://claude.ai/code/session_011EuGx5KH6zfiZQYHTcygyh