release: v0.2.1 (fix PyPI publish — drop git direct-ref) #309
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| 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/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/**/*_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 ")" >> $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/lerobot_g1_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/test_gpu_smoke.py' | |
| - 'tests/test_isaac_lab_gpu.py' | |
| - 'tests/test_isaac_lab_compat.py' | |
| - 'src/roboharness/wrappers/gymnasium_wrapper.py' | |
| - '.cirun.yml' | |
| - 'Dockerfile.gpu' | |
| - '.github/workflows/ci.yml' | |
| gpu-test: | |
| needs: [gpu-changes] | |
| runs-on: [self-hosted, cirun-gpu] | |
| 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 | |
| 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/lerobot_g1.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 |