Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
0fde46e
feat(e2e): introduce scenario-based setup matrix and runner
jyaunches May 8, 2026
e34826e
fix(e2e): make run-suites.sh summary loops safe under bash 3.2 (macOS)
jyaunches May 8, 2026
a52bcce
refactor(e2e): reorganize lib/ and suites/ by scenario concern; addre…
jyaunches May 11, 2026
a3215e7
docs(e2e): add MIGRATION.md tracking legacy-to-scenario mapping
jyaunches May 11, 2026
7ee5675
test(e2e): add failing tests for Phase 1 infrastructure
jyaunches May 11, 2026
711aaef
feat(e2e): Phase 1 \u2014 pre-flight infrastructure for migration
jyaunches May 11, 2026
387767d
docs(e2e): expand MIGRATION.md with reuse-absorption table
jyaunches May 11, 2026
77d1d38
docs(e2e): consolidate READMEs into one concise top-level guide
jyaunches May 11, 2026
dc6cb9e
docs(e2e): move top-level README.md and MIGRATION.md under docs/
jyaunches May 11, 2026
6fbaed0
refactor(e2e): relocate runners, resolver, and cross-cutting lib to r…
jyaunches May 12, 2026
0e02caa
refactor(e2e): move declarative YAML inputs to domain buckets
jyaunches May 12, 2026
2b0c7d6
refactor(e2e): relocate install dispatch + helpers under nemoclaw_sce…
jyaunches May 12, 2026
d77dc1a
refactor(e2e): split onboard.sh into per-path files
jyaunches May 12, 2026
674a96d
refactor(e2e): move fixtures under nemoclaw_scenarios/fixtures/
jyaunches May 12, 2026
820daa7
refactor(e2e): consolidate assert helpers, sandbox-exec, and suites u…
jyaunches May 12, 2026
4e8abe2
refactor(e2e): update external callers for restructured paths
jyaunches May 12, 2026
853dcd6
refactor(e2e): point legacy test-*.sh scripts at relocated install-pa…
jyaunches May 12, 2026
45c895d
docs(e2e): restore 'how to add' heading for metadata-hygiene test
jyaunches May 12, 2026
cdf6018
chore(e2e): add parity-map placeholders for 3 legacy scripts that lan…
jyaunches May 12, 2026
19dff69
chore(e2e): isolate scenario framework tests
jyaunches May 12, 2026
1cc4b82
test: sanitize scenario helper environments
jyaunches May 12, 2026
cf99b16
test: avoid shell command strings in helpers
jyaunches May 12, 2026
0e59b1a
test(e2e): seed parity entries for new legacy scripts
jyaunches May 12, 2026
107bb92
fix(e2e): tighten convention lint edge cases
jyaunches May 12, 2026
6ab5062
fix(e2e): address assertion helper feedback
jyaunches May 12, 2026
1750996
fix(e2e): harden fixture helper validation
jyaunches May 12, 2026
70f5674
fix(e2e): address scenario workflow feedback
jyaunches May 12, 2026
9c65ac1
fix(e2e): harden runtime helper edge cases
jyaunches May 12, 2026
9b7fcdf
fix(e2e): harden assertion pattern checks
jyaunches May 12, 2026
2666711
fix(e2e): preserve parity YAML parse errors
jyaunches May 12, 2026
f0e4b16
fix(e2e): match sandbox names literally
jyaunches May 12, 2026
5d111f7
fix(e2e): mark scenario scripts executable
jyaunches May 12, 2026
7b2f0ac
style(e2e): apply pre-push formatting
jyaunches May 12, 2026
80c7852
docs(e2e): align scenario matrix paths
jyaunches May 13, 2026
023742b
chore(e2e): restore script executable bits
jyaunches May 13, 2026
361df8d
fix(e2e): restore helper hardening
jyaunches May 13, 2026
147ba3b
fix(e2e): harden scenario validation
jyaunches May 13, 2026
3b38323
Merge remote-tracking branch 'origin/main' into feat/e2e-scenario-mat…
jyaunches May 13, 2026
4e04f12
fix(e2e): seed new legacy parity entries
jyaunches May 13, 2026
6f865d9
docs(spec): simplify e2e parity plan
jyaunches May 13, 2026
47ac12f
docs(spec): add e2e parity test plan
jyaunches May 13, 2026
eaca286
docs(spec): add e2e parity validation plan
jyaunches May 13, 2026
385d86a
fix(e2e): dedupe parity map entries
jyaunches May 13, 2026
abefc0d
fix(e2e): untrack ignored parity spec
jyaunches May 13, 2026
492c30d
docs(spec): apply e2e parity design review
jyaunches May 13, 2026
f614360
docs(spec): apply e2e parity implementation review
jyaunches May 13, 2026
9cf738a
test: Add failing tests for Phase 1
jyaunches May 13, 2026
7920672
feat: Implement Phase 1 - Inventory Legacy Assertions
jyaunches May 13, 2026
618d8cc
Mark Phase 1 as completed [7920672b0]
jyaunches May 13, 2026
089015c
test: Add failing tests for Phase 2
jyaunches May 13, 2026
3f24605
feat: Implement Phase 2 - Enforce Parity Map Schema
jyaunches May 13, 2026
2f07256
Mark Phase 2 as completed [3f24605c2]
jyaunches May 13, 2026
26ad7b7
test(cli): relax installer version timeout
jyaunches May 13, 2026
0dc6950
fix(e2e): satisfy parity script hooks
jyaunches May 13, 2026
97958fb
style(e2e): format parity scripts
jyaunches May 13, 2026
5c84816
fix(e2e): untrack parity spec again
jyaunches May 13, 2026
dec8b36
style(e2e): format convention lint
jyaunches May 13, 2026
c223fa6
Merge remote-tracking branch 'origin/main' into feat/e2e-scenario-mat…
jyaunches May 13, 2026
830bd05
fix(e2e): seed gateway drift parity entry
jyaunches May 13, 2026
3528aa0
test(e2e): complete parity validation mapping
jyaunches May 13, 2026
fd8ac54
style(e2e): format retired wrapper lint
jyaunches May 13, 2026
893c126
Merge branch 'main' into feat/e2e-scenario-matrix-phase1
cv May 13, 2026
e175d18
Potential fix for pull request finding 'CodeQL / Unused variable, imp…
cv May 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions .github/workflows/e2e-parity-compare.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# E2E parity compare.
#
# Runs a legacy `test/e2e/test-*.sh` script AND its migrated scenario on
# the same runner, collects PASS/FAIL per assertion from both, and fails
# the job if any mapped assertion in test/e2e/docs/parity-map.yaml diverges.
#
# Manual-only (workflow_dispatch). Each migration phase dispatches this
# workflow for every scenario it introduces and records zero-divergence
# before marking the phase complete.

name: e2e-parity-compare

on:
workflow_dispatch:
inputs:
legacy_script:
description: "Legacy script filename under test/e2e/ (e.g. test-full-e2e.sh). Empty = no legacy run, empty-diff only."
required: false
default: ""
type: string
scenario:
description: "Migrated scenario id (e.g. ubuntu-repo-cloud-openclaw). Empty = use script map/default bucket scenarios."
required: false
default: ""
type: string
bucket:
description: "Parity bucket to run (onboarding-baseline, lifecycle, rebuild-runtime, providers-messaging, final-security-policy-platform-misc)."
required: false
default: ""
type: string
all_migrated:
description: "Run all migrated buckets from parity-map.yaml."
required: false
default: false
type: boolean
strict:
description: "Pass --strict to compare-parity.sh and fail on missing mapped log assertions."
required: false
default: true
type: boolean
deferred_handling:
description: "How deferred/retired assertions are handled by reporting."
required: false
default: "skip"
type: choice
options:
- skip
- report

permissions:
contents: read

concurrency:
group: e2e-parity-compare-${{ github.event.inputs.legacy_script }}-${{ github.event.inputs.scenario }}
cancel-in-progress: false

jobs:
resolve-runner:
runs-on: ubuntu-latest
outputs:
runner: ${{ steps.pick.outputs.runner }}
steps:
- id: pick
env:
SCENARIO: ${{ github.event.inputs.scenario }}
run: |
case "${SCENARIO}" in
macos-*) echo "runner=macos-latest" >> "$GITHUB_OUTPUT" ;;
wsl-*) echo "runner=windows-latest" >> "$GITHUB_OUTPUT" ;;
gpu-*) echo "runner=self-hosted" >> "$GITHUB_OUTPUT" ;;
ubuntu-*|brev-*|"") echo "runner=ubuntu-latest" >> "$GITHUB_OUTPUT" ;;
*)
echo "::error::Unknown scenario prefix for runner selection: ${SCENARIO}" >&2
exit 1
;;
esac

compare:
needs: resolve-runner
runs-on: ${{ needs.resolve-runner.outputs.runner }}
timeout-minutes: 60
steps:
- uses: actions/checkout@v4

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm

- name: Install root dependencies
run: npm ci --ignore-scripts

- name: Run legacy script
id: legacy
if: ${{ github.event.inputs.legacy_script != '' }}
env:
NVIDIA_API_KEY: ${{ secrets.NVIDIA_API_KEY }}
run: |
mkdir -p .e2e/parity
LOG=".e2e/parity/legacy.log"
if [ ! -x "test/e2e/${{ github.event.inputs.legacy_script }}" ]; then
echo "::error::legacy script not found: test/e2e/${{ github.event.inputs.legacy_script }}"
exit 1
fi
bash "test/e2e/${{ github.event.inputs.legacy_script }}" 2>&1 | tee "$LOG" || true

- name: Run migrated scenario
id: scenario
if: ${{ github.event.inputs.scenario != '' }}
env:
NVIDIA_API_KEY: ${{ secrets.NVIDIA_API_KEY }}
run: |
mkdir -p .e2e/parity
LOG=".e2e/parity/scenario.log"
bash test/e2e/runtime/run-scenario.sh "${{ github.event.inputs.scenario }}" 2>&1 | tee "$LOG" || true

- name: Compare parity
env:
LEGACY_SCRIPT: ${{ github.event.inputs.legacy_script }}
run: |
mkdir -p .e2e/parity
LEGACY_LOG=".e2e/parity/legacy.log"
SCENARIO_LOG=".e2e/parity/scenario.log"
[ -f "$LEGACY_LOG" ] || : > "$LEGACY_LOG"
[ -f "$SCENARIO_LOG" ] || : > "$SCENARIO_LOG"
SCRIPT_ARG="${LEGACY_SCRIPT:-none.sh}"
REPORT=".e2e/parity/parity-report.json"
STRICT_ARGS=()
if [ "${{ github.event.inputs.strict }}" = "true" ]; then
STRICT_ARGS+=(--strict)
fi
bash scripts/e2e/compare-parity.sh \
--script "$SCRIPT_ARG" \
--legacy "$LEGACY_LOG" \
--scenario "$SCENARIO_LOG" \
--map test/e2e/docs/parity-map.yaml \
--bucket "${{ github.event.inputs.bucket }}" \
--all-migrated "${{ github.event.inputs.all_migrated }}" \
--deferred-handling "${{ github.event.inputs.deferred_handling }}" \
--report "$REPORT" \
"${STRICT_ARGS[@]}"

- name: Render coverage report
if: always()
run: |
mkdir -p .e2e/parity
bash test/e2e/runtime/coverage-report.sh > .e2e/parity/coverage-report.md

- name: Upload parity artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-parity-${{ github.event.inputs.scenario }}-${{ github.event.inputs.legacy_script }}
path: |
.e2e/
if-no-files-found: warn
retention-days: 14
112 changes: 112 additions & 0 deletions .github/workflows/e2e-scenarios.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Scenario-based E2E. Runs a single setup scenario by id against the
# matching runner; can also validate resolution / coverage via --plan-only.
#
# Manual-only (workflow_dispatch) while scenario-based coverage migrates.
# Existing nightly-e2e / macos-e2e / wsl-e2e workflows remain unchanged.

name: e2e-scenarios

on:
workflow_dispatch:
inputs:
scenario:
description: "Scenario id (e.g. ubuntu-repo-cloud-openclaw)"
required: true
type: string
plan_only:
description: "Resolve and print plan only (no install/onboard/suites)"
required: false
default: "false"
type: choice
Comment thread
jyaunches marked this conversation as resolved.
options:
- "true"
- "false"
suite_filter:
description: "Comma-separated suite ids to run (optional; defaults to the scenario's full suite list)"
required: false
default: ""
type: string

permissions:
contents: read

concurrency:
group: e2e-scenarios-${{ github.event.inputs.scenario }}
cancel-in-progress: false

jobs:
# Route the scenario to the correct runner.
#
# Scenario ids encode their target platform as the first segment
# (e.g. `macos-repo-cloud-openclaw`, `wsl-repo-cloud-openclaw`,
# `gpu-repo-local-ollama-openclaw`). The workflow previously pinned
# `runs-on: ubuntu-latest` for every scenario, which caused non-Ubuntu
# scenarios to fail on the wrong runner (CodeRabbit review item #1).
resolve-runner:
runs-on: ubuntu-latest
outputs:
runner: ${{ steps.pick.outputs.runner }}
steps:
- id: pick
env:
SCENARIO: ${{ github.event.inputs.scenario }}
run: |
case "${SCENARIO}" in
macos-*) echo "runner=macos-latest" >> "$GITHUB_OUTPUT" ;;
wsl-*) echo "runner=windows-latest" >> "$GITHUB_OUTPUT" ;;
gpu-*) echo "runner=self-hosted" >> "$GITHUB_OUTPUT" ;;
ubuntu-*|brev-*) echo "runner=ubuntu-latest" >> "$GITHUB_OUTPUT" ;;
*)
echo "::error::Unknown scenario prefix for runner selection: ${SCENARIO}" >&2
exit 1
;;
esac

run-scenario:
needs: resolve-runner
runs-on: ${{ needs.resolve-runner.outputs.runner }}
timeout-minutes: 45
steps:
- uses: actions/checkout@v4

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm

- name: Install root dependencies
run: npm ci --ignore-scripts

- name: Render coverage report
run: |
mkdir -p .e2e
bash test/e2e/runtime/coverage-report.sh > .e2e/coverage.md
echo '## E2E scenario coverage' >> "$GITHUB_STEP_SUMMARY"
cat .e2e/coverage.md >> "$GITHUB_STEP_SUMMARY"

- name: Show resolved plan
run: |
bash test/e2e/runtime/run-scenario.sh "${{ github.event.inputs.scenario }}" --plan-only

- name: Run scenario
if: github.event.inputs.plan_only != 'true'
env:
NVIDIA_API_KEY: ${{ secrets.NVIDIA_API_KEY }}
E2E_SUITE_FILTER: ${{ github.event.inputs.suite_filter }}
run: |
bash test/e2e/runtime/run-scenario.sh "${{ github.event.inputs.scenario }}"

- name: Upload scenario artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-scenario-${{ github.event.inputs.scenario }}
path: |
.e2e/
test/e2e/logs/
if-no-files-found: warn
retention-days: 14
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,4 @@ secrets.json
secrets.yaml
service-account*.json
token.json
.e2e/
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ This repo ships agent skills under `.agents/skills/`, organized into three audie
| `nemoclaw-blueprint/model-specific-setup/` | JSON | Agent-scoped model/provider compatibility registry |
| `scripts/` | Bash/JS/TS | Install helpers, setup, automation, E2E tooling |
| `test/` | JavaScript (ESM) | Root-level integration tests (Vitest) |
| `test/e2e/` | Bash/JS | End-to-end tests (Brev cloud instances) |
| `test/e2e/` | Bash/JS/TS | End-to-end tests, scenario-based runner (see `test/e2e/README.md`) |
| `docs/` | Markdown (MyST) | User-facing docs (Sphinx) |

## Quick Reference
Expand Down
Loading
Loading