-
Notifications
You must be signed in to change notification settings - Fork 107
144 lines (133 loc) · 6.72 KB
/
Copy pathon-pr-sdk-python-e2e-full.yml
File metadata and controls
144 lines (133 loc) · 6.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# QVAC sdk-python full cross-platform e2e - PR (test-e2e-full-gated)
#
# The broader real-worker leg: runs the FULL pytest suite (including the `heavy`
# parakeet/BCI streaming tests) on the self-hosted GPU runners for all three
# desktop platforms, proving the Python client cross-platform. Models are cached
# (keyed on the shared model registry) so repeat runs skip the cold download.
#
# The fast per-PR leg is on-pr-sdk-python-e2e.yml (hosted, `test-e2e-smoke` label,
# minimal models, -m "not heavy"). This heavier leg is gated on `test-e2e-full`.
#
# Plain `pull_request` (not pull_request_target): the worker build uses only the
# public-npm `@qvac/*` packages and pytest (no `@tetherto` GPR harness / MQTT
# secrets), so this needs no secrets. The `test-e2e-full` label is the
# maintainer approval that gates running PR code on the self-hosted runners.
name: QVAC Tests (sdk-python) full - PR
on:
pull_request:
# Only `labeled` (fresh approval, pinned to the head SHA at approval time) —
# NOT `synchronize`. A later fork push must be re-approved rather than riding
# a stale `test-e2e-full` label onto a new, unreviewed SHA on the GPU runners.
types: [labeled]
paths:
- "packages/sdk-python/**"
- "packages/sdk/**"
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
test:
name: full e2e (${{ matrix.os }})
# SHA-bound approval: only a FRESH `test-e2e-full` application (labeled event,
# tied to the head SHA at approval time) or a manual dispatch runs the
# self-hosted GPU suite. A later fork push must be re-approved — a stale label
# must not authorise a new, unreviewed SHA. See
# .cursor/rules/devops/github-actions.mdc "CI trust policy for fork PRs".
if: >-
github.event_name == 'workflow_dispatch' ||
(github.event.action == 'labeled' && github.event.label.name == 'test-e2e-full')
strategy:
fail-fast: false
matrix:
os: ["qvac-win25-x64-gpu", "qvac-ubuntu2204-x64-gpu", "qvac-macos26-arm64-gpu"]
runs-on: ${{ matrix.os }}
timeout-minutes: 45
defaults:
run:
shell: bash
working-directory: packages/sdk-python
env:
# Point the worker's model storage (SDK `cacheDirectory` config, applied
# via BareRpcTransport's __init_config) at a cacheable, absolute, per-OS
# path. Same idea as the SDK e2e's cacheDirectory.
QVAC_CACHE_DIR: ${{ github.workspace }}/.qvac-cache
steps:
# Self-hosted runners persist the workspace between runs; wipe it.
- name: Manual Workspace Cleanup
if: runner.environment != 'github-hosted'
working-directory: .
run: rm -rf "$GITHUB_WORKSPACE" && mkdir -p "$GITHUB_WORKSPACE"
# Pin to the exact approved head SHA (not the mutable PR merge ref) so the
# GPU suite runs the commit `test-e2e-full` was applied to — closing the
# label-at-A / push-B TOCTOU window. Empty on workflow_dispatch → default ref.
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
with:
ref: ${{ github.event.pull_request.head.sha }}
persist-credentials: false
# Use the runner's own Python. actions/setup-python doesn't work on these
# self-hosted GPU runners: its python-versions tarball ships a setup.sh
# that hardcodes `mkdir /Users/runner/hostedtoolcache`, which isn't
# writable here (the runner user's home is /Users/actions-runner-*). The
# runners already have Python; make a venv from it so installs don't touch
# the system interpreter. Fails loudly if the system Python is < 3.10.
# Per infra, don't run actions/setup-python on these runners: Python is
# already provisioned, and setup-python hard-fails anyway (its
# python-versions tarball hardcodes an unwritable /Users/runner toolcache
# path). Use the present Python via a venv (keeps installs out of the
# system interpreter). Fails loudly if the system Python is < 3.10.
- name: Set up Python (runner's system Python)
run: |
set -e
if command -v python3 >/dev/null 2>&1; then PY=python3; else PY=python; fi
echo "System Python: $("$PY" --version) at $(command -v "$PY")"
"$PY" -c 'import sys; assert sys.version_info[:2] >= (3, 10), "need Python >=3.10, got " + sys.version'
"$PY" -m venv .venv
if [ -x ".venv/bin/python" ]; then PYBIN="$(pwd)/.venv/bin/python"; else PYBIN="$(pwd)/.venv/Scripts/python"; fi
echo "PYBIN=$PYBIN" >> "$GITHUB_ENV"
"$PYBIN" -m pip install --upgrade pip
# node/bun are needed to build the worker. Unlike setup-python these
# actions work on the runners (they find the pre-cached tool, no download),
# and bun in particular is not otherwise on PATH. Same actions the SDK's
# own desktop e2e (test-node-sdk.yml) uses on these runners.
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # 6.3.0
with:
node-version: 22
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # 2.2.0
with:
bun-version: latest
# Shared model cache, keyed on the same registry the SDK e2e keys on, so
# it invalidates in lockstep. Cross-OS so the three platforms share it.
- name: Restore models cache
id: models-cache
uses: actions/cache/restore@v4
with:
path: ${{ github.workspace }}/.qvac-cache
key: qvac-py-models-${{ hashFiles('packages/sdk/models/registry/models.ts') }}
# Fall back to the SDK e2e's own cache for the same registry, so the
# first Python run reuses already-downloaded models instead of
# re-fetching them.
restore-keys: |
qvac-models-${{ hashFiles('packages/sdk/models/registry/models.ts') }}
enableCrossOsArchive: true
- name: Install (with transport + optional extras)
run: |
"$PYBIN" -m pip install -e ".[gen,dev,vla,notebook]"
- name: Build worker
run: |
"$PYBIN" scripts/build_worker.py
- name: Test (full suite, real worker)
run: |
"$PYBIN" -m pytest tests/ -v
# Save even on test failure so the (multi-GB) models downloaded this run
# are cached and the next run doesn't re-fetch them. Skipped only when the
# cache already hit.
- name: Save models cache
if: always() && steps.models-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: ${{ github.workspace }}/.qvac-cache
key: qvac-py-models-${{ hashFiles('packages/sdk/models/registry/models.ts') }}
enableCrossOsArchive: true