name: Headless portability on: pull_request: paths: - ".github/workflows/headless-portability.yml" - "AcDream.slnx" - "src/AcDream.Core/**" - "src/AcDream.Core.Net/**" - "src/AcDream.Content/**" - "src/AcDream.Plugin.Abstractions/**" - "src/AcDream.Runtime/**" - "src/AcDream.Headless/**" - "src/AcDream.App/**" - "src/AcDream.UI.Abstractions/**" - "src/AcDream.UI.ImGui/**" - "tests/AcDream.Core.Tests/**" - "tests/AcDream.Core.Net.Tests/**" - "tests/AcDream.Content.Tests/**" - "tests/AcDream.Runtime.Tests/**" - "tests/AcDream.Headless.Tests/**" - "tests/AcDream.App.Tests/**" - "tests/AcDream.UI.Abstractions.Tests/**" push: paths: - ".github/workflows/headless-portability.yml" - "AcDream.slnx" - "src/AcDream.Core/**" - "src/AcDream.Core.Net/**" - "src/AcDream.Content/**" - "src/AcDream.Plugin.Abstractions/**" - "src/AcDream.Runtime/**" - "src/AcDream.Headless/**" - "src/AcDream.App/**" - "src/AcDream.UI.Abstractions/**" - "src/AcDream.UI.ImGui/**" - "tests/AcDream.Core.Tests/**" - "tests/AcDream.Core.Net.Tests/**" - "tests/AcDream.Content.Tests/**" - "tests/AcDream.Runtime.Tests/**" - "tests/AcDream.Headless.Tests/**" - "tests/AcDream.App.Tests/**" - "tests/AcDream.UI.Abstractions.Tests/**" workflow_dispatch: permissions: contents: read jobs: portable-headless: strategy: fail-fast: false matrix: os: [windows-latest, ubuntu-latest] runs-on: ${{ matrix.os }} steps: - name: Checkout uses: actions/checkout@v6 - name: Install .NET 10 uses: actions/setup-dotnet@v4 with: dotnet-version: "10.0.x" - name: Install Linux graphical smoke dependencies shell: bash run: | sudo apt-get update sudo apt-get install -y --no-install-recommends \ libgl1-mesa-dri \ mesa-utils \ xauth \ xvfb - name: Build presentation-free closure shell: pwsh run: | $projects = @( "src/AcDream.Plugin.Abstractions/AcDream.Plugin.Abstractions.csproj", "src/AcDream.Core/AcDream.Core.csproj", "src/AcDream.Core.Net/AcDream.Core.Net.csproj", "src/AcDream.Content/AcDream.Content.csproj", "src/AcDream.Runtime/AcDream.Runtime.csproj", "src/AcDream.Headless/AcDream.Headless.csproj" ) foreach ($project in $projects) { dotnet build $project -c Release if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } } # AcDream.Core.Tests still contains historical App integration fixtures, # so it is deliberately not a member of this no-App restore lane. Core is # built directly above and exercised through every portable downstream # test project below; the complete solution lane retains Core.Tests. - name: Test presentation-free closure shell: pwsh run: | $projects = @( "tests/AcDream.Core.Net.Tests/AcDream.Core.Net.Tests.csproj", "tests/AcDream.Content.Tests/AcDream.Content.Tests.csproj", "tests/AcDream.Runtime.Tests/AcDream.Runtime.Tests.csproj", "tests/AcDream.Headless.Tests/AcDream.Headless.Tests.csproj" ) foreach ($project in $projects) { dotnet test $project -c Release if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } } - name: Verify CLI without connecting shell: pwsh run: | dotnet run --project src/AcDream.Headless/AcDream.Headless.csproj -c Release -- --help if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } Set-Content -LiteralPath headless-k0.json -Value '{"version":1,"sessions":[]}' dotnet run --project src/AcDream.Headless/AcDream.Headless.csproj -c Release -- validate --config headless-k0.json if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } linux-graphical: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v6 - name: Install .NET 10 uses: actions/setup-dotnet@v4 with: dotnet-version: "10.0.x" - name: Build and publish Linux graphical client shell: pwsh run: | dotnet build src/AcDream.App/AcDream.App.csproj -c Release -r linux-x64 if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } dotnet publish src/AcDream.App/AcDream.App.csproj ` -c Release ` -r linux-x64 ` --self-contained false ` -o artifacts/acdream-linux-x64 if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - name: Test portable graphical boundary shell: pwsh run: | dotnet test ` tests/AcDream.UI.Abstractions.Tests/AcDream.UI.Abstractions.Tests.csproj ` -c Release if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } dotnet test ` tests/AcDream.App.Tests/AcDream.App.Tests.csproj ` -c Release ` --filter "FullyQualifiedName~LinuxMonotonicFramePacingWaiterTests|FullyQualifiedName~LinuxPlatformBoundaryTests|FullyQualifiedName~GraphicalHostPlatformServicesTests|FullyQualifiedName~GraphicalLegacyConfigurationMigratorTests|FullyQualifiedName~GraphicalWindowBackendSelectionTests|FullyQualifiedName~GraphicalCapabilityRequirementsTests|FullyQualifiedName~StudioWindowTests" if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - name: Verify Linux package contract shell: bash run: | set -euo pipefail root=artifacts/acdream-linux-x64 test -x "$root/AcDream.App" test -f "$root/AcDream.App.dll" test -f "$root/libglfw.so.3" test -f "$root/libopenal.so" test -f "$root/libcimgui.so" test -f "$root/Rendering/Shaders/mesh_modern.vert" test -f "$root/plugins/AcDream.Plugins.Smoke/AcDream.Plugins.Smoke.dll" test -f "$root/plugins/AcDream.Plugins.Smoke/plugin.json" test "$(grep -RIl --include='*.cs' 'LibraryImport(\"kernel32.dll\"' \ src/AcDream.App | wc -l)" -eq 1 grep -q 'WindowsHighResolutionFramePacingWaiter.cs' < <( grep -RIl --include='*.cs' 'LibraryImport(\"kernel32.dll\"' \ src/AcDream.App) ! grep -RIn --include='*.cs' 'LocalApplicationData' \ src/AcDream.App src/AcDream.UI.Abstractions ! grep -RIn --include='*.cs' \ 'WindowsHighResolutionFramePacingWaiter.Create()' \ src/AcDream.App \ --exclude='FramePacingWaiterFactory.cs' \ --exclude='WindowsHighResolutionFramePacingWaiter.cs' - name: Verify actionable unsupported-driver gate shell: bash run: | set -euo pipefail root=artifacts/acdream-linux-x64 report=artifacts/linux-x11-capabilities.json set +e ACDREAM_DISPLAY_PROTOCOL=x11 \ xvfb-run -a "$root/AcDream.App" \ ui-studio /tmp/not-needed \ --mockup \ --capability-report "$report" code=$? set -e test "$code" -eq 4 test "$(jq -r '.ActiveDisplayProtocol' "$report")" = X11 test "$(jq -r '.Lifecycle.ShutdownComplete' "$report")" = true test "$(jq -r '.Lifecycle.OwnedWindowCount' "$report")" -eq 0 test "$(jq -r '.Lifecycle.OwnedGlApiCount' "$report")" -eq 0 test "$(jq -r '.Lifecycle.OwnedInputContextCount' "$report")" -eq 0 jq -e '.SupportFailures | length > 0' "$report"