Skip to content

Actuators integration #3176

Actuators integration

Actuators integration #3176

Workflow file for this run

# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
# region help
# Every test job runs on every PR.
#
# =============================================================================
# CI DEBUGGING TIPS
# =============================================================================
#
# 1. DISABLE A TEST JOB (to isolate a specific job):
# Change the job's `if:` clause to `if: false`
# Example:
# test-isaaclab-tasks:
# ...
# if: false # TEMP: Disabled for debugging
#
# 2. RUN ONLY SPECIFIC TEST FILES (within a job):
# Add `include-files:` parameter to run-package-tests action
# Example:
# - uses: ./.github/actions/run-package-tests
# with:
# ...
# include-files: "test_rigid_object_collection.py" # Comma-separated
#
# 3. SKIP CONCURRENCY WAIT (run immediately without waiting for other runs):
# Comment out the concurrency block:
# # concurrency:
# # group: ${{ github.workflow }}-${{ github.ref }}
# # cancel-in-progress: true
#
# 4. TEST LOCALLY LIKE CI:
# docker run -it --rm --gpus all --network=host --entrypoint bash \
# -e OMNI_KIT_ACCEPT_EULA=yes -e ACCEPT_EULA=Y -e ISAAC_SIM_HEADLESS=1 \
# -e TEST_FILTER_PATTERN="isaaclab_physx" \
# -e TEST_INCLUDE_FILES="test_rigid_object_collection.py" \
# -v "$PWD":/workspace/isaaclab isaac-lab-base:latest \
# -c 'cd /workspace/isaaclab && /isaac-sim/python.sh -m pytest tools -v'
#
# Remember to REVERT all temporary changes before merging!
# =============================================================================
#endregion
name: Docker + Tests
on:
pull_request:
types: [opened, synchronize, reopened]
branches:
- main
- develop
- 'release/**'
workflow_dispatch:
# Concurrency control to prevent parallel runs on the same PR
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: write
checks: write
issues: read
env:
NGC_API_KEY: ${{ secrets.NGC_API_KEY }}
CI_IMAGE_TAG: isaac-lab-ci:${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || github.ref_name }}-${{ github.sha }}
jobs:
changes:
name: Detect Changes
runs-on: ubuntu-latest
outputs:
run_docker_tests: ${{ steps.detect.outputs.run_docker_tests }}
steps:
- id: detect
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
EVENT_NAME: ${{ github.event_name }}
REPO: ${{ github.repository }}
run: |
set -euo pipefail
# Docker test jobs run only when paths in the patterns table change.
# Otherwise they skip via `if:` and report green to branch protection,
# which is why we don't use a workflow-level `paths:` filter (a
# not-triggered required check would block the PR forever).
# config.yaml is included because it controls the base image names and
# tags consumed by the Docker build jobs.
patterns=(
$'^source/\tLibrary source code'
$'^docker/\tContainer build inputs'
$'^tools/\tBuild tooling'
$'^apps/\tStandalone apps'
$'^scripts/\tStandalone scripts'
$'^\\.github/workflows/build\\.yaml$\tThis workflow file'
$'^\\.github/workflows/config\\.yaml$\tBase image config'
$'^\\.github/actions/\tCI actions'
)
triggered_jobs="Docker build + all test-* matrix jobs"
render_table() {
local files="$1" entry regex desc count sample
echo "| Pattern | What it covers | Matched files |"
echo "|---|---|---|"
for entry in "${patterns[@]}"; do
IFS=$'\t' read -r regex desc <<< "$entry"
count=$(printf '%s\n' "$files" | grep -cE "$regex" || true)
if [ "$count" -gt 0 ]; then
sample=$(printf '%s\n' "$files" | grep -E "$regex" | head -3 | paste -sd ', ' -)
[ "$count" -gt 3 ] && sample="$sample (and $((count - 3)) more)"
echo "| \`$regex\` | $desc | $sample |"
else
echo "| \`$regex\` | $desc | - |"
fi
done
}
any_match() {
local files="$1" entry regex
for entry in "${patterns[@]}"; do
IFS=$'\t' read -r regex _ <<< "$entry"
if printf '%s\n' "$files" | grep -qE "$regex"; then
return 0
fi
done
return 1
}
decide() {
local decision="$1" reason="$2" files="${3:-}"
echo "Decision: run_docker_tests=$decision ($reason)"
echo "run_docker_tests=$decision" >> "$GITHUB_OUTPUT"
{
echo "## Docker test gating"
echo ""
if [ "$decision" = "true" ]; then
echo "Docker tests will **run**: $reason."
else
echo "Docker tests will be **skipped**: $reason."
fi
echo ""
echo "Triggered jobs: $triggered_jobs."
if [ -n "$files" ]; then
echo ""
render_table "$files"
fi
} >> "$GITHUB_STEP_SUMMARY"
}
if [ "$EVENT_NAME" != "pull_request" ]; then
decide true "non-PR event ($EVENT_NAME)"
exit 0
fi
if ! changed_files="$(gh api --paginate "repos/$REPO/pulls/$PR_NUMBER/files" --jq '.[].filename')"; then
# Fail-safe: a transient API error must not block merge. Default to running.
echo "::warning::Could not list changed files; defaulting to running tests"
decide true "fail-safe (could not list changed files)"
exit 0
fi
printf '%s\n' "$changed_files"
if any_match "$changed_files"; then
decide true "relevant paths changed" "$changed_files"
else
decide false "no relevant paths changed" "$changed_files"
fi
config:
name: Load Config
runs-on: ubuntu-latest
outputs:
isaacsim_image_name: ${{ steps.load.outputs.isaacsim_image_name }}
isaacsim_image_tag: ${{ steps.load.outputs.isaacsim_image_tag }}
isaaclab_image_name: ${{ steps.load.outputs.isaaclab_image_name }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
sparse-checkout: .github/workflows/config.yaml
sparse-checkout-cone-mode: false
- id: load
run: |
set -euo pipefail
f=.github/workflows/config.yaml
echo "isaacsim_image_name=$(yq -r .isaacsim_image_name "$f")" >> "$GITHUB_OUTPUT"
echo "isaacsim_image_tag=$(yq -r .isaacsim_image_tag "$f")" >> "$GITHUB_OUTPUT"
echo "isaaclab_image_name=$(yq -r .isaaclab_image_name "$f")" >> "$GITHUB_OUTPUT"
#region build jobs
build:
name: Build Base Docker Image
runs-on: [self-hosted, gpu]
needs: [changes, config]
if: needs.changes.outputs.run_docker_tests == 'true'
steps:
- name: Checkout Code
uses: actions/checkout@v6
with:
fetch-depth: 1
lfs: true
- name: Build and push to ECR
uses: ./.github/actions/ecr-build-push-pull
with:
image-tag: ${{ env.CI_IMAGE_TAG }}
isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
dockerfile-path: docker/Dockerfile.base
cache-tag: cache-base
build-curobo:
name: Build cuRobo Docker Image
runs-on: [self-hosted, gpu]
needs: [changes, config]
if: needs.changes.outputs.run_docker_tests == 'true'
steps:
- name: Checkout Code
uses: actions/checkout@v6
with:
fetch-depth: 1
lfs: true
- name: Build and push to ECR
uses: ./.github/actions/ecr-build-push-pull
with:
image-tag: ${{ env.CI_IMAGE_TAG }}-curobo
isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
dockerfile-path: docker/Dockerfile.curobo
cache-tag: cache-curobo
#endregion
#region test jobs
test-isaaclab-tasks:
name: isaaclab_tasks [1/3]
runs-on: [self-hosted, gpu]
timeout-minutes: 180
continue-on-error: true
needs: [build, config]
if: needs.build.result == 'success'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
lfs: true
- uses: ./.github/actions/run-package-tests
with:
image-tag: ${{ env.CI_IMAGE_TAG }}
isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
filter-pattern: "isaaclab_tasks"
extra-pip-packages: "ovrtx"
shard-index: "0"
shard-count: "3"
container-name: isaac-lab-tasks-1-test
test-isaaclab-tasks-2:
name: isaaclab_tasks [2/3]
runs-on: [self-hosted, gpu]
timeout-minutes: 180
continue-on-error: true
needs: [build, config]
if: needs.build.result == 'success'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
lfs: true
- uses: ./.github/actions/run-package-tests
with:
image-tag: ${{ env.CI_IMAGE_TAG }}
isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
filter-pattern: "isaaclab_tasks"
extra-pip-packages: "ovrtx"
shard-index: "1"
shard-count: "3"
container-name: isaac-lab-tasks-2-test
test-isaaclab-tasks-3:
name: isaaclab_tasks [3/3]
runs-on: [self-hosted, gpu]
timeout-minutes: 180
continue-on-error: true
needs: [build, config]
if: needs.build.result == 'success'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
lfs: true
- uses: ./.github/actions/run-package-tests
with:
image-tag: ${{ env.CI_IMAGE_TAG }}
isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
filter-pattern: "isaaclab_tasks"
extra-pip-packages: "ovrtx"
shard-index: "2"
shard-count: "3"
container-name: isaac-lab-tasks-3-test
test-isaaclab-core:
name: isaaclab (core) [1/3]
runs-on: [self-hosted, gpu]
timeout-minutes: 180
needs: [build, config]
if: needs.build.result == 'success'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
lfs: true
- uses: ./.github/actions/run-package-tests
with:
image-tag: ${{ env.CI_IMAGE_TAG }}
isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
filter-pattern: "not isaaclab_"
shard-index: "0"
shard-count: "3"
container-name: isaac-lab-core-1-test
test-isaaclab-core-2:
name: isaaclab (core) [2/3]
runs-on: [self-hosted, gpu]
timeout-minutes: 180
needs: [build, config]
if: needs.build.result == 'success'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
lfs: true
- uses: ./.github/actions/run-package-tests
with:
image-tag: ${{ env.CI_IMAGE_TAG }}
isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
filter-pattern: "not isaaclab_"
shard-index: "1"
shard-count: "3"
container-name: isaac-lab-core-2-test
test-isaaclab-core-3:
name: isaaclab (core) [3/3]
runs-on: [self-hosted, gpu]
timeout-minutes: 180
needs: [build, config]
if: needs.build.result == 'success'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
lfs: true
- uses: ./.github/actions/run-package-tests
with:
image-tag: ${{ env.CI_IMAGE_TAG }}
isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
filter-pattern: "not isaaclab_"
shard-index: "2"
shard-count: "3"
container-name: isaac-lab-core-3-test
test-isaaclab-rl:
name: isaaclab_rl
runs-on: [self-hosted, gpu]
timeout-minutes: 180
needs: [build, config]
if: needs.build.result == 'success'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
lfs: true
- uses: ./.github/actions/run-package-tests
with:
image-tag: ${{ env.CI_IMAGE_TAG }}
isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
filter-pattern: "isaaclab_rl"
extra-pip-packages: "leapp"
container-name: isaac-lab-rl-test
test-isaaclab-mimic:
name: isaaclab_mimic
runs-on: [self-hosted, gpu]
timeout-minutes: 180
needs: [build, config]
if: needs.build.result == 'success'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
lfs: true
- uses: ./.github/actions/run-package-tests
with:
image-tag: ${{ env.CI_IMAGE_TAG }}
isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
filter-pattern: "isaaclab_mimic"
container-name: isaac-lab-mimic-test
test-isaaclab-contrib:
name: isaaclab_contrib
runs-on: [self-hosted, gpu]
timeout-minutes: 180
needs: [build, config]
if: needs.build.result == 'success'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
lfs: true
- uses: ./.github/actions/run-package-tests
with:
image-tag: ${{ env.CI_IMAGE_TAG }}
isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
filter-pattern: "isaaclab_contrib"
container-name: isaac-lab-contrib-test
test-isaaclab-teleop:
name: isaaclab_teleop
runs-on: [self-hosted, gpu]
timeout-minutes: 180
needs: [build, config]
if: needs.build.result == 'success'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
lfs: true
- uses: ./.github/actions/run-package-tests
with:
image-tag: ${{ env.CI_IMAGE_TAG }}
isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
filter-pattern: "isaaclab_teleop"
container-name: isaac-lab-teleop-test
test-isaaclab-visualizers:
name: isaaclab_visualizers
runs-on: [self-hosted, gpu]
timeout-minutes: 180
needs: [build, config]
if: needs.build.result == 'success'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
lfs: true
- uses: ./.github/actions/run-package-tests
with:
image-tag: ${{ env.CI_IMAGE_TAG }}
isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
filter-pattern: "isaaclab_visualizers"
container-name: isaac-lab-visualizers-test
test-isaaclab-assets:
name: isaaclab_assets
runs-on: [self-hosted, gpu]
timeout-minutes: 180
needs: [build, config]
if: needs.build.result == 'success'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
lfs: true
- uses: ./.github/actions/run-package-tests
with:
image-tag: ${{ env.CI_IMAGE_TAG }}
isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
filter-pattern: "isaaclab_assets"
container-name: isaac-lab-assets-test
test-isaaclab-newton:
name: isaaclab_newton
runs-on: [self-hosted, gpu]
timeout-minutes: 180
needs: [build, config]
if: needs.build.result == 'success'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
lfs: true
- uses: ./.github/actions/run-package-tests
with:
image-tag: ${{ env.CI_IMAGE_TAG }}
isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
filter-pattern: "isaaclab_newton"
container-name: isaac-lab-newton-test
test-isaaclab-physx:
name: isaaclab_physx
runs-on: [self-hosted, gpu]
timeout-minutes: 180
needs: [build, config]
if: needs.build.result == 'success'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
lfs: true
- uses: ./.github/actions/run-package-tests
with:
image-tag: ${{ env.CI_IMAGE_TAG }}
isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
filter-pattern: "isaaclab_physx"
container-name: isaac-lab-physx-test
test-isaaclab-ov:
name: isaaclab_ov
runs-on: [self-hosted, gpu]
timeout-minutes: 180
needs: [build, config]
if: needs.build.result == 'success'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
lfs: true
- uses: ./.github/actions/run-package-tests
with:
image-tag: ${{ env.CI_IMAGE_TAG }}
isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
filter-pattern: "isaaclab_ov"
container-name: isaac-lab-ov-test
test-curobo:
name: test-curobo
runs-on: [self-hosted, gpu]
timeout-minutes: 120
continue-on-error: true
needs: [build-curobo, config]
if: needs.build-curobo.result == 'success'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
lfs: true
- uses: ./.github/actions/run-package-tests
with:
image-tag: ${{ env.CI_IMAGE_TAG }}-curobo
isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
dockerfile-path: docker/Dockerfile.curobo
cache-tag: cache-curobo
include-files: "test_curobo_planner_franka.py,test_curobo_planner_cube_stack.py,test_pink_ik.py"
container-name: isaac-lab-curobo-test
test-skillgen:
name: test-skillgen
runs-on: [self-hosted, gpu]
timeout-minutes: 120
continue-on-error: true
needs: [build-curobo, config]
if: needs.build-curobo.result == 'success'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
lfs: true
- uses: ./.github/actions/run-package-tests
with:
image-tag: ${{ env.CI_IMAGE_TAG }}-curobo
isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
dockerfile-path: docker/Dockerfile.curobo
cache-tag: cache-curobo
include-files: "test_generate_dataset_skillgen.py,test_environments_skillgen.py,test_environments_automate.py"
container-name: isaac-lab-skillgen-test
test-environments-training:
name: "environments_training"
runs-on: [self-hosted, gpu]
timeout-minutes: 300
continue-on-error: true
needs: [build, config]
if: needs.build.result == 'success'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
lfs: true
- uses: ./.github/actions/run-package-tests
with:
image-tag: ${{ env.CI_IMAGE_TAG }}
isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
filter-pattern: "isaaclab_tasks"
include-files: "test_environments_training.py"
container-name: isaac-lab-environments-training-test
#endregion
#region disabled quarantined tests
# test-quarantined:
# name: "Quarantined Tests"
# runs-on: [self-hosted, gpu]
# timeout-minutes: 180
# continue-on-error: true
# needs: [build, config]
# if: >-
# needs.build.result == 'success' &&
# vars.RUN_QUARANTINED_TESTS == 'true'
# steps:
# - uses: actions/checkout@v6
# with:
# fetch-depth: 1
# lfs: true
# - uses: ./.github/actions/run-package-tests
# with:
# image-tag: ${{ env.CI_IMAGE_TAG }}
# isaacsim-base-image: ${{ needs.config.outputs.isaacsim_image_name }}
# isaacsim-version: ${{ needs.config.outputs.isaacsim_image_tag }}
# quarantined-only: "true"
# container-name: isaac-lab-quarantined-test
#endregion