Files
openhuman/.github/workflows/e2e-reusable.yml
T

996 lines
35 KiB
YAML

---
# Reusable E2E workflow — single source of truth for the desktop E2E recipe.
#
# Callers:
# - `.github/workflows/e2e.yml` — PR/push, all-OS mega-flow gate.
# - `.github/workflows/release-staging.yml` — pretest gate, all 3 OS, full suite.
# - `.github/workflows/release-production.yml` — pretest gate, all 3 OS, full suite.
#
# Recipe per OS (identical across platforms — see e2e-run-session.sh):
# 1. Build the CEF app via `pnpm --filter openhuman-app test:e2e:build`.
# 2. Install Appium 3.x + the `chromium` driver.
# 3. Run `app/scripts/e2e-run-session.sh` which:
# - launches the built binary,
# - waits for CDP on :19222,
# - prunes the prewarm `about:blank` target,
# - downloads a chromedriver matching CEF's Chromium version,
# - starts Appium and runs WDIO against `wdio.conf.ts`.
#
# Linux runs inside the project CI container under Xvfb (no native display).
# macOS / Windows run on GitHub-hosted runners.
#
# Caching: pnpm store, Swatinem rust-cache, and CEF runtime download
# (~400MB) are cached on every job. The CEF cache key matches what
# build-desktop.yml uses so cross-workflow hits are possible.
name: E2E (reusable)
on:
workflow_call:
inputs:
ref:
description: Git ref (tag or SHA) to test. Release workflows pass the
freshly-pushed staging/production tag here so pretest validates
the exact commit the build matrix will check out, not main HEAD
at workflow_dispatch time. Defaults to empty (checkout uses its
own default, i.e. the workflow's triggering ref).
type: string
default: ""
run_linux:
description: Run the Linux (Xvfb / container) E2E job.
type: boolean
default: true
run_macos:
description: Run the macOS E2E job.
type: boolean
default: false
run_windows:
description: Run the Windows E2E job.
type: boolean
default: false
full:
description:
When true, run the entire spec suite via `e2e-run-session.sh` (no
spec arg). When false, run the desktop full-flow lane only
(`mega-flow.spec.ts`). Releases set this to true.
type: boolean
default: false
permissions:
contents: read
packages: read
jobs:
# Mega-flow gate for PR/push (full=false). The full-suite path lives in
# `e2e-linux-full` below, which fans out across 4 parallel shards via
# `e2e-run-all-flows.sh --suite=<list>`. Splitting the two prevents the
# smoke job from paying matrix overhead for a 2-spec run.
e2e-linux:
if: inputs.run_linux && !inputs.full
name: E2E (Linux / Appium Chromium)
runs-on: ubuntu-22.04
container:
image: ghcr.io/tinyhumansai/openhuman_ci:latest
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
persist-credentials: false
submodules: recursive
- name: Cache pnpm store
uses: actions/cache@v5
with:
path: ~/.local/share/pnpm/store
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
pnpm-store-${{ runner.os }}-
- name: Cache Rust build artifacts
uses: Swatinem/rust-cache@v2
with:
workspaces: |
. -> target
app/src-tauri -> target
cache-on-failure: true
key: e2e-linux-unified
# CEF runtime download cache — matches the key shape used by
# build-desktop.yml so a release build and an E2E run on the same
# commit can share a single download.
- name: Cache CEF binary distribution
uses: actions/cache@v5
with:
path: |
~/.cache/tauri-cef
key: cef-x86_64-unknown-linux-gnu-${{ hashFiles('app/src-tauri/Cargo.toml') }}
restore-keys: |
cef-x86_64-unknown-linux-gnu-
- name: Cache Appium global install
uses: actions/cache@v5
with:
path: |
~/.appium
/usr/local/lib/node_modules/appium
key: appium3-chromium-${{ runner.os }}-v1
- name: Install JS dependencies
run: bash scripts/ci-cancel-aware.sh pnpm install --frozen-lockfile
- name: Ensure .env exists for E2E build
run: |
touch .env
touch app/.env
- name: Install Appium and chromium driver
run: |
if ! command -v appium >/dev/null 2>&1; then
bash scripts/ci-cancel-aware.sh npm install -g appium@3
fi
# `appium driver list --installed` can miss cached installs on some
# Appium builds; install idempotently and ignore "already installed".
bash scripts/ci-cancel-aware.sh appium driver install --source=npm appium-chromium-driver >/dev/null 2>&1 || true
- name: Build E2E app
run: bash scripts/ci-cancel-aware.sh pnpm --filter openhuman-app test:e2e:build
- name: Run E2E (mega-flow)
if: ${{ !inputs.full }}
run: |
bash scripts/ci-cancel-aware.sh \
xvfb-run -a --server-args="-screen 0 1280x960x24" \
bash app/scripts/e2e-run-session.sh test/e2e/specs/mega-flow.spec.ts mega-flow
- name: Upload E2E failure artifacts
if: failure()
uses: actions/upload-artifact@v5
with:
name: e2e-failure-logs-${{ runner.os }}-${{ github.run_id }}
path: |
${{ runner.temp }}/openhuman-e2e-app-*.log
/tmp/openhuman-e2e-app-*.log
app/test/e2e/artifacts/
retention-days: 7
if-no-files-found: ignore
- name: Write job summary
if: always()
run: |
echo "## E2E Results (${{ runner.os }})" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ -f /tmp/e2e-summary.txt ]; then
cat /tmp/e2e-summary.txt >> $GITHUB_STEP_SUMMARY
else
echo "No summary file found." >> $GITHUB_STEP_SUMMARY
fi
# Full-suite Linux is now build-once-then-fanout: one `build-linux-full`
# job produces the binary + frontend dist + CEF runtime as a single
# workflow artifact, and the 4 shard test jobs `needs:` that build and
# download the artifact. This eliminates the parallel-shard cache race
# (only the first shard would otherwise populate the binary/CEF caches,
# the others would lose the race and rebuild) and guarantees the binary
# and its libcef.so are always packaged together.
build-linux-full:
if: inputs.run_linux && inputs.full
name: Build (Linux full)
runs-on: ubuntu-22.04
container:
image: ghcr.io/tinyhumansai/openhuman_ci:latest
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
submodules: recursive
- name: Cache pnpm store
uses: actions/cache@v5
with:
path: ~/.local/share/pnpm/store
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
pnpm-store-${{ runner.os }}-
- name: Cache Rust build artifacts
uses: Swatinem/rust-cache@v2
with:
workspaces: |
. -> target
app/src-tauri -> target
cache-on-failure: true
key: e2e-linux-unified
- name: Cache CEF binary distribution
uses: actions/cache@v5
with:
# cef-dll-sys downloads into $CEF_PATH; ensure-tauri-cli.sh +
# e2e-build.sh pin that to $HOME/Library/Caches/tauri-cef on
# every OS, so the cache key/path live there too.
path: |
~/Library/Caches/tauri-cef
key: cef-x86_64-unknown-linux-gnu-v2-${{ hashFiles('app/src-tauri/Cargo.toml') }}
restore-keys: |
cef-x86_64-unknown-linux-gnu-v2-
- name: Install JS dependencies
run: bash scripts/ci-cancel-aware.sh pnpm install --frozen-lockfile
- name: Ensure .env exists for E2E build
run: |
touch .env
touch app/.env
- name: Build E2E app
run: bash scripts/ci-cancel-aware.sh pnpm --filter openhuman-app test:e2e:build
- name: Package build artifact
run: |
# Stage everything the test shards need at the layout they expect
# under a single directory, so the consumer can extract straight
# into the workspace + $HOME.
STAGE="$(mktemp -d)"
mkdir -p "$STAGE/repo/app/src-tauri/target/debug"
mkdir -p "$STAGE/repo/app/dist"
mkdir -p "$STAGE/home/Library/Caches"
cp -a app/src-tauri/target/debug/OpenHuman "$STAGE/repo/app/src-tauri/target/debug/"
cp -a app/dist/. "$STAGE/repo/app/dist/"
cp -a "$HOME/Library/Caches/tauri-cef" "$STAGE/home/Library/Caches/tauri-cef"
tar -czf e2e-build-linux.tar.gz -C "$STAGE" repo home
ls -lh e2e-build-linux.tar.gz
- name: Upload build artifact
uses: actions/upload-artifact@v5
with:
name: e2e-build-linux-${{ github.run_id }}
path: e2e-build-linux.tar.gz
retention-days: 1
if-no-files-found: error
e2e-linux-full:
if: inputs.run_linux && inputs.full
needs: build-linux-full
name: E2E (Linux full / ${{ matrix.shard.name }})
runs-on: ubuntu-22.04
container:
image: ghcr.io/tinyhumansai/openhuman_ci:latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
shard:
- { name: foundation, suites: "auth,navigation,system" }
- { name: chat, suites: "chat,skills,journeys" }
- { name: providers, suites: "providers,notifications" }
- { name: webhooks, suites: "webhooks" }
- { name: connectors, suites: "connectors" }
- { name: commerce, suites: "payments,settings" }
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
submodules: recursive
- name: Cache pnpm store
uses: actions/cache@v5
with:
path: ~/.local/share/pnpm/store
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
pnpm-store-${{ runner.os }}-
- name: Cache Appium global install
uses: actions/cache@v5
with:
path: |
~/.appium
/usr/local/lib/node_modules/appium
key: appium3-chromium-${{ runner.os }}-v1
- name: Install JS dependencies (for test harness only)
run: bash scripts/ci-cancel-aware.sh pnpm install --frozen-lockfile
- name: Install Appium and chromium driver
run: |
if ! command -v appium >/dev/null 2>&1; then
bash scripts/ci-cancel-aware.sh npm install -g appium@3
fi
bash scripts/ci-cancel-aware.sh appium driver install --source=npm appium-chromium-driver >/dev/null 2>&1 || true
- name: Download build artifact
uses: actions/download-artifact@v5
with:
name: e2e-build-linux-${{ github.run_id }}
path: .
- name: Restore build artifact into workspace + $HOME
run: |
tar -xzf e2e-build-linux.tar.gz
# The artifact contains: repo/{app/src-tauri/target/debug/OpenHuman, app/dist/...}
# and home/Library/Caches/tauri-cef/...
mkdir -p app/src-tauri/target/debug app/dist "$HOME/Library/Caches"
cp -a repo/app/src-tauri/target/debug/OpenHuman app/src-tauri/target/debug/
cp -a repo/app/dist/. app/dist/
cp -a home/Library/Caches/tauri-cef "$HOME/Library/Caches/"
rm -rf repo home e2e-build-linux.tar.gz
chmod +x app/src-tauri/target/debug/OpenHuman
ls -la app/src-tauri/target/debug/OpenHuman app/dist | head
ls -la "$HOME/Library/Caches/tauri-cef" | head
- name: Run E2E shard (${{ matrix.shard.name }} — suites=${{ matrix.shard.suites }})
env:
E2E_BAIL_ON_FAILURE: ${{ vars.E2E_BAIL_ON_FAILURE || '' }}
run: |
export CEF_PATH="$HOME/Library/Caches/tauri-cef"
BAIL_FLAG=""
if [[ "${E2E_BAIL_ON_FAILURE:-}" == "1" ]]; then
BAIL_FLAG="--bail"
fi
bash scripts/ci-cancel-aware.sh \
xvfb-run -a --server-args="-screen 0 1280x960x24" \
bash app/scripts/e2e-run-all-flows.sh --skip-preflight \
--suite=${{ matrix.shard.suites }} $BAIL_FLAG
- name: Upload E2E failure artifacts
if: failure()
uses: actions/upload-artifact@v5
with:
name: e2e-failure-logs-${{ runner.os }}-${{ matrix.shard.name }}-${{ github.run_id }}
path: |
${{ runner.temp }}/openhuman-e2e-app-*.log
/tmp/openhuman-e2e-app-*.log
app/test/e2e/artifacts/
retention-days: 7
if-no-files-found: ignore
- name: Write job summary
if: always()
run: |
echo "## E2E Results (${{ runner.os }} / ${{ matrix.shard.name }})" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ -f /tmp/e2e-summary.txt ]; then
cat /tmp/e2e-summary.txt >> $GITHUB_STEP_SUMMARY
else
echo "No summary file found." >> $GITHUB_STEP_SUMMARY
fi
# Rust-side E2E counterpart to the Tauri runs above. Same Linux-only
# scope (CI does not run this on macOS or Windows — the Rust core is
# platform-independent, so one OS is enough signal). Boots the same
# `scripts/mock-api-server.mjs` the Tauri specs hit, then runs every
# `tests/*_e2e.rs` suite against it.
rust-e2e-linux:
if: inputs.run_linux
name: E2E (Linux / Rust integration suite)
runs-on: ubuntu-22.04
container:
image: ghcr.io/tinyhumansai/openhuman_ci:latest
timeout-minutes: 30
env:
CARGO_INCREMENTAL: "0"
RUST_BACKTRACE: "1"
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
persist-credentials: false
submodules: recursive
- name: Cache pnpm store
uses: actions/cache@v5
with:
path: ~/.local/share/pnpm/store
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
pnpm-store-${{ runner.os }}-
- name: Cache Rust build artifacts
uses: Swatinem/rust-cache@v2
with:
workspaces: . -> target
cache-on-failure: true
key: rust-e2e-linux
- name: Install JS dependencies
run: bash scripts/ci-cancel-aware.sh pnpm install --frozen-lockfile
- name: Ensure .env exists for tests
run: |
touch .env
touch app/.env
- name: Run Rust E2E suite (tests/*_e2e.rs vs mock backend)
run: bash scripts/ci-cancel-aware.sh pnpm test:rust:e2e
# No artifact uploads here either — same release-workflow reuse
# concern as the Tauri job above. Mock-backend log lives at
# /tmp/openhuman-rust-e2e-mock.log for local docker repro.
e2e-macos:
if: inputs.run_macos && !inputs.full
name: E2E (macOS / Appium Chromium)
runs-on: macos-latest
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
persist-credentials: false
submodules: recursive
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Setup Node.js 24.x
uses: actions/setup-node@v5
with:
node-version: 24.x
cache: pnpm
- name: Install Rust (rust-toolchain.toml)
uses: dtolnay/rust-toolchain@1.93.0
with:
# macos-latest is arm64, but the vendored tauri-cli's build.rs
# compiles a CEF helper for x86_64-apple-darwin (universal binary),
# so the x86_64 libstd must be installed too.
targets: x86_64-apple-darwin
- name: Verify cargo resolves to real toolchain
run: |
rustup default 1.93.0 || true
which cargo
cargo --version
- name: Cache Rust build artifacts
uses: Swatinem/rust-cache@v2
with:
workspaces: |
. -> target
app/src-tauri -> target
cache-on-failure: true
key: e2e-macos-unified-v2
- name: Cache CEF binary distribution
uses: actions/cache@v5
with:
path: |
~/Library/Caches/tauri-cef
key: cef-aarch64-apple-darwin-${{ hashFiles('app/src-tauri/Cargo.toml') }}
restore-keys: |
cef-aarch64-apple-darwin-
- name: Cache Appium global install
uses: actions/cache@v5
with:
path: |
~/.appium
key: appium3-chromium-${{ runner.os }}-v1
- name: Install JS dependencies
run: bash scripts/ci-cancel-aware.sh pnpm install --frozen-lockfile
- name: Ensure .env exists for E2E build
run: |
touch .env
touch app/.env
- name: Install Appium and chromium driver
run: |
if ! command -v appium >/dev/null 2>&1; then
bash scripts/ci-cancel-aware.sh npm install -g appium@3
fi
# `appium driver list --installed` can miss cached installs on some
# Appium builds; install idempotently and ignore "already installed".
bash scripts/ci-cancel-aware.sh appium driver install --source=npm appium-chromium-driver >/dev/null 2>&1 || true
- name: Build E2E app
run: bash scripts/ci-cancel-aware.sh pnpm --filter openhuman-app test:e2e:build
# macOS rejects dynamic-framework loads from unsigned bundles — adhoc
# signing satisfies the loader without a real developer-ID cert.
- name: Adhoc-sign the .app bundle
run: |
codesign --force --deep --sign - \
app/src-tauri/target/debug/bundle/macos/OpenHuman.app
codesign --verify --deep --verbose=2 \
app/src-tauri/target/debug/bundle/macos/OpenHuman.app
- name: Run E2E (mega-flow)
run: |
bash scripts/ci-cancel-aware.sh bash app/scripts/e2e-run-session.sh test/e2e/specs/mega-flow.spec.ts mega-flow
# Artifact uploads intentionally omitted — see e2e-linux for the
# reusable-workflow-is-also-used-by-releases rationale.
e2e-windows:
if: inputs.run_windows && !inputs.full
name: E2E (Windows / Appium Chromium)
runs-on: windows-latest
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
persist-credentials: false
submodules: recursive
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Setup Node.js 24.x
uses: actions/setup-node@v5
with:
node-version: 24.x
cache: pnpm
- name: Install Rust (rust-toolchain.toml)
uses: dtolnay/rust-toolchain@1.93.0
- name: Cache Rust build artifacts
uses: Swatinem/rust-cache@v2
with:
workspaces: |
. -> target
app/src-tauri -> target
cache-on-failure: true
key: e2e-windows-unified
- name: Cache CEF binary distribution
uses: actions/cache@v5
with:
path: |
~/AppData/Local/tauri-cef
key: cef-x86_64-pc-windows-msvc-${{ hashFiles('app/src-tauri/Cargo.toml') }}
restore-keys: |
cef-x86_64-pc-windows-msvc-
- name: Cache Appium global install
uses: actions/cache@v5
with:
path: |
~/.appium
key: appium3-chromium-${{ runner.os }}-v1
- name: Install JS dependencies
run: bash scripts/ci-cancel-aware.sh pnpm install --frozen-lockfile
- name: Ensure .env exists for E2E build
shell: bash
run: |
touch .env
touch app/.env
- name: Install Appium and chromium driver
shell: bash
run: |
if ! command -v appium >/dev/null 2>&1; then
bash scripts/ci-cancel-aware.sh npm install -g appium@3
fi
# `appium driver list --installed` can miss cached installs on some
# Appium builds; install idempotently and ignore "already installed".
bash scripts/ci-cancel-aware.sh appium driver install --source=npm appium-chromium-driver >/dev/null 2>&1 || true
- name: Build E2E app
run: bash scripts/ci-cancel-aware.sh pnpm --filter openhuman-app test:e2e:build
- name: Run E2E (mega-flow)
shell: bash
run: |
bash scripts/ci-cancel-aware.sh bash app/scripts/e2e-run-session.sh test/e2e/specs/mega-flow.spec.ts mega-flow
# Artifact uploads intentionally omitted — see e2e-linux for the
# reusable-workflow-is-also-used-by-releases rationale.
# ---------------------------------------------------------------------------
# Full-suite macOS — build-once-then-fanout, mirroring build-linux-full.
#
# Previously e2e-macos-full was a 6-shard matrix where each shard restored an
# `actions/cache` of the .app bundle and rebuilt the full Tauri app on a cold
# cache. On a cold cache that means up to 6 parallel full Tauri builds (only
# the first shard to finish would populate the cache; the rest lose the race).
# `build-macos-full` now builds the .app once and uploads it as a per-run
# workflow artifact; the shards `needs:` it, download, adhoc-sign, and run.
# ---------------------------------------------------------------------------
build-macos-full:
if: inputs.run_macos && inputs.full
name: Build (macOS full)
runs-on: macos-latest
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
submodules: recursive
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Setup Node.js 24.x
uses: actions/setup-node@v5
with:
node-version: 24.x
cache: pnpm
- name: Install Rust (rust-toolchain.toml)
uses: dtolnay/rust-toolchain@1.93.0
with:
# macos-latest is arm64, but the vendored tauri-cli's build.rs
# compiles a CEF helper for x86_64-apple-darwin (universal binary),
# so the x86_64 libstd must be installed too. Without this the
# build fails with E0463 "can't find crate for `core`".
targets: x86_64-apple-darwin
- name: Verify cargo resolves to real toolchain
run: |
rustup default 1.93.0 || true
which cargo
cargo --version
- name: Cache Rust build artifacts
uses: Swatinem/rust-cache@v2
with:
workspaces: |
. -> target
app/src-tauri -> target
cache-on-failure: true
key: e2e-macos-unified-v2
- name: Cache CEF binary distribution
uses: actions/cache@v5
with:
path: |
~/Library/Caches/tauri-cef
key: cef-aarch64-apple-darwin-${{ hashFiles('app/src-tauri/Cargo.toml') }}
restore-keys: |
cef-aarch64-apple-darwin-
- name: Install JS dependencies
run: bash scripts/ci-cancel-aware.sh pnpm install --frozen-lockfile
- name: Ensure .env exists for E2E build
run: |
touch .env
touch app/.env
- name: Build E2E app
run: bash scripts/ci-cancel-aware.sh pnpm --filter openhuman-app test:e2e:build
- name: Package build artifact
run: |
# The macOS .app is self-contained (frontend assets + CEF Frameworks +
# the OpenHuman Helper.app are embedded by tauri-bundler), so the .app
# bundle alone is everything a shard needs. tar preserves the bundle's
# internal symlinks + executable bits; each shard re-signs after
# extraction (adhoc codesign is required on every runner regardless).
tar -czf e2e-build-macos.tar.gz \
-C app/src-tauri/target/debug/bundle/macos OpenHuman.app
ls -lh e2e-build-macos.tar.gz
- name: Upload build artifact
uses: actions/upload-artifact@v5
with:
name: e2e-build-macos-${{ github.run_id }}
path: e2e-build-macos.tar.gz
retention-days: 1
if-no-files-found: error
e2e-macos-full:
if: inputs.run_macos && inputs.full
needs: build-macos-full
name: E2E (macOS full / ${{ matrix.shard.name }})
runs-on: macos-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
shard:
- { name: foundation, suites: "auth,navigation,system" }
- { name: chat, suites: "chat,skills,journeys" }
- { name: providers, suites: "providers,notifications" }
- { name: webhooks, suites: "webhooks" }
- { name: connectors, suites: "connectors" }
- { name: commerce, suites: "payments,settings" }
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
submodules: recursive
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Setup Node.js 24.x
uses: actions/setup-node@v5
with:
node-version: 24.x
cache: pnpm
- name: Cache Appium global install
uses: actions/cache@v5
with:
path: |
~/.appium
key: appium3-chromium-${{ runner.os }}-v1
- name: Install JS dependencies (for test harness only)
run: bash scripts/ci-cancel-aware.sh pnpm install --frozen-lockfile
- name: Install Appium and chromium driver
run: |
if ! command -v appium >/dev/null 2>&1; then
bash scripts/ci-cancel-aware.sh npm install -g appium@3
fi
bash scripts/ci-cancel-aware.sh appium driver install --source=npm appium-chromium-driver >/dev/null 2>&1 || true
- name: Download build artifact
uses: actions/download-artifact@v5
with:
name: e2e-build-macos-${{ github.run_id }}
path: .
- name: Restore .app bundle into workspace
run: |
mkdir -p app/src-tauri/target/debug/bundle/macos
tar -xzf e2e-build-macos.tar.gz \
-C app/src-tauri/target/debug/bundle/macos
rm -f e2e-build-macos.tar.gz
ls -la app/src-tauri/target/debug/bundle/macos/OpenHuman.app | head
# macOS rejects dynamic-framework loads from unsigned bundles — adhoc
# signing satisfies the loader without a real developer-ID cert. A
# bundle restored from the build artifact also needs (re-)signing on this
# runner; codesign is idempotent.
- name: Adhoc-sign the .app bundle
run: |
codesign --force --deep --sign - \
app/src-tauri/target/debug/bundle/macos/OpenHuman.app
codesign --verify --deep --verbose=2 \
app/src-tauri/target/debug/bundle/macos/OpenHuman.app
- name: Run E2E shard (${{ matrix.shard.name }} — suites=${{ matrix.shard.suites }})
env:
E2E_BAIL_ON_FAILURE: ${{ vars.E2E_BAIL_ON_FAILURE || '' }}
run: |
BAIL_FLAG=""
if [[ "${E2E_BAIL_ON_FAILURE:-}" == "1" ]]; then
BAIL_FLAG="--bail"
fi
bash scripts/ci-cancel-aware.sh bash app/scripts/e2e-run-all-flows.sh --skip-preflight \
--suite=${{ matrix.shard.suites }} $BAIL_FLAG
- name: Upload E2E failure artifacts
if: failure()
uses: actions/upload-artifact@v5
with:
name: e2e-failure-logs-${{ runner.os }}-${{ matrix.shard.name }}-${{ github.run_id }}
path: |
${{ runner.temp }}/openhuman-e2e-app-*.log
/tmp/openhuman-e2e-app-*.log
app/test/e2e/artifacts/
retention-days: 7
if-no-files-found: ignore
- name: Write job summary
if: always()
run: |
echo "## E2E Results (${{ runner.os }} / ${{ matrix.shard.name }})" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ -f /tmp/e2e-summary.txt ]; then
cat /tmp/e2e-summary.txt >> $GITHUB_STEP_SUMMARY
else
echo "No summary file found." >> $GITHUB_STEP_SUMMARY
fi
# ---------------------------------------------------------------------------
# Full-suite Windows — build-once-then-fanout, mirroring build-linux-full.
# `build-windows-full` builds the .exe + frontend dist + CEF runtime once and
# uploads them as a per-run workflow artifact; the shards `needs:` it and
# download, instead of each shard rebuilding on a cold binary cache.
# ---------------------------------------------------------------------------
build-windows-full:
if: inputs.run_windows && inputs.full
name: Build (Windows full)
runs-on: windows-latest
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
submodules: recursive
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Setup Node.js 24.x
uses: actions/setup-node@v5
with:
node-version: 24.x
cache: pnpm
- name: Install Rust (rust-toolchain.toml)
uses: dtolnay/rust-toolchain@1.93.0
- name: Cache Rust build artifacts
uses: Swatinem/rust-cache@v2
with:
workspaces: |
. -> target
app/src-tauri -> target
cache-on-failure: true
key: e2e-windows-unified
- name: Cache CEF binary distribution
uses: actions/cache@v5
with:
# ensure-tauri-cli.sh + e2e-build.sh export
# CEF_PATH=$HOME/Library/Caches/tauri-cef regardless of OS; under Git
# Bash on Windows that resolves under the user profile.
path: |
~/Library/Caches/tauri-cef
key: cef-x86_64-pc-windows-msvc-v2-${{ hashFiles('app/src-tauri/Cargo.toml') }}
restore-keys: |
cef-x86_64-pc-windows-msvc-v2-
- name: Install JS dependencies
run: bash scripts/ci-cancel-aware.sh pnpm install --frozen-lockfile
- name: Ensure .env exists for E2E build
shell: bash
run: |
touch .env
touch app/.env
- name: Build E2E app
run: bash scripts/ci-cancel-aware.sh pnpm --filter openhuman-app test:e2e:build
- name: Package build artifact
shell: bash
run: |
# Windows is NOT self-contained: the shard needs the .exe, the
# frontend dist, and the CEF runtime (exported via CEF_PATH at run
# time). Stage all three at the layout the shard restores into.
STAGE="$(mktemp -d)"
mkdir -p "$STAGE/repo/app/src-tauri/target/debug"
mkdir -p "$STAGE/repo/app/dist"
mkdir -p "$STAGE/home/Library/Caches"
cp -a app/src-tauri/target/debug/OpenHuman.exe "$STAGE/repo/app/src-tauri/target/debug/"
cp -a app/dist/. "$STAGE/repo/app/dist/"
cp -a "$HOME/Library/Caches/tauri-cef" "$STAGE/home/Library/Caches/tauri-cef"
tar -czf e2e-build-windows.tar.gz -C "$STAGE" repo home
ls -lh e2e-build-windows.tar.gz
- name: Upload build artifact
uses: actions/upload-artifact@v5
with:
name: e2e-build-windows-${{ github.run_id }}
path: e2e-build-windows.tar.gz
retention-days: 1
if-no-files-found: error
e2e-windows-full:
if: inputs.run_windows && inputs.full
needs: build-windows-full
name: E2E (Windows full / ${{ matrix.shard.name }})
runs-on: windows-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
shard:
- { name: foundation, suites: "auth,navigation,system" }
- { name: chat, suites: "chat,skills,journeys" }
- { name: providers, suites: "providers,notifications" }
- { name: webhooks, suites: "webhooks" }
- { name: connectors, suites: "connectors" }
- { name: commerce, suites: "payments,settings" }
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
submodules: recursive
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Setup Node.js 24.x
uses: actions/setup-node@v5
with:
node-version: 24.x
cache: pnpm
- name: Cache Appium global install
uses: actions/cache@v5
with:
path: |
~/.appium
key: appium3-chromium-${{ runner.os }}-v1
- name: Install JS dependencies (for test harness only)
run: bash scripts/ci-cancel-aware.sh pnpm install --frozen-lockfile
- name: Install Appium and chromium driver
shell: bash
run: |
if ! command -v appium >/dev/null 2>&1; then
bash scripts/ci-cancel-aware.sh npm install -g appium@3
fi
bash scripts/ci-cancel-aware.sh appium driver install --source=npm appium-chromium-driver >/dev/null 2>&1 || true
- name: Download build artifact
uses: actions/download-artifact@v5
with:
name: e2e-build-windows-${{ github.run_id }}
path: .
- name: Restore build artifact into workspace + $HOME
shell: bash
run: |
tar -xzf e2e-build-windows.tar.gz
mkdir -p app/src-tauri/target/debug app/dist "$HOME/Library/Caches"
cp -a repo/app/src-tauri/target/debug/OpenHuman.exe app/src-tauri/target/debug/
cp -a repo/app/dist/. app/dist/
cp -a home/Library/Caches/tauri-cef "$HOME/Library/Caches/"
rm -rf repo home e2e-build-windows.tar.gz
ls -la app/src-tauri/target/debug/OpenHuman.exe app/dist | head
- name: Run E2E shard (${{ matrix.shard.name }} — suites=${{ matrix.shard.suites }})
shell: bash
env:
E2E_BAIL_ON_FAILURE: ${{ vars.E2E_BAIL_ON_FAILURE || '' }}
run: |
# e2e-build.sh + ensure-tauri-cli.sh always download CEF to
# $HOME/Library/Caches/tauri-cef regardless of OS.
export CEF_PATH="$HOME/Library/Caches/tauri-cef"
BAIL_FLAG=""
if [[ "${E2E_BAIL_ON_FAILURE:-}" == "1" ]]; then
BAIL_FLAG="--bail"
fi
bash scripts/ci-cancel-aware.sh bash app/scripts/e2e-run-all-flows.sh --skip-preflight \
--suite=${{ matrix.shard.suites }} $BAIL_FLAG
- name: Upload E2E failure artifacts
if: failure()
uses: actions/upload-artifact@v5
with:
name: e2e-failure-logs-${{ runner.os }}-${{ matrix.shard.name }}-${{ github.run_id }}
# e2e-run-session.sh writes its app log to `${RUNNER_TEMP:-${TMPDIR:-/tmp}}`.
# On Windows runners RUNNER_TEMP resolves to D:\a\_temp, not /tmp.
path: |
${{ runner.temp }}/openhuman-e2e-app-*.log
app/test/e2e/artifacts/
retention-days: 7
if-no-files-found: ignore
- name: Write job summary
if: always()
shell: bash
run: |
echo "## E2E Results (${{ runner.os }} / ${{ matrix.shard.name }})" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ -f /tmp/e2e-summary.txt ]; then
cat /tmp/e2e-summary.txt >> $GITHUB_STEP_SUMMARY
else
echo "No summary file found." >> $GITHUB_STEP_SUMMARY
fi