mirror of
https://github.com/software-mansion/argent.git
synced 2026-09-14 19:27:14 +08:00
5a3f896652
Resolution trusted the first `command -v ffmpeg` hit unconditionally and only consulted the fallback list when ffmpeg was ABSENT. A conda-forge build (`--disable-gpl`, so no libx264) ahead of Homebrew on PATH therefore won every time, and every recording died with `Unrecognized option 'preset'` — `-preset` being a libx264-private option — while a working build sat in the fallback list, unreachable. Each candidate is now asked whether it can encode, and the first that says yes wins. The probe has to read ffmpeg's OUTPUT: `-h encoder=libx264` exits 0 whether or not the encoder exists, so the obvious implementation — try/catch around execFile — would look like a fix and change nothing. It matches the success header rather than the failure sentence, because the header comes from ffmpeg's help formatter and has been stable for a decade while the failure text is prose any release may reword; keying on the failure string would silently re-break recording, and in the direction that breaks setups which currently work. `-hide_banner` is load-bearing rather than cosmetic: without it the build banner goes to stderr carrying the literal `--enable-libx264`. Everything inconclusive — a timeout, a kill, no output at all — is treated as usable, so the probe can only ever demote a build that positively said it lacks libx264. On any host where recording works today, ffmpeg still gets to speak for itself. Two things the failure path was getting wrong: - "ffmpeg was not found on PATH. Install it" was shown to someone with three ffmpegs installed, which is what sent the reporter looking in the wrong place. That case now has its own message and its own failure code, since the code is rendered to the user verbatim. An EACCES binary counts as found, not missing, for the same reason. - There was no way to override the choice. ARGENT_FFMPEG adds one, and the probe is deliberately ADVISORY for it: the probe's one new failure mode is a false negative on a build whose help output we don't recognise, and an escape hatch subject to the filter it exists to escape would rescue nobody. A pinned binary is never silently swapped for a different one either — it fails loudly instead. `resolveBinary` is deleted rather than extended. Its generic half duplicated `commandOnPath`, worse: the hand-rolled `/bin/sh -c command -v` could never match on Windows, where Android recording is reachable. Going through `commandOnPath` also means the binary we validate is the binary we spawn, instead of resolving PATH twice and proving nothing. Not cached on purpose — the tool-server has no idle shutdown by default, so a cached "no usable ffmpeg" would outlive the user acting on our own error message. One ~33ms probe per recording start, against a path that already waits ~800ms. `resolveFfmpeg` keeps its name and stays reachable from ./watermark so the existing test mock seam still disarms it. Verified end to end on a host in the reported state (conda's ffmpeg first on PATH): recording now produces a valid 87KB h264 mp4 at native resolution where it previously failed instantly. Fixes #621
192 lines
9.0 KiB
YAML
192 lines
9.0 KiB
YAML
name: Windows E2E
|
|
|
|
# Proves Argent runs on Windows. iOS Simulator is macOS-only (Apple), so
|
|
# "Argent on Windows" means the Android + Chromium host control plane.
|
|
#
|
|
# This job, windows-chromium, has the tool-server drive a real headless Chrome
|
|
# over CDP (discover → screenshot → describe → tap → observe the DOM change).
|
|
# Chromium control is pure host-side TypeScript, so a hosted Windows runner (no
|
|
# virtualization) verifies it fully. It also runs the cross-platform resolver
|
|
# unit tests natively on Windows and confirms adb.exe resolution.
|
|
#
|
|
# The simulator-server.exe itself (the binary the Android path spawns) lives in
|
|
# the private radon repo, so it can't be built here without a cross-repo token.
|
|
# Its Windows build + smoke-run is verified in radon CI instead — see the
|
|
# build_argent_windows job in radon's simulator-server-ci workflow (companion
|
|
# PR). WHPX is available on windows-latest (Server 2025), so an Android emulator
|
|
# does boot on a hosted runner — that is where the boot-device stdio fix was
|
|
# verified. The full Android emulator E2E still lives in radon CI alongside that
|
|
# binary rather than here, because this repo can't build simulator-server.exe
|
|
# without a cross-repo token; that path is therefore out of scope for this job.
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
pull_request:
|
|
branches:
|
|
- main
|
|
paths:
|
|
- "packages/tool-server/src/utils/command-on-path.ts"
|
|
- "packages/tool-server/src/utils/android-binary.ts"
|
|
- "packages/tool-server/src/utils/adb.ts"
|
|
- "packages/tool-server/src/utils/check-deps.ts"
|
|
- "packages/tool-server/src/utils/vega-cli.ts"
|
|
- "packages/tool-server/src/utils/chromium-discovery.ts"
|
|
- "packages/tool-server/src/tools/simulator/stop-metro.ts"
|
|
- "packages/tool-server/src/tools/devices/boot-device.ts"
|
|
- "packages/tool-server/src/utils/device-shutdown.ts"
|
|
# The unit tests this job runs — editing one must re-run it here.
|
|
- "packages/tool-server/test/command-on-path.test.ts"
|
|
- "packages/tool-server/test/android-binary-windows.test.ts"
|
|
- "packages/tool-server/test/adb-resolve-avd-path.test.ts"
|
|
- "packages/tool-server/test/check-deps.test.ts"
|
|
- "packages/tool-server/test/http-dep-gate.test.ts"
|
|
- "packages/tool-server/test/stop-metro-netstat.test.ts"
|
|
- "packages/tool-server/test/device-shutdown.test.ts"
|
|
- "packages/native-devtools-ios/src/index.ts"
|
|
- "packages/native-devtools-ios/test/index.test.ts"
|
|
- "packages/argent/scripts/bundle-tools.cjs"
|
|
- "packages/argent/scripts/argent-simulator-server.cjs"
|
|
- "scripts/dev.cjs"
|
|
- "scripts/download-simulator-server.sh"
|
|
- "scripts/ci/windows-chromium-e2e.mjs"
|
|
- "scripts/ci/e2e-chromium-page.html"
|
|
- ".github/workflows/windows-e2e.yml"
|
|
|
|
jobs:
|
|
windows-chromium:
|
|
name: Chromium control plane + resolver unit tests (Windows)
|
|
runs-on: windows-latest
|
|
timeout-minutes: 20
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: "20"
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Fix rollup native bindings (win32)
|
|
# vitest 4 transforms via rollup, whose platform binary is an optional
|
|
# dep npm ci sometimes skips; install the win32 one explicitly.
|
|
run: npm install @rollup/rollup-win32-x64-msvc --no-save
|
|
|
|
- name: Build workspace
|
|
run: npx tsc --build
|
|
|
|
- name: Resolver unit tests on Windows (tool-server)
|
|
# The win32 branches added for Windows support, exercised on a real
|
|
# Windows host (real `where.exe`, real `.exe` access semantics) rather
|
|
# than a mocked platform. The broader suite has POSIX-only fixtures, so
|
|
# this is the curated cross-platform subset.
|
|
working-directory: packages/tool-server
|
|
run: >
|
|
npx vitest run
|
|
test/command-on-path.test.ts
|
|
test/ffmpeg-resolver.test.ts
|
|
test/android-binary-windows.test.ts
|
|
test/adb-resolve-avd-path.test.ts
|
|
test/check-deps.test.ts
|
|
test/http-dep-gate.test.ts
|
|
test/stop-metro-netstat.test.ts
|
|
test/device-shutdown.test.ts
|
|
|
|
- name: Resolver unit tests on Windows (native-devtools-ios)
|
|
working-directory: packages/native-devtools-ios
|
|
run: npx vitest run
|
|
|
|
- name: adb.exe resolves on Windows
|
|
# windows-latest ships the Android SDK with ANDROID_HOME/ANDROID_SDK_ROOT
|
|
# set but does NOT put platform-tools on PATH — exactly the gap the
|
|
# Windows resolver closes (`.exe` suffix + SDK-root fallback). Resolve
|
|
# adb the way the tool-server does, then run the *resolved* path (a bare
|
|
# `adb` wouldn't be found, which is the whole point).
|
|
shell: pwsh
|
|
run: |
|
|
$adb = node -e "require('./packages/tool-server/dist/utils/android-binary.js').resolveAndroidBinary('adb').then(p => process.stdout.write(p || ''))"
|
|
Write-Host "resolved adb -> $adb"
|
|
if ([string]::IsNullOrWhiteSpace($adb) -or -not $adb.ToLower().EndsWith('adb.exe')) {
|
|
Write-Error "expected resolveAndroidBinary('adb') to return an adb.exe path"
|
|
exit 1
|
|
}
|
|
if (-not (Test-Path $adb)) { Write-Error "resolved adb path does not exist: $adb"; exit 1 }
|
|
& $adb version
|
|
|
|
- name: Locate Chrome
|
|
id: chrome
|
|
run: |
|
|
$candidates = @(
|
|
"$env:ProgramFiles\Google\Chrome\Application\chrome.exe",
|
|
"${env:ProgramFiles(x86)}\Google\Chrome\Application\chrome.exe",
|
|
"$env:LOCALAPPDATA\Google\Chrome\Application\chrome.exe"
|
|
)
|
|
$chrome = $candidates | Where-Object { Test-Path $_ } | Select-Object -First 1
|
|
if (-not $chrome) { Write-Error "Google Chrome not found on this runner"; exit 1 }
|
|
Write-Host "Chrome: $chrome"
|
|
"path=$chrome" >> $env:GITHUB_OUTPUT
|
|
|
|
# Launch Chrome + the tool-server AND run the E2E in one step. On Windows
|
|
# runners, `Start-Process` background processes don't reliably survive into
|
|
# a later step (unlike `nohup` on Linux), so both must stay in scope for
|
|
# the duration of the E2E — hence a single step rather than three.
|
|
- name: Launch Chrome + tool-server and run Chromium E2E
|
|
env:
|
|
ARGENT_E2E_URL: http://127.0.0.1:3033
|
|
run: |
|
|
$page = "file:///" + ((Resolve-Path scripts/ci/e2e-chromium-page.html).Path -replace '\\','/')
|
|
$udd = Join-Path $env:RUNNER_TEMP "chrome-e2e-profile"
|
|
$chromeLog = Join-Path $env:RUNNER_TEMP "chrome.log"
|
|
Start-Process -FilePath "${{ steps.chrome.outputs.path }}" -ArgumentList @(
|
|
"--headless=new","--remote-debugging-port=9222","--user-data-dir=$udd",
|
|
"--no-first-run","--no-default-browser-check","--disable-gpu",$page
|
|
) -RedirectStandardOutput $chromeLog -RedirectStandardError "$chromeLog.err" | Out-Null
|
|
$cdpUp = $false
|
|
for ($i = 0; $i -lt 30; $i++) {
|
|
try {
|
|
$r = Invoke-WebRequest -UseBasicParsing "http://127.0.0.1:9222/json/version" -TimeoutSec 2
|
|
if ($r.StatusCode -eq 200) { Write-Host "CDP up at t+${i}s"; $cdpUp = $true; break }
|
|
} catch {}
|
|
Start-Sleep -Seconds 1
|
|
}
|
|
if (-not $cdpUp) { Get-Content "$chromeLog.err" -ErrorAction SilentlyContinue; Write-Error "Chrome CDP never came up on :9222"; exit 1 }
|
|
|
|
$env:ARGENT_PORT = "3033"
|
|
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.argent" | Out-Null
|
|
$tsLog = Join-Path $env:RUNNER_TEMP "tool-server.log"
|
|
Start-Process -FilePath "node" -ArgumentList @("packages/tool-server/dist/index.js","start") `
|
|
-RedirectStandardOutput $tsLog -RedirectStandardError "$tsLog.err" | Out-Null
|
|
$tsUp = $false
|
|
for ($i = 0; $i -lt 40; $i++) {
|
|
try {
|
|
$r = Invoke-WebRequest -UseBasicParsing "http://127.0.0.1:3033/tools" -TimeoutSec 2
|
|
if ($r.StatusCode -eq 200) { Write-Host "tool-server up at t+${i}s"; $tsUp = $true; break }
|
|
} catch {}
|
|
Start-Sleep -Seconds 1
|
|
}
|
|
if (-not $tsUp) {
|
|
Write-Host "--- tool-server.log ---"; Get-Content $tsLog -ErrorAction SilentlyContinue
|
|
Write-Host "--- tool-server.err ---"; Get-Content "$tsLog.err" -ErrorAction SilentlyContinue
|
|
Write-Error "tool-server never came up on :3033"; exit 1
|
|
}
|
|
|
|
$env:ARGENT_E2E_OUT = Join-Path $env:RUNNER_TEMP "e2e"
|
|
node scripts/ci/windows-chromium-e2e.mjs
|
|
|
|
- name: Upload artifacts
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: windows-chromium-e2e
|
|
path: |
|
|
${{ runner.temp }}/e2e/*.png
|
|
${{ runner.temp }}/tool-server.log
|
|
${{ runner.temp }}/tool-server.log.err
|
|
${{ runner.temp }}/chrome.log
|
|
${{ runner.temp }}/chrome.log.err
|
|
if-no-files-found: warn
|
|
retention-days: 7
|