Skip to content

Commit a4c2ade

Browse files
committed
perf(e2e): hoist Linux full-suite build into a single job, fan-out tests
Replace per-shard build+test with a build-once-then-fanout structure for the Linux full-suite path: build-linux-full (one job, ~10-15 min cold / ~2 min warm) │ └─> e2e-linux-full (4 matrix shards, each ~15-20 min) Why: - Eliminates the parallel-shard cache race: with per-shard builds, 4 shards all hit the binary/CEF caches simultaneously at first run. Only the first to write actually populates them; the others lose the race and rebuild from cargo cache. Now the cache lives in exactly one job. - Guarantees the binary and its libcef.so ship together as a single workflow artifact, so the prior class of bugs ('binary cache hit but CEF cache miss → libcef.so not found at launch') is structurally impossible. - Cuts compute time: 1 build instead of 4 parallel builds. Wall clock on the longest path is the same, but minutes consumed drops by ~3x. Mechanics: - build job tars OpenHuman + app/dist + ~/Library/Caches/tauri-cef into a single zstd-compressed artifact (~retention 1 day). - Test shards download + extract back into the workspace and $HOME before invoking e2e-run-all-flows.sh --suite=<csv>. - Test shards no longer need Rust toolchain / CEF cache / binary cache steps — JS deps + Appium are all they install. macOS / Windows full jobs are unchanged for now (user is focused on Linux); same hoist can be applied later.
1 parent fc3683c commit a4c2ade

1 file changed

Lines changed: 97 additions & 54 deletions

File tree

.github/workflows/e2e-reusable.yml

Lines changed: 97 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -174,27 +174,20 @@ jobs:
174174
echo "No summary file found." >> $GITHUB_STEP_SUMMARY
175175
fi
176176
177-
# Full-suite Linux runs are sharded across 4 parallel jobs by suite group.
178-
# `e2e-run-all-flows.sh --suite=<csv>` accepts a comma-separated list, so
179-
# each shard runs roughly a quarter of the ~80 specs. With Swatinem
180-
# rust-cache + the CEF cache restored on every job, the per-shard build
181-
# step is fast (~1-3 min). Longest shard dominates wall clock — expect
182-
# ~20-25 min vs the ~60-min serial baseline.
183-
e2e-linux-full:
177+
# Full-suite Linux is now build-once-then-fanout: one `build-linux-full`
178+
# job produces the binary + frontend dist + CEF runtime as a single
179+
# workflow artifact, and the 4 shard test jobs `needs:` that build and
180+
# download the artifact. This eliminates the parallel-shard cache race
181+
# (only the first shard would otherwise populate the binary/CEF caches,
182+
# the others would lose the race and rebuild) and guarantees the binary
183+
# and its libcef.so are always packaged together.
184+
build-linux-full:
184185
if: inputs.run_linux && inputs.full
185-
name: E2E (Linux full / ${{ matrix.shard.name }})
186+
name: Build (Linux full)
186187
runs-on: ubuntu-22.04
187188
container:
188189
image: ghcr.io/tinyhumansai/openhuman_ci:latest
189-
timeout-minutes: 60
190-
strategy:
191-
fail-fast: false
192-
matrix:
193-
shard:
194-
- { name: foundation, suites: "auth,navigation,system" }
195-
- { name: chat, suites: "chat,skills,journeys" }
196-
- { name: integrations, suites: "providers,webhooks,notifications" }
197-
- { name: commerce, suites: "payments,settings" }
190+
timeout-minutes: 45
198191
steps:
199192
- name: Checkout code
200193
uses: actions/checkout@v5
@@ -218,25 +211,86 @@ jobs:
218211
. -> target
219212
app/src-tauri -> target
220213
cache-on-failure: true
221-
# Shared key across shards so the first shard to populate the cache
222-
# warms it for the others within the same run.
223214
key: e2e-linux-unified
224215

225216
- name: Cache CEF binary distribution
226-
id: cef-cache
227217
uses: actions/cache@v5
228218
with:
229-
# e2e-build.sh + ensure-tauri-cli.sh always export
230-
# CEF_PATH=$HOME/Library/Caches/tauri-cef regardless of OS, so the
231-
# cef-dll-sys download lands there on Linux/Windows too. Cache the
232-
# actual download location so the cache hits when the binary-cache
233-
# short-circuit skips the build step.
219+
# cef-dll-sys downloads into $CEF_PATH; ensure-tauri-cli.sh +
220+
# e2e-build.sh pin that to $HOME/Library/Caches/tauri-cef on
221+
# every OS, so the cache key/path live there too.
234222
path: |
235223
~/Library/Caches/tauri-cef
236224
key: cef-x86_64-unknown-linux-gnu-v2-${{ hashFiles('app/src-tauri/Cargo.toml') }}
237225
restore-keys: |
238226
cef-x86_64-unknown-linux-gnu-v2-
239227
228+
- name: Install JS dependencies
229+
run: pnpm install --frozen-lockfile
230+
231+
- name: Ensure .env exists for E2E build
232+
run: |
233+
touch .env
234+
touch app/.env
235+
236+
- name: Build E2E app
237+
run: pnpm --filter openhuman-app test:e2e:build
238+
239+
- name: Package build artifact
240+
run: |
241+
# Stage everything the test shards need at the layout they expect
242+
# under a single directory, so the consumer can extract straight
243+
# into the workspace + $HOME.
244+
STAGE="$(mktemp -d)"
245+
mkdir -p "$STAGE/repo/app/src-tauri/target/debug"
246+
mkdir -p "$STAGE/repo/app/dist"
247+
mkdir -p "$STAGE/home/Library/Caches"
248+
cp -a app/src-tauri/target/debug/OpenHuman "$STAGE/repo/app/src-tauri/target/debug/"
249+
cp -a app/dist/. "$STAGE/repo/app/dist/"
250+
cp -a "$HOME/Library/Caches/tauri-cef" "$STAGE/home/Library/Caches/tauri-cef"
251+
tar --zstd -cf e2e-build-linux.tar.zst -C "$STAGE" repo home
252+
ls -lh e2e-build-linux.tar.zst
253+
254+
- name: Upload build artifact
255+
uses: actions/upload-artifact@v5
256+
with:
257+
name: e2e-build-linux-${{ github.run_id }}
258+
path: e2e-build-linux.tar.zst
259+
retention-days: 1
260+
if-no-files-found: error
261+
262+
e2e-linux-full:
263+
if: inputs.run_linux && inputs.full
264+
needs: build-linux-full
265+
name: E2E (Linux full / ${{ matrix.shard.name }})
266+
runs-on: ubuntu-22.04
267+
container:
268+
image: ghcr.io/tinyhumansai/openhuman_ci:latest
269+
timeout-minutes: 60
270+
strategy:
271+
fail-fast: false
272+
matrix:
273+
shard:
274+
- { name: foundation, suites: "auth,navigation,system" }
275+
- { name: chat, suites: "chat,skills,journeys" }
276+
- { name: integrations, suites: "providers,webhooks,notifications" }
277+
- { name: commerce, suites: "payments,settings" }
278+
steps:
279+
- name: Checkout code
280+
uses: actions/checkout@v5
281+
with:
282+
ref: ${{ inputs.ref }}
283+
fetch-depth: 1
284+
submodules: recursive
285+
286+
- name: Cache pnpm store
287+
uses: actions/cache@v5
288+
with:
289+
path: ~/.local/share/pnpm/store
290+
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
291+
restore-keys: |
292+
pnpm-store-${{ runner.os }}-
293+
240294
- name: Cache Appium global install
241295
uses: actions/cache@v5
242296
with:
@@ -245,51 +299,40 @@ jobs:
245299
/usr/local/lib/node_modules/appium
246300
key: appium3-chromium-${{ runner.os }}-v1
247301

248-
- name: Install JS dependencies
302+
- name: Install JS dependencies (for test harness only)
249303
run: pnpm install --frozen-lockfile
250304

251-
- name: Ensure .env exists for E2E build
252-
run: |
253-
touch .env
254-
touch app/.env
255-
256305
- name: Install Appium and chromium driver
257306
run: |
258307
if ! command -v appium >/dev/null 2>&1; then
259308
npm install -g appium@3
260309
fi
261310
appium driver install --source=npm appium-chromium-driver >/dev/null 2>&1 || true
262311
263-
# Cache the built debug binary + bundled frontend dist across runs.
264-
# Most iteration on this branch is CI/spec/orchestrator changes that do
265-
# NOT touch the Rust core or the React app — so the key below is stable
266-
# across those iterations and the next run hits the cache, skipping the
267-
# 10-15 min `cargo tauri build` step.
268-
- name: Cache built E2E binary (Linux)
269-
id: e2e-binary-cache
270-
uses: actions/cache@v5
312+
- name: Download build artifact
313+
uses: actions/download-artifact@v5
271314
with:
272-
path: |
273-
app/src-tauri/target/debug/OpenHuman
274-
app/dist
275-
key: e2e-binary-${{ runner.os }}-${{ hashFiles('src/**/*.rs', 'app/src-tauri/src/**', 'app/src-tauri/build.rs', 'app/src-tauri/tauri.conf.json', 'Cargo.lock', 'app/src-tauri/Cargo.lock', 'app/src-tauri/vendor/tauri-cef/Cargo.lock', 'rust-toolchain.toml', 'app/src/**', 'app/index.html', 'app/vite.config.*', 'app/tailwind.config.*', 'app/postcss.config.*', 'app/package.json', 'pnpm-lock.yaml', 'app/scripts/e2e-build.sh') }}
315+
name: e2e-build-linux-${{ github.run_id }}
316+
path: .
276317

277-
# Skip the (slow) build only when BOTH the binary AND the CEF runtime
278-
# caches hit — having the binary without libcef makes the runner fail
279-
# with 'libcef.so: cannot open shared object file' at launch.
280-
- name: Build E2E app
281-
if: steps.e2e-binary-cache.outputs.cache-hit != 'true' || steps.cef-cache.outputs.cache-hit != 'true'
282-
run: pnpm --filter openhuman-app test:e2e:build
318+
- name: Restore build artifact into workspace + $HOME
319+
run: |
320+
tar --zstd -xf e2e-build-linux.tar.zst
321+
# The artifact contains: repo/{app/src-tauri/target/debug/OpenHuman, app/dist/...}
322+
# and home/Library/Caches/tauri-cef/...
323+
mkdir -p app/src-tauri/target/debug app/dist "$HOME/Library/Caches"
324+
cp -a repo/app/src-tauri/target/debug/OpenHuman app/src-tauri/target/debug/
325+
cp -a repo/app/dist/. app/dist/
326+
cp -a home/Library/Caches/tauri-cef "$HOME/Library/Caches/"
327+
rm -rf repo home e2e-build-linux.tar.zst
328+
chmod +x app/src-tauri/target/debug/OpenHuman
329+
ls -la app/src-tauri/target/debug/OpenHuman app/dist | head
330+
ls -la "$HOME/Library/Caches/tauri-cef" | head
283331
284332
- name: Run E2E shard (${{ matrix.shard.name }} — suites=${{ matrix.shard.suites }})
285333
env:
286334
E2E_BAIL_ON_FAILURE: ${{ vars.E2E_BAIL_ON_FAILURE || '' }}
287335
run: |
288-
# Pin CEF_PATH to the actual download location used by
289-
# ensure-tauri-cli.sh + e2e-build.sh. The default in
290-
# e2e-run-session.sh already points here on macOS but Linux
291-
# needs the explicit export when the binary-cache short-circuit
292-
# skips the build step (which would otherwise have exported it).
293336
export CEF_PATH="$HOME/Library/Caches/tauri-cef"
294337
BAIL_FLAG=""
295338
if [[ "${E2E_BAIL_ON_FAILURE:-}" == "1" ]]; then

0 commit comments

Comments
 (0)