name: E2E (packaged app, Windows) # Fast-feedback packaged-app gate, Windows-only. Split into parallel jobs so the # push wall-clock stays well under ~10 min: # gate - cheap pure-node selftests (no build): mutation gate + preflight # Layers 1-5. Fails the "tests that test the tests" fast. # verify - build the UNPACKED app (electron-builder --dir, which skips the # slow ~2min NSIS LZMA compression) and run the deterministic # verify-all gate against win-unpacked\OpenSwarm.exe. # playwright - build the unpacked app and run the renderer-level Playwright e2e. # installer - full NSIS build + destructive install->verify->uninstall. The # heaviest leg, so it runs only on PR-to-main / dispatch (NOT on # routine pushes); release-windows.yml covers it on v* tags. # verify + playwright run concurrently; both reuse cached heavy build inputs # (bundled Python env, uv, MCP bundles, npm) so warm builds are fast - the build # script skips any input already on disk. # # macOS legs were removed (runner starvation + untriageable mac-only failures); # re-add when a Mac maintainer can own them. Real Win10 coverage still needs the # SELF-HOSTED e2e-win10 job (repo var WIN10_SELF_HOSTED=true + a # [self-hosted, windows, win10] runner). on: push: branches: [eric/lock] paths: &build-paths - 'electron/**' - 'frontend/**' - 'backend/**' - 'e2e/**' - 'scripts/build-app**' - 'scripts/build-python-env**' - 'scripts/fetch-router**' - 'scripts/ci/**' - '.github/workflows/e2e.yml' pull_request: branches: [main] paths: *build-paths workflow_dispatch: permissions: contents: read env: CSC_IDENTITY_AUTO_DISCOVERY: 'false' GOOGLE_OAUTH_CLIENT_ID: 'e2e-placeholder.apps.googleusercontent.com' GOOGLE_OAUTH_CLIENT_SECRET: 'e2e-placeholder-secret' jobs: # Pure-node, no build: cheap enough to always run and fail fast. gate: runs-on: windows-latest timeout-minutes: 15 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20.18.1' - name: Gate selftest (mutation) shell: bash run: node scripts/ci/selftest-gate.js - name: Preflight selftest (Layers 1+2) shell: bash run: node scripts/ci/selftest-preflight.js - name: Preflight failure rigs (Layer 3) shell: bash run: node scripts/ci/verify-preflight-rigs.js - name: Preflight race / cache (Layer 4) shell: bash run: node scripts/ci/verify-preflight-race.js - name: Pairwise generator selftest (covering-array math) shell: bash run: node scripts/ci/selftest-pairwise.js - name: Preflight matrix (normal + hostile-env scenarios) shell: bash run: | node scripts/ci/verify-preflight.js OPENSWARM_TEST_NETWORK=blocked node scripts/ci/verify-preflight.js OPENSWARM_TEST_APPDATA=readonly node scripts/ci/verify-preflight.js OPENSWARM_TEST_LANG=de-DE node scripts/ci/verify-preflight.js # Build the unpacked app + run the deterministic gate. verify: runs-on: windows-latest timeout-minutes: 30 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20.18.1' cache: npm cache-dependency-path: | electron/package-lock.json frontend/package-lock.json - uses: actions/setup-python@v5 with: python-version: '3.13' - name: Cache bundled Python env uses: actions/cache@v4 with: path: electron/python-env key: pyenv-win-${{ hashFiles('scripts/build-python-env-win.ps1', 'backend/requirements.txt') }} - name: Cache uv binaries uses: actions/cache@v4 with: path: backend/uv-bin key: uvbin-win-${{ hashFiles('scripts/build-app-win.ps1') }} - name: Cache MCP bundles uses: actions/cache@v4 with: path: backend/mcp-bundles key: mcpbundles-win-${{ hashFiles('scripts/build-app-win.ps1') }} - name: Build packaged app (unpacked, no installer) shell: pwsh run: pwsh -NoProfile -File scripts/build-app-win.ps1 -DirOnly - name: Deterministic gate (verify-all) shell: bash run: node scripts/ci/verify-all.js # Build the unpacked app + run the Playwright renderer suite, concurrently with verify. playwright: runs-on: windows-latest timeout-minutes: 30 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20.18.1' cache: npm cache-dependency-path: | electron/package-lock.json frontend/package-lock.json e2e/package-lock.json - uses: actions/setup-python@v5 with: python-version: '3.13' - name: Cache bundled Python env uses: actions/cache@v4 with: path: electron/python-env key: pyenv-win-${{ hashFiles('scripts/build-python-env-win.ps1', 'backend/requirements.txt') }} - name: Cache uv binaries uses: actions/cache@v4 with: path: backend/uv-bin key: uvbin-win-${{ hashFiles('scripts/build-app-win.ps1') }} - name: Cache MCP bundles uses: actions/cache@v4 with: path: backend/mcp-bundles key: mcpbundles-win-${{ hashFiles('scripts/build-app-win.ps1') }} - name: Build packaged app (unpacked, no installer) shell: pwsh run: pwsh -NoProfile -File scripts/build-app-win.ps1 -DirOnly - name: Install e2e deps shell: bash working-directory: e2e env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' run: npm ci - name: GUI hand selftest (MCP) shell: bash working-directory: e2e run: node mcp/selftest.js - name: Run E2E (Playwright) shell: bash working-directory: e2e run: npm test - name: Upload E2E results if: always() uses: actions/upload-artifact@v4 with: name: e2e-results path: e2e/results.json if-no-files-found: ignore retention-days: 14 # Per-test traces: playwright-trace.zip, events.jsonl, mousepath.jsonl, # backend.log.tail - always uploaded so a failed run is debuggable. - name: Upload E2E visibility traces if: always() uses: actions/upload-artifact@v4 with: name: e2e-traces path: e2e/traces/ if-no-files-found: ignore retention-days: 14 # Heaviest leg: full NSIS installer + destructive install->verify->uninstall on # a clean runner. Skip on routine pushes; run on PRs into main + manual dispatch. installer: if: github.event_name != 'push' runs-on: windows-latest timeout-minutes: 45 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20.18.1' cache: npm cache-dependency-path: | electron/package-lock.json frontend/package-lock.json - uses: actions/setup-python@v5 with: python-version: '3.13' - name: Cache bundled Python env uses: actions/cache@v4 with: path: electron/python-env key: pyenv-win-${{ hashFiles('scripts/build-python-env-win.ps1', 'backend/requirements.txt') }} - name: Cache uv binaries uses: actions/cache@v4 with: path: backend/uv-bin key: uvbin-win-${{ hashFiles('scripts/build-app-win.ps1') }} - name: Cache MCP bundles uses: actions/cache@v4 with: path: backend/mcp-bundles key: mcpbundles-win-${{ hashFiles('scripts/build-app-win.ps1') }} - name: Build packaged app (full NSIS installer) shell: pwsh run: pwsh -NoProfile -File scripts/build-app-win.ps1 - name: Installer cycle (clean runner) shell: pwsh run: node scripts/ci/verify-installer.js --destructive # Real Windows 10 coverage. Skipped unless a self-hosted Win10 runner exists # and WIN10_SELF_HOSTED=true (repo variable). Mirrors the windows steps above. e2e-win10: if: ${{ vars.WIN10_SELF_HOSTED == 'true' }} runs-on: [self-hosted, windows, win10] timeout-minutes: 90 env: CSC_IDENTITY_AUTO_DISCOVERY: 'false' GOOGLE_OAUTH_CLIENT_ID: 'e2e-placeholder.apps.googleusercontent.com' GOOGLE_OAUTH_CLIENT_SECRET: 'e2e-placeholder-secret' steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20.18.1' - uses: actions/setup-python@v5 with: python-version: '3.13' - name: Gate selftest (mutation) shell: bash run: node scripts/ci/selftest-gate.js - name: Preflight selftest + rigs + race + matrix (Layers 1-5) shell: bash run: | node scripts/ci/selftest-preflight.js node scripts/ci/verify-preflight-rigs.js node scripts/ci/verify-preflight-race.js node scripts/ci/verify-preflight.js OPENSWARM_TEST_NETWORK=blocked node scripts/ci/verify-preflight.js OPENSWARM_TEST_APPDATA=readonly node scripts/ci/verify-preflight.js - name: Build packaged app (Windows) shell: pwsh run: pwsh -NoProfile -File scripts/build-app-win.ps1 - name: Deterministic gate (verify-all) shell: bash run: node scripts/ci/verify-all.js - name: Install e2e deps shell: bash working-directory: e2e env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' run: npm ci - name: GUI hand selftest (MCP) shell: bash working-directory: e2e run: node mcp/selftest.js - name: Run E2E (Playwright) shell: bash working-directory: e2e run: npm test - name: Installer cycle (clean runner) shell: pwsh run: node scripts/ci/verify-installer.js --destructive