diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 39773c363415..81fa3547bdef 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -4,30 +4,7 @@ # SPDX-License-Identifier: BSD-3-Clause # region help -# Test job gating summary -# -# +------------------------------------+-----------------------------------------------------+ -# | Job | Gate (any match triggers the job) | -# +------------------------------------+-----------------------------------------------------+ -# | test-isaaclab-tasks (x3 shards) | isaaclab-tasks | isaaclab-core | infra | -# | test-isaaclab-core (x3 shards) | isaaclab-core | infra | -# | test-isaaclab-rl | isaaclab-rl | isaaclab-core | infra | -# | test-isaaclab-mimic | isaaclab-mimic | isaaclab-core | infra | -# | test-isaaclab-contrib | isaaclab-contrib | isaaclab-core | infra | -# | test-isaaclab-teleop | isaaclab-teleop | isaaclab-core | infra | -# | test-isaaclab-visualizers | isaaclab-visualizers | isaaclab-core | infra | -# | test-isaaclab-assets | isaaclab-assets | isaaclab-core | infra | -# | test-isaaclab-newton | isaaclab-newton | isaaclab-core | infra | -# | test-isaaclab-physx | isaaclab-physx | isaaclab-core | infra | -# | test-isaaclab-ov | isaaclab-ov | isaaclab-core | infra | -# | test-environments-training | isaaclab-tasks | isaaclab-core | infra | -# | test-curobo (needs build-curobo) | isaaclab-mimic | isaaclab-core | infra | -# | test-skillgen (needs build-curobo) | isaaclab-mimic | isaaclab-tasks | isaaclab-core | -# | | | infra | -# | test-quarantined | vars.RUN_QUARANTINED_TESTS == "true" | -# | build-curobo | isaaclab-mimic | isaaclab-tasks | isaaclab-core | -# | | | infra | -# +------------------------------------+-----------------------------------------------------+ +# Every test job runs on every PR. # # ============================================================================= # CI DEBUGGING TIPS @@ -121,149 +98,11 @@ jobs: echo "isaacsim_image_tag=$(yq -r .isaacsim_image_tag "$f")" >> "$GITHUB_OUTPUT" echo "isaaclab_image_name=$(yq -r .isaaclab_image_name "$f")" >> "$GITHUB_OUTPUT" - detect-changes: - name: Detect Changes - runs-on: ubuntu-latest - outputs: - isaaclab-core: ${{ steps.check.outputs.isaaclab-core }} - isaaclab-physx: ${{ steps.check.outputs.isaaclab-physx }} - isaaclab-newton: ${{ steps.check.outputs.isaaclab-newton }} - isaaclab-tasks: ${{ steps.check.outputs.isaaclab-tasks }} - isaaclab-rl: ${{ steps.check.outputs.isaaclab-rl }} - isaaclab-mimic: ${{ steps.check.outputs.isaaclab-mimic }} - isaaclab-contrib: ${{ steps.check.outputs.isaaclab-contrib }} - isaaclab-teleop: ${{ steps.check.outputs.isaaclab-teleop }} - isaaclab-visualizers: ${{ steps.check.outputs.isaaclab-visualizers }} - isaaclab-assets: ${{ steps.check.outputs.isaaclab-assets }} - isaaclab-ov: ${{ steps.check.outputs.isaaclab-ov }} - infra: ${{ steps.check.outputs.infra }} - steps: - - name: Checkout Code - uses: actions/checkout@v6 - with: - fetch-depth: 1 - - - name: Detect changed files and packages - id: check - run: | - set -euo pipefail - - # For non-PR events, run all tests - if [ "${{ github.event_name }}" != "pull_request" ]; then - for pkg in isaaclab-core isaaclab-physx isaaclab-newton isaaclab-tasks \ - isaaclab-rl isaaclab-mimic isaaclab-contrib isaaclab-teleop \ - isaaclab-visualizers isaaclab-assets isaaclab-ov infra; do - echo "$pkg=true" >> "$GITHUB_OUTPUT" - done - exit 0 - fi - - # Fetch the PR base branch tip to diff against - git fetch --depth=1 origin "${{ github.event.pull_request.base.ref }}" - changed=$(git diff --name-only FETCH_HEAD HEAD) - - if [ -z "$changed" ]; then - echo "::warning::No changed files detected between FETCH_HEAD and HEAD - running all tests as a safety measure" - for pkg in isaaclab-core isaaclab-physx isaaclab-newton isaaclab-tasks \ - isaaclab-rl isaaclab-mimic isaaclab-contrib isaaclab-teleop \ - isaaclab-visualizers isaaclab-assets isaaclab-ov infra; do - echo "$pkg=true" >> "$GITHUB_OUTPUT" - done - exit 0 - fi - - has() { - echo "$changed" | grep -qE "$1" - local rc=$? - if [ $rc -eq 0 ]; then echo true - elif [ $rc -eq 1 ]; then echo false - else - echo "::error::grep failed with exit $rc for pattern: $1" - exit 1 - fi - } - - # Detect per-package changes - core=$(has '^source/isaaclab/') - physx=$(has '^source/isaaclab_physx/') - newton=$(has '^source/isaaclab_newton/') - tasks=$(has '^source/isaaclab_tasks/') - - # Changes in apps/ trigger: core, physx, newton, tasks - apps=$(has '^apps/') - if [ "$apps" = "true" ]; then - core=true - physx=true - newton=true - tasks=true - fi - - echo "isaaclab-core=$core" >> "$GITHUB_OUTPUT" - echo "isaaclab-physx=$physx" >> "$GITHUB_OUTPUT" - echo "isaaclab-newton=$newton" >> "$GITHUB_OUTPUT" - echo "isaaclab-tasks=$tasks" >> "$GITHUB_OUTPUT" - echo "isaaclab-rl=$(has '^source/isaaclab_rl/')" >> "$GITHUB_OUTPUT" - echo "isaaclab-mimic=$(has '^source/isaaclab_mimic/')" >> "$GITHUB_OUTPUT" - echo "isaaclab-contrib=$(has '^source/isaaclab_contrib/')" >> "$GITHUB_OUTPUT" - echo "isaaclab-teleop=$(has '^source/isaaclab_teleop/')" >> "$GITHUB_OUTPUT" - echo "isaaclab-visualizers=$(has '^source/isaaclab_visualizers/')" >> "$GITHUB_OUTPUT" - echo "isaaclab-assets=$(has '^source/isaaclab_assets/')" >> "$GITHUB_OUTPUT" - echo "isaaclab-ov=$(has '^source/isaaclab_ov/')" >> "$GITHUB_OUTPUT" - echo "infra=$(has '^(\.github/|docker/|tools/|scripts/)')" >> "$GITHUB_OUTPUT" - - echo "" - echo "CHANGED FILES:" - echo "$changed" | while IFS= read -r f; do - case "$f" in - source/isaaclab/*) echo "$f (isaaclab-core)" ;; - source/isaaclab_physx/*) echo "$f (isaaclab-physx)" ;; - source/isaaclab_newton/*) echo "$f (isaaclab-newton)" ;; - source/isaaclab_tasks/*) echo "$f (isaaclab-tasks)" ;; - source/isaaclab_rl/*) echo "$f (isaaclab-rl)" ;; - source/isaaclab_mimic/*) echo "$f (isaaclab-mimic)" ;; - source/isaaclab_contrib/*) echo "$f (isaaclab-contrib)" ;; - source/isaaclab_teleop/*) echo "$f (isaaclab-teleop)" ;; - source/isaaclab_visualizers/*) echo "$f (isaaclab-visualizers)" ;; - source/isaaclab_assets/*) echo "$f (isaaclab-assets)" ;; - source/isaaclab_ov/*) echo "$f (isaaclab-ov)" ;; - .github/*|docker/*|tools/*|scripts/*) echo "$f (infra)" ;; - apps/*) echo "$f (apps - core/physx/newton/tasks)" ;; - *) echo "$f" ;; - esac - done - echo "" - echo "CHANGED PACKAGES:" - cat "$GITHUB_OUTPUT" - - # Write job summary visible on the GH Actions UI - { - echo "| File | Package |" - echo "|------|---------|" - echo "$changed" | while IFS= read -r f; do - case "$f" in - source/isaaclab/*) echo "| \`$f\` | isaaclab-core |" ;; - source/isaaclab_physx/*) echo "| \`$f\` | isaaclab-physx |" ;; - source/isaaclab_newton/*) echo "| \`$f\` | isaaclab-newton |" ;; - source/isaaclab_tasks/*) echo "| \`$f\` | isaaclab-tasks |" ;; - source/isaaclab_rl/*) echo "| \`$f\` | isaaclab-rl |" ;; - source/isaaclab_mimic/*) echo "| \`$f\` | isaaclab-mimic |" ;; - source/isaaclab_contrib/*) echo "| \`$f\` | isaaclab-contrib |" ;; - source/isaaclab_teleop/*) echo "| \`$f\` | isaaclab-teleop |" ;; - source/isaaclab_visualizers/*) echo "| \`$f\` | isaaclab-visualizers |" ;; - source/isaaclab_assets/*) echo "| \`$f\` | isaaclab-assets |" ;; - source/isaaclab_ov/*) echo "| \`$f\` | isaaclab-ov |" ;; - .github/*|docker/*|tools/*|scripts/*) echo "| \`$f\` | infra |" ;; - apps/*) echo "| \`$f\` | apps - core/physx/newton/tasks |" ;; - *) echo "| \`$f\` | - |" ;; - esac - done - } >> "$GITHUB_STEP_SUMMARY" - #region build jobs build: name: Build Base Docker Image runs-on: [self-hosted, gpu] - needs: [detect-changes, config] + needs: [config] steps: - name: Checkout Code uses: actions/checkout@v6 @@ -283,12 +122,7 @@ jobs: build-curobo: name: Build cuRobo Docker Image runs-on: [self-hosted, gpu] - needs: [detect-changes, config] - if: >- - needs.detect-changes.outputs.isaaclab-mimic == 'true' || - needs.detect-changes.outputs.isaaclab-tasks == 'true' || - needs.detect-changes.outputs.isaaclab-core == 'true' || - needs.detect-changes.outputs.infra == 'true' + needs: [config] steps: - name: Checkout Code uses: actions/checkout@v6 @@ -312,13 +146,8 @@ jobs: runs-on: [self-hosted, gpu] timeout-minutes: 180 continue-on-error: true - needs: [build, detect-changes, config] - if: >- - always() && needs.build.result == 'success' && ( - needs.detect-changes.outputs.isaaclab-tasks == 'true' || - needs.detect-changes.outputs.isaaclab-core == 'true' || - needs.detect-changes.outputs.infra == 'true' - ) + needs: [build, config] + if: always() && needs.build.result == 'success' steps: - uses: actions/checkout@v6 with: @@ -339,13 +168,8 @@ jobs: runs-on: [self-hosted, gpu] timeout-minutes: 180 continue-on-error: true - needs: [build, detect-changes, config] - if: >- - always() && needs.build.result == 'success' && ( - needs.detect-changes.outputs.isaaclab-tasks == 'true' || - needs.detect-changes.outputs.isaaclab-core == 'true' || - needs.detect-changes.outputs.infra == 'true' - ) + needs: [build, config] + if: always() && needs.build.result == 'success' steps: - uses: actions/checkout@v6 with: @@ -366,13 +190,8 @@ jobs: runs-on: [self-hosted, gpu] timeout-minutes: 180 continue-on-error: true - needs: [build, detect-changes, config] - if: >- - always() && needs.build.result == 'success' && ( - needs.detect-changes.outputs.isaaclab-tasks == 'true' || - needs.detect-changes.outputs.isaaclab-core == 'true' || - needs.detect-changes.outputs.infra == 'true' - ) + needs: [build, config] + if: always() && needs.build.result == 'success' steps: - uses: actions/checkout@v6 with: @@ -392,12 +211,8 @@ jobs: name: isaaclab (core) [1/3] runs-on: [self-hosted, gpu] timeout-minutes: 180 - needs: [build, detect-changes, config] - if: >- - always() && needs.build.result == 'success' && ( - needs.detect-changes.outputs.isaaclab-core == 'true' || - needs.detect-changes.outputs.infra == 'true' - ) + needs: [build, config] + if: always() && needs.build.result == 'success' steps: - uses: actions/checkout@v6 with: @@ -417,12 +232,8 @@ jobs: name: isaaclab (core) [2/3] runs-on: [self-hosted, gpu] timeout-minutes: 180 - needs: [build, detect-changes, config] - if: >- - always() && needs.build.result == 'success' && ( - needs.detect-changes.outputs.isaaclab-core == 'true' || - needs.detect-changes.outputs.infra == 'true' - ) + needs: [build, config] + if: always() && needs.build.result == 'success' steps: - uses: actions/checkout@v6 with: @@ -442,12 +253,8 @@ jobs: name: isaaclab (core) [3/3] runs-on: [self-hosted, gpu] timeout-minutes: 180 - needs: [build, detect-changes, config] - if: >- - always() && needs.build.result == 'success' && ( - needs.detect-changes.outputs.isaaclab-core == 'true' || - needs.detect-changes.outputs.infra == 'true' - ) + needs: [build, config] + if: always() && needs.build.result == 'success' steps: - uses: actions/checkout@v6 with: @@ -467,13 +274,8 @@ jobs: name: isaaclab_rl runs-on: [self-hosted, gpu] timeout-minutes: 180 - needs: [build, detect-changes, config] - if: >- - always() && needs.build.result == 'success' && ( - needs.detect-changes.outputs.isaaclab-rl == 'true' || - needs.detect-changes.outputs.isaaclab-core == 'true' || - needs.detect-changes.outputs.infra == 'true' - ) + needs: [build, config] + if: always() && needs.build.result == 'success' steps: - uses: actions/checkout@v6 with: @@ -491,13 +293,8 @@ jobs: name: isaaclab_mimic runs-on: [self-hosted, gpu] timeout-minutes: 180 - needs: [build, detect-changes, config] - if: >- - always() && needs.build.result == 'success' && ( - needs.detect-changes.outputs.isaaclab-mimic == 'true' || - needs.detect-changes.outputs.isaaclab-core == 'true' || - needs.detect-changes.outputs.infra == 'true' - ) + needs: [build, config] + if: always() && needs.build.result == 'success' steps: - uses: actions/checkout@v6 with: @@ -515,13 +312,8 @@ jobs: name: isaaclab_contrib runs-on: [self-hosted, gpu] timeout-minutes: 180 - needs: [build, detect-changes, config] - if: >- - always() && needs.build.result == 'success' && ( - needs.detect-changes.outputs.isaaclab-contrib == 'true' || - needs.detect-changes.outputs.isaaclab-core == 'true' || - needs.detect-changes.outputs.infra == 'true' - ) + needs: [build, config] + if: always() && needs.build.result == 'success' steps: - uses: actions/checkout@v6 with: @@ -539,13 +331,8 @@ jobs: name: isaaclab_teleop runs-on: [self-hosted, gpu] timeout-minutes: 180 - needs: [build, detect-changes, config] - if: >- - always() && needs.build.result == 'success' && ( - needs.detect-changes.outputs.isaaclab-teleop == 'true' || - needs.detect-changes.outputs.isaaclab-core == 'true' || - needs.detect-changes.outputs.infra == 'true' - ) + needs: [build, config] + if: always() && needs.build.result == 'success' steps: - uses: actions/checkout@v6 with: @@ -563,13 +350,8 @@ jobs: name: isaaclab_visualizers runs-on: [self-hosted, gpu] timeout-minutes: 180 - needs: [build, detect-changes, config] - if: >- - always() && needs.build.result == 'success' && ( - needs.detect-changes.outputs.isaaclab-visualizers == 'true' || - needs.detect-changes.outputs.isaaclab-core == 'true' || - needs.detect-changes.outputs.infra == 'true' - ) + needs: [build, config] + if: always() && needs.build.result == 'success' steps: - uses: actions/checkout@v6 with: @@ -587,13 +369,8 @@ jobs: name: isaaclab_assets runs-on: [self-hosted, gpu] timeout-minutes: 180 - needs: [build, detect-changes, config] - if: >- - always() && needs.build.result == 'success' && ( - needs.detect-changes.outputs.isaaclab-assets == 'true' || - needs.detect-changes.outputs.isaaclab-core == 'true' || - needs.detect-changes.outputs.infra == 'true' - ) + needs: [build, config] + if: always() && needs.build.result == 'success' steps: - uses: actions/checkout@v6 with: @@ -611,13 +388,8 @@ jobs: name: isaaclab_newton runs-on: [self-hosted, gpu] timeout-minutes: 180 - needs: [build, detect-changes, config] - if: >- - always() && needs.build.result == 'success' && ( - needs.detect-changes.outputs.isaaclab-newton == 'true' || - needs.detect-changes.outputs.isaaclab-core == 'true' || - needs.detect-changes.outputs.infra == 'true' - ) + needs: [build, config] + if: always() && needs.build.result == 'success' steps: - uses: actions/checkout@v6 with: @@ -635,13 +407,8 @@ jobs: name: isaaclab_physx runs-on: [self-hosted, gpu] timeout-minutes: 180 - needs: [build, detect-changes, config] - if: >- - always() && needs.build.result == 'success' && ( - needs.detect-changes.outputs.isaaclab-physx == 'true' || - needs.detect-changes.outputs.isaaclab-core == 'true' || - needs.detect-changes.outputs.infra == 'true' - ) + needs: [build, config] + if: always() && needs.build.result == 'success' steps: - uses: actions/checkout@v6 with: @@ -659,13 +426,8 @@ jobs: name: isaaclab_ov runs-on: [self-hosted, gpu] timeout-minutes: 180 - needs: [build, detect-changes, config] - if: >- - always() && needs.build.result == 'success' && ( - needs.detect-changes.outputs.isaaclab-ov == 'true' || - needs.detect-changes.outputs.isaaclab-core == 'true' || - needs.detect-changes.outputs.infra == 'true' - ) + needs: [build, config] + if: always() && needs.build.result == 'success' steps: - uses: actions/checkout@v6 with: @@ -684,13 +446,8 @@ jobs: runs-on: [self-hosted, gpu] timeout-minutes: 120 continue-on-error: true - needs: [build-curobo, detect-changes, config] - if: >- - always() && needs.build-curobo.result == 'success' && ( - needs.detect-changes.outputs.isaaclab-mimic == 'true' || - needs.detect-changes.outputs.isaaclab-core == 'true' || - needs.detect-changes.outputs.infra == 'true' - ) + needs: [build-curobo, config] + if: always() && needs.build-curobo.result == 'success' steps: - uses: actions/checkout@v6 with: @@ -711,14 +468,8 @@ jobs: runs-on: [self-hosted, gpu] timeout-minutes: 120 continue-on-error: true - needs: [build-curobo, detect-changes, config] - if: >- - always() && needs.build-curobo.result == 'success' && ( - needs.detect-changes.outputs.isaaclab-mimic == 'true' || - needs.detect-changes.outputs.isaaclab-tasks == 'true' || - needs.detect-changes.outputs.isaaclab-core == 'true' || - needs.detect-changes.outputs.infra == 'true' - ) + needs: [build-curobo, config] + if: always() && needs.build-curobo.result == 'success' steps: - uses: actions/checkout@v6 with: @@ -739,13 +490,8 @@ jobs: runs-on: [self-hosted, gpu] timeout-minutes: 300 continue-on-error: true - needs: [build, detect-changes, config] - if: >- - always() && needs.build.result == 'success' && ( - needs.detect-changes.outputs.isaaclab-tasks == 'true' || - needs.detect-changes.outputs.isaaclab-core == 'true' || - needs.detect-changes.outputs.infra == 'true' - ) + needs: [build, config] + if: always() && needs.build.result == 'success' steps: - uses: actions/checkout@v6 with: @@ -767,7 +513,7 @@ jobs: # runs-on: [self-hosted, gpu] # timeout-minutes: 180 # continue-on-error: true -# needs: [build, detect-changes, config] +# needs: [build, config] # if: >- # always() && needs.build.result == 'success' && # vars.RUN_QUARANTINED_TESTS == 'true' diff --git a/source/isaaclab_newton/isaaclab_newton/test/mock_interfaces/views/mock_articulation_view.py b/source/isaaclab_newton/isaaclab_newton/test/mock_interfaces/views/mock_articulation_view.py index dc698e97d223..26761937667e 100644 --- a/source/isaaclab_newton/isaaclab_newton/test/mock_interfaces/views/mock_articulation_view.py +++ b/source/isaaclab_newton/isaaclab_newton/test/mock_interfaces/views/mock_articulation_view.py @@ -49,6 +49,7 @@ def __init__( # Internal state (lazily initialised) self._root_transforms: wp.array | None = None self._root_velocities: wp.array | None = None + self._articulation_ids: wp.array | None = None self._attributes: dict[str, wp.array | None] = { "body_com": None, "body_mass": None, @@ -67,6 +68,16 @@ def count(self) -> int: def body_names(self) -> list[str]: return self._body_names + @property + def articulation_ids(self) -> wp.array: + """Mapping from ``(world, arti)`` to model articulation index. Shape ``(N, B)`` dtype=int.""" + if self._articulation_ids is None: + ids_np = np.arange(self._num_envs * self._num_bodies, dtype=np.int32).reshape( + self._num_envs, self._num_bodies + ) + self._articulation_ids = wp.array(ids_np, dtype=int, device=self._device) + return self._articulation_ids + # -- Lazy init helpers ------------------------------------------------- def _ensure_root_transforms(self) -> wp.array: @@ -222,6 +233,7 @@ def __init__( self._link_velocities: wp.array | None = None self._dof_positions: wp.array | None = None self._dof_velocities: wp.array | None = None + self._articulation_ids: wp.array | None = None # Attributes dict (lazily initialized) self._attributes: dict[str, wp.array | None] = { @@ -281,6 +293,14 @@ def link_names(self) -> list[str]: """Alias for body_names (Newton calls bodies 'links').""" return self._body_names + @property + def articulation_ids(self) -> wp.array: + """Mapping from ``(world, arti)`` to model articulation index. Shape ``(N, 1)`` dtype=int.""" + if self._articulation_ids is None: + ids_np = np.arange(self._count, dtype=np.int32).reshape(self._count, 1) + self._articulation_ids = wp.array(ids_np, dtype=int, device=self._device) + return self._articulation_ids + # -- Lazy Initialization Helpers -- def _ensure_root_transforms(self) -> wp.array: