Skip to content

fix(evidence): resolve repo-relative suite case dirs #406

fix(evidence): resolve repo-relative suite case dirs

fix(evidence): resolve repo-relative suite case dirs #406

Workflow file for this run

name: CI
on:
push:
branches: [main, claude/test-aws-gpu-ci-gl5Jf]
pull_request:
branches: [main]
concurrency:
group: gpu-${{ github.head_ref || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@v4
- name: Install dependencies
run: uv pip install --system ruff mypy
- name: Ruff lint
run: ruff check .
- name: Ruff format check
run: ruff format --check .
- name: Mypy type check
run: mypy src/
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install uv
uses: astral-sh/setup-uv@v4
- name: Install package with dev dependencies
run: uv pip install --system -e ".[dev]"
- name: Run tests with coverage
run: pytest
test-mujoco:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@v4
- name: Install system dependencies (OSMesa for headless rendering)
run: sudo apt-get update && sudo apt-get install -y libosmesa6-dev
- name: Install package with demo and dev dependencies
run: uv pip install --system -e ".[demo,dev]"
- name: Run tests (including MuJoCo-dependent tests)
env:
MUJOCO_GL: osmesa
run: pytest
mujoco-example:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@v4
- name: Install system dependencies (OSMesa for headless rendering)
run: sudo apt-get update && sudo apt-get install -y libosmesa6-dev
- name: Install package with demo dependencies
run: uv pip install --system -e ".[demo]"
- name: Run MuJoCo grasp example
env:
MUJOCO_GL: osmesa
run: python examples/demos/mujoco/grasp.py --report --assert-success --output-dir ./harness_output
- name: Upload visual artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: mujoco-grasp-output
path: |
harness_output/report.html
harness_output/mujoco_grasp/trial_001/autonomous_report.json
harness_output/mujoco_grasp/trial_001/alarms.json
harness_output/mujoco_grasp/trial_001/phase_manifest.json
harness_output/mujoco_grasp/trial_001/**/*_rgb.png
harness_output/mujoco_grasp/trial_001/**/metadata.json
retention-days: 30
- name: Post summary with checkpoint images
if: always()
run: |
echo "## MuJoCo Grasp Example Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Checkpoint captures from the scripted grasp sequence:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
for cp in harness_output/mujoco_grasp/trial_001/*/; do
name=$(basename "$cp")
echo "### ${name}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ -f "${cp}front_rgb.png" ]; then
echo "![${name} front view](data:image/png;base64,$(base64 -w0 "${cp}front_rgb.png"))" >> $GITHUB_STEP_SUMMARY
fi
if [ -f "${cp}metadata.json" ]; then
step=$(python3 -c "import json; print(json.load(open('${cp}metadata.json'))['step'])")
sim_time=$(python3 -c "import json; print(f\"{json.load(open('${cp}metadata.json'))['sim_time']:.3f}\")")
echo "" >> $GITHUB_STEP_SUMMARY
echo "Step: ${step} | Sim time: ${sim_time}s" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
done
echo "---" >> $GITHUB_STEP_SUMMARY
echo "Download the full artifact (including HTML report) from the Actions tab." >> $GITHUB_STEP_SUMMARY
lerobot-g1-native-example:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@v4
- name: Install system dependencies (OSMesa for headless rendering)
run: sudo apt-get update && sudo apt-get install -y libosmesa6-dev
- name: Install package with demo dependencies
run: uv pip install --system -e ".[demo]"
- name: Install unitree SDK directly from fork
run: |
# unitree-sdk2py is installed directly (not via a pyproject extra —
# PyPI rejects packages with git-based direct references on upload)
uv pip install --system "unitree-sdk2py @ git+https://github.com/MiaoDX-fork-and-pruning/unitree_sdk2_python_uv.git"
- name: Install CPU PyTorch and lerobot
run: |
uv pip install --system torch --index-url https://download.pytorch.org/whl/cpu
uv pip install --system lerobot
- name: Install lerobot/unitree-g1-mujoco runtime deps
run: uv pip install --system loguru pygame scipy pyyaml
- name: Cache HuggingFace models
uses: actions/cache@v4
with:
path: ~/.cache/huggingface/hub
key: hf-models-${{ runner.os }}-v1
- name: Run native LeRobot G1 example (GR00T)
env:
MUJOCO_GL: osmesa
run: python examples/demos/g1/lerobot_native.py --controller groot --report --assert-success --output-dir ./harness_output
- name: Upload visual artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: lerobot-g1-native-output
path: |
harness_output/lerobot_g1_native_groot_report.html
harness_output/lerobot_g1_native_groot/trial_001/**/*_rgb.png
harness_output/lerobot_g1_native_groot/trial_001/**/metadata.json
retention-days: 30
gpu-changes:
runs-on: ubuntu-latest
outputs:
gpu_relevant: ${{ steps.filter.outputs.gpu }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
gpu:
- 'tests/integration/gpu/test_gpu_smoke.py'
- 'tests/integration/gpu/test_isaac_lab_gpu.py'
- 'tests/unit/wrappers/test_isaac_lab_compat.py'
- 'src/roboharness/wrappers/gymnasium_wrapper.py'
- '.cirun.yml'
- 'Dockerfile.gpu'
- '.github/workflows/ci.yml'
# ─── gpu-test (GCP) PAUSED 2026-04-14 ────────────────────────────────
# GCP runner is currently paused in .cirun.yml; AWS Sydney is the
# primary GPU CI. To re-enable, uncomment the block below AND
# uncomment the GCP runner block in .cirun.yml.
#
# gpu-test:
# needs: [gpu-changes]
# runs-on: [self-hosted, cirun-gpu]
# timeout-minutes: 45
# # Only one GCP GPU job runs at a time globally — we only have quota for
# # a single T4. `cancel-in-progress: true` so a new push immediately
# # pre-empts any stale in-progress / queued job in this group; otherwise
# # a stuck provisioning attempt would hold the slot indefinitely and
# # every subsequent push would pile up behind it.
# concurrency:
# group: gpu-test-gcp
# cancel-in-progress: true
# if: |
# github.event_name == 'push' && github.ref == 'refs/heads/main'
# || contains(github.event.pull_request.labels.*.name, 'gpu-test')
# || needs.gpu-changes.outputs.gpu_relevant == 'true'
# steps:
# - uses: actions/checkout@v4
# - uses: actions/setup-python@v5
# with:
# python-version: "3.12"
# - name: Install uv
# uses: astral-sh/setup-uv@v4
# - name: Install package with dev dependencies and torch
# run: |
# uv pip install --system -e ".[dev]"
# uv pip install --system torch --index-url https://download.pytorch.org/whl/cu121
# - name: Verify GPU
# run: |
# nvidia-smi
# python -c 'import torch; print(f"CUDA: {torch.cuda.is_available()}, GPUs: {torch.cuda.device_count()}")'
# - name: Run GPU tests
# run: pytest -m gpu -v --no-cov
# ─── End paused gpu-test (GCP) ───────────────────────────────────────
# AWS GPU smoke test — primary GPU CI. Runs on the cirun-aws-gpu runner
# provisioned on AWS (g4dn.xlarge in ap-southeast-2 + NVIDIA GPU-Optimized
# AMI). Gated to the test branch and to the gpu-relevant paths filter so
# we don't spin up AWS instances on unrelated pushes.
gpu-test-aws:
needs: [gpu-changes]
runs-on: [self-hosted, cirun-aws-gpu]
timeout-minutes: 45
# Serialize AWS GPU jobs too. `cancel-in-progress: true` so a new push
# pre-empts any stale in-progress / queued attempt — important because
# Cirun provisioning on AWS can silently sit queued (e.g. if the
# Dashboard has no AWS credentials or the Marketplace AMI subscription
# is still propagating), and `false` would stack pushes behind forever.
# Runs in a different group from gpu-test-gcp, so GCP and AWS do not
# block each other.
concurrency:
group: gpu-test-aws
cancel-in-progress: true
if: |
github.ref == 'refs/heads/claude/test-aws-gpu-ci-gl5Jf'
|| contains(github.event.pull_request.labels.*.name, 'gpu-test-aws')
|| needs.gpu-changes.outputs.gpu_relevant == 'true'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@v4
- name: Show host info
run: |
uname -a
cat /etc/os-release || true
nvidia-smi
- name: Install package with dev dependencies and torch
run: |
uv pip install --system -e ".[dev]"
uv pip install --system torch --index-url https://download.pytorch.org/whl/cu121
- name: Verify PyTorch CUDA
run: |
python -c 'import torch; print(f"torch={torch.__version__}, CUDA available={torch.cuda.is_available()}, GPUs={torch.cuda.device_count()}, name={torch.cuda.get_device_name(0) if torch.cuda.is_available() else None}")'
- name: Run GPU tests
run: pytest -m gpu -v --no-cov
lerobot-g1-example:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@v4
- name: Install system dependencies (OSMesa for headless rendering)
run: sudo apt-get update && sudo apt-get install -y libosmesa6-dev
- name: Install package with demo dependencies
run: uv pip install --system -e ".[demo]"
- name: Run LeRobot G1 example
env:
MUJOCO_GL: osmesa
run: python examples/demos/g1/lerobot_locomotion.py --report --assert-success --output-dir ./harness_output
- name: Upload visual artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: lerobot-g1-output
path: |
harness_output/lerobot_g1_report.html
harness_output/lerobot_g1/trial_001/**/*_rgb.png
harness_output/lerobot_g1/trial_001/**/metadata.json
retention-days: 30
- name: Post summary
if: always()
run: |
echo "## LeRobot G1 Example Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Checkpoint captures from the G1 humanoid validation:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
for cp in harness_output/lerobot_g1/trial_001/*/; do
name=$(basename "$cp")
n_images=$(find "$cp" -name '*_rgb.png' 2>/dev/null | wc -l)
if [ -f "${cp}metadata.json" ]; then
step=$(python3 -c "import json; print(json.load(open('${cp}metadata.json'))['step'])")
echo "- **${name}**: step ${step}, ${n_images} captures" >> $GITHUB_STEP_SUMMARY
else
echo "- **${name}**: ${n_images} captures" >> $GITHUB_STEP_SUMMARY
fi
done
echo "" >> $GITHUB_STEP_SUMMARY
echo "Download the full artifact (including HTML report and images) from the Actions tab." >> $GITHUB_STEP_SUMMARY