Files
hermes-agent/.github/workflows/windows-install-update-e2e.yml

100 lines
4.3 KiB
YAML

name: Windows install + update E2E
# PR-time native Windows install/update journey (tests/e2e/core/windows_update):
# the real scripts/install.ps1 on a fresh fake user profile (git redirected to a local
# bare clone, no git/python/uv on PATH), then the real `hermes update` HEAD -> NEXT,
# a running gateway across that update, and a turn against the loopback provider.
# Each file walks one journey (one install) and asserts several user-visible cells;
# tracked bugs are message-gated xfails (tests/e2e/core/_pending_fixes.py).
#
# Called from tests-os.yml on every Python PR. Pushes to wine2e-install/** run it alone,
# for sabotage proofs and iteration without the rest of CI.
on:
workflow_call:
push:
branches: ['wine2e-install/**']
permissions:
contents: read
concurrency:
group: windows-install-update-e2e-${{ github.event_name }}-${{ github.ref }}
cancel-in-progress: true
jobs:
install-update:
name: Windows install.ps1 + hermes update E2E
runs-on: windows-latest-32-core
# A typical run is ~17 min; one slow runner took 28 min for the same work (run 36295230146).
timeout-minutes: 50
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
# serve.git is a bare clone of this checkout: the installer's treeless clone and
# `hermes update` need real history and release tags (version identity), as on GitHub.
fetch-depth: 0
- name: Set up locked Python and test dependencies
uses: ./.github/actions/setup-pm
with:
packages: git,ripgrep
extras: '["all", "telegram", "anthropic", "mistral", "fal", "modal", "daytona", "parallel-web"]'
test-environment: 'true'
prune-python-cache: true
- name: Run Windows install + update E2E
shell: bash
run: |
scripts/run_tests.sh tests/e2e/core/windows_update/ -- \
-m "platforms and integration" -v --tb=short -rA
env:
HERMES_E2E_WINDOWS_INSTALL: '1'
# Machine work dirs (serve.git, transcripts) stay short under runner.temp. The fake
# user profiles live in C:\Users itself, where a real one does: the checkout carries
# 159-character paths, so a deeper profile hits MAX_PATH where no user would (the
# runner is disposable, so writing C:\Users is fine).
HERMES_E2E_MACHINE_ROOT: ${{ runner.temp }}\wm
HERMES_E2E_PROFILES_ROOT: C:\Users
HERMES_E2E_ARTIFACTS: ${{ runner.temp }}\win-update-e2e
# One journey per file, all in parallel (each is mostly network + subprocess wait).
HERMES_TEST_WORKERS: '6'
HERMES_TEST_FILE_TIMEOUT: '2400'
HERMES_TEST_FILE_RETRIES: '0'
OPENROUTER_API_KEY: ''
OPENAI_API_KEY: ''
NOUS_API_KEY: ''
- name: Upload transcripts, logs and receipts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: windows-install-update-e2e-${{ github.run_attempt }}
path: ${{ runner.temp }}/win-update-e2e
if-no-files-found: ignore
retention-days: 14
- name: No leftover Python / Hermes processes
# Backstop for each journey's teardown: nothing a machine started may outlive it.
if: always()
shell: pwsh
run: |
$names = 'python.exe', 'pythonw.exe', 'hermes.exe', 'node.exe'
# Work dirs live under runner.temp\wm; profiles are C:\Users\*hermes-e2e-<id>.
$root = "${{ runner.temp }}\wm".ToLower()
$profileMark = 'hermes-e2e-'
$deadline = (Get-Date).AddSeconds(20)
do {
$left = @(Get-CimInstance Win32_Process | Where-Object {
$blob = "$($_.CommandLine) $($_.ExecutablePath)".ToLower()
($names -contains $_.Name.ToLower()) -and ($blob.Contains($root) -or $blob.Contains($profileMark))
})
if ($left.Count -eq 0) { 'no leftover processes from the E2E machines'; exit 0 }
Start-Sleep -Milliseconds 500
} while ((Get-Date) -lt $deadline)
foreach ($p in $left) {
"::error::leftover pid=$($p.ProcessId) ppid=$($p.ParentProcessId): $($p.CommandLine)"
}
exit 1