Fixes Newton cloner ignoring collision approximation #12967
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
| # 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 | |
| name: Python Dependency Licenses Check | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, reopened] | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| jobs: | |
| license-check: | |
| # Fork PRs cannot access NGC_API_KEY, so they cannot resolve the immutable | |
| # OVPhysX wheel required by the development extras. | |
| if: github.event.pull_request.head.repo.full_name == github.repository | |
| runs-on: ubuntu-24.04 | |
| env: | |
| NGC_API_KEY: ${{ secrets.NGC_API_KEY }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| with: | |
| filter: tree:0 | |
| - name: Load OVPhysX wheelhouse configuration | |
| id: config | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| resource=$(yq -r .ovphysx_wheelhouse_resource .github/workflows/config.yaml) | |
| echo "wheelhouse_resource=${resource}" >> "$GITHUB_OUTPUT" | |
| - name: Restore NGC CLI cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: ${{ runner.temp }}/ngc-cli-cache/ngccli_linux.zip | |
| key: ngc-cli-${{ runner.os }}-${{ runner.arch }}-4.20.0-5cf084c88998c58ad8abf7849d2d1b41d578423886eb03018df10194e341d35b | |
| - name: Extract OVPhysX wheelhouse | |
| id: extract-wheelhouse | |
| shell: bash | |
| env: | |
| WHEELHOUSE_RESOURCE: ${{ steps.config.outputs.wheelhouse_resource }} | |
| run: | | |
| set -euo pipefail | |
| if [ -z "${NGC_API_KEY:-}" ]; then | |
| echo "::error::NGC_API_KEY is unavailable; cannot download the configured OVPhysX wheelhouse" | |
| exit 1 | |
| fi | |
| NGC_CLI_VERSION="4.20.0" | |
| NGC_CLI_SHA256="5cf084c88998c58ad8abf7849d2d1b41d578423886eb03018df10194e341d35b" | |
| NGC_CLI_URL="https://api.ngc.nvidia.com/v2/resources/nvidia/ngc-apps/ngc_cli/versions/${NGC_CLI_VERSION}/files/ngccli_linux.zip" | |
| wheelhouse_root="$(mktemp -d "${RUNNER_TEMP:-/tmp}/ovphysx-wheelhouse.XXXXXX")" | |
| download_root="$(mktemp -d "${RUNNER_TEMP:-/tmp}/ovphysx-wheelhouse-download.XXXXXX")" | |
| ngc_home="$(mktemp -d "${RUNNER_TEMP:-/tmp}/ovphysx-ngc-home.XXXXXX")" | |
| ngc_unpack_dir="" | |
| preserve_wheelhouse_root=false | |
| cleanup() { | |
| if [ "$preserve_wheelhouse_root" != "true" ]; then | |
| rm -rf "$wheelhouse_root" | |
| fi | |
| rm -rf "$download_root" "$ngc_home" | |
| if [ -n "$ngc_unpack_dir" ]; then | |
| rm -rf "$ngc_unpack_dir" | |
| fi | |
| } | |
| trap cleanup EXIT | |
| cache_dir="${RUNNER_TEMP:-/tmp}/ngc-cli-cache" | |
| ngc_zip="${cache_dir}/ngccli_linux.zip" | |
| mkdir -p "$cache_dir" | |
| if [ ! -f "$ngc_zip" ]; then | |
| echo "Downloading NGC CLI ${NGC_CLI_VERSION}" | |
| curl -fsSL -o "$ngc_zip" "$NGC_CLI_URL" | |
| fi | |
| echo "${NGC_CLI_SHA256} ${ngc_zip}" | sha256sum -c - | |
| ngc_unpack_dir="$(mktemp -d "${RUNNER_TEMP:-/tmp}/ngc-cli.XXXXXX")" | |
| unzip -q "$ngc_zip" -d "$ngc_unpack_dir" | |
| export PATH="${ngc_unpack_dir}/ngc-cli:${PATH}" | |
| export NGC_CLI_API_KEY="$NGC_API_KEY" | |
| export NGC_CLI_ORG=nvidian | |
| export NGC_CLI_TEAM=no-team | |
| export NGC_CLI_HOME="$ngc_home" | |
| ngc --version | |
| echo "Downloading wheelhouse resource: $WHEELHOUSE_RESOURCE" | |
| ngc registry resource download-version "$WHEELHOUSE_RESOURCE" --dest "$download_root" | |
| mapfile -t manifests < <(find "$download_root" -type f -name manifest.json) | |
| if [ "${#manifests[@]}" -ne 1 ]; then | |
| echo "::error::expected exactly one manifest.json in downloaded wheelhouse resource, found ${#manifests[@]}" | |
| printf '%s\n' "${manifests[@]}" | |
| exit 1 | |
| fi | |
| payload_dir="$(dirname "${manifests[0]}")" | |
| if [ ! -d "${payload_dir}/wheelhouse" ]; then | |
| echo "::error::downloaded wheelhouse resource is missing wheelhouse/ next to manifest.json" | |
| exit 1 | |
| fi | |
| mkdir -p "$wheelhouse_root/wheelhouse" | |
| cp "${payload_dir}/manifest.json" "$wheelhouse_root/manifest.json" | |
| cp "${payload_dir}/wheelhouse/"*.whl "$wheelhouse_root/wheelhouse/" | |
| python3 - <<'PY' "$wheelhouse_root/manifest.json" "$wheelhouse_root/wheelhouse" | |
| import hashlib | |
| import json | |
| import pathlib | |
| import sys | |
| manifest_path = pathlib.Path(sys.argv[1]) | |
| wheelhouse_dir = pathlib.Path(sys.argv[2]) | |
| manifest = json.loads(manifest_path.read_text(encoding="utf-8")) | |
| expected = { | |
| "artifact": "ovphysx-wheelhouse", | |
| "platform": "manylinux_2_35_x86_64", | |
| } | |
| for key, value in expected.items(): | |
| actual = manifest.get(key) | |
| if actual != value: | |
| raise SystemExit(f"manifest {key!r} mismatch: expected {value!r}, got {actual!r}") | |
| wheels = manifest.get("wheels") | |
| if not isinstance(wheels, list) or not wheels: | |
| raise SystemExit("manifest has no wheels list") | |
| for wheel in wheels: | |
| filename = wheel.get("file") | |
| expected_sha = wheel.get("sha256") | |
| if not filename or not expected_sha: | |
| raise SystemExit(f"invalid wheel manifest entry: {wheel!r}") | |
| wheel_path = wheelhouse_dir / filename | |
| if not wheel_path.is_file(): | |
| raise SystemExit(f"manifest wheel is missing from wheelhouse: {filename}") | |
| actual_sha = hashlib.sha256(wheel_path.read_bytes()).hexdigest() | |
| if actual_sha != expected_sha: | |
| raise SystemExit(f"sha256 mismatch for {filename}: expected {expected_sha}, got {actual_sha}") | |
| print(f"Validated {len(wheels)} wheelhouse wheels from {manifest_path}") | |
| PY | |
| echo "wheelhouse_root=$wheelhouse_root" >> "$GITHUB_OUTPUT" | |
| echo "wheelhouse_dir=$wheelhouse_root/wheelhouse" >> "$GITHUB_OUTPUT" | |
| # - name: Install jq | |
| # run: sudo apt-get update && sudo apt-get install -y jq | |
| - name: Clean up disk space | |
| run: | | |
| # Remove pre-installed tools | |
| rm -rf /opt/hostedtoolcache | |
| rm -rf /usr/share/dotnet | |
| rm -rf /opt/ghc | |
| sudo rm -rf /usr/local/lib/android | |
| rm -rf /usr/share/swift | |
| rm -rf /usr/local/share/boost | |
| sudo rm -rf /usr/local/.ghcup | |
| sudo rm -rf /usr/local/lib/node_modules | |
| sudo rm -rf /usr/local/share/chromium | |
| sudo rm -rf /usr/local/share/powershell | |
| # Clean apt cache | |
| sudo apt-get clean | |
| sudo rm -rf /var/lib/apt/lists/* | |
| # Docker cleanup | |
| docker container prune -f | |
| docker image prune -af | |
| docker volume prune -f | |
| docker system prune -af | |
| - name: Set up uv | |
| uses: astral-sh/setup-uv@v6 | |
| with: | |
| python-version: '3.12' | |
| enable-cache: true | |
| - name: Install dependencies with uv | |
| env: | |
| OMNI_KIT_ACCEPT_EULA: yes | |
| ACCEPT_EULA: Y | |
| ISAACSIM_ACCEPT_EULA: YES | |
| UV_FIND_LINKS: ${{ steps.extract-wheelhouse.outputs.wheelhouse_dir }} | |
| run: | | |
| uv sync --extra all | |
| # Isaac Sim conflicts with --extra all under uv, so install it imperatively | |
| # after the sync. Read the pinned spec from pyproject (single source of truth). | |
| ISAACSIM_SPEC=$(.venv/bin/python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['optional-dependencies']['isaacsim'][0])") | |
| uv pip install "$ISAACSIM_SPEC" | |
| uv pip install pip-licenses pipdeptree \ | |
| -r tools/template/requirements.txt \ | |
| -r docs/requirements.txt | |
| # Put the venv on PATH for later steps. | |
| echo "$PWD/.venv/bin" >> "$GITHUB_PATH" | |
| # Optional: Print the license report for visibility | |
| - name: Print License Report | |
| run: pip-licenses --from=mixed --format=markdown | |
| # Print pipdeptree | |
| - name: Print pipdeptree | |
| run: pipdeptree | |
| - name: Check licenses against whitelist and exceptions | |
| run: | | |
| # Define the whitelist of allowed licenses | |
| ALLOWED_LICENSES="MIT Apache BSD ISC zlib" | |
| # Load the exceptions list from the exceptions.json file | |
| EXCEPTIONS_FILE=".github/workflows/license-exceptions.json" | |
| # Initialize counter for failed packages | |
| FAILED_PACKAGES=0 | |
| # Get the list of installed packages and their licenses | |
| pip-licenses --from=mixed --format=json > licenses.json | |
| # Check the output of pip-licenses to ensure it is valid JSON | |
| if ! jq empty licenses.json; then | |
| echo "ERROR: Failed to parse pip-licenses output. Exiting..." | |
| exit 1 | |
| fi | |
| # Split ALLOWED_LICENSES into individual words | |
| IFS=' ' read -r -a allowed_licenses <<< "$ALLOWED_LICENSES" | |
| # Loop through the installed packages and their licenses | |
| for pkg in $(jq -r '.[].Name' licenses.json); do | |
| # Skip packages starting with nvidia (case-insensitive) | |
| if [[ "${pkg,,}" == nvidia* ]]; then | |
| continue | |
| fi | |
| LICENSE=$(jq -r --arg pkg "$pkg" '.[] | select(.Name == $pkg) | .License' licenses.json) | |
| # Check if any of the allowed licenses are a substring of the package's license | |
| match_found=false | |
| for allowed_license in "${allowed_licenses[@]}"; do | |
| if [[ "$LICENSE" == *"$allowed_license"* ]]; then | |
| match_found=true | |
| break | |
| fi | |
| done | |
| if [ "$match_found" = false ]; then | |
| # Check if the package is in the exceptions list | |
| EXCEPTION=$(jq -r --arg pkg "$pkg" --arg license "$LICENSE" \ | |
| '.[] | select(.package == $pkg)' "$EXCEPTIONS_FILE") | |
| # If the package is in the exceptions list | |
| if [ -n "$EXCEPTION" ]; then | |
| # If the license is provided in the exceptions list, check the license | |
| EXCEPTION_LICENSE=$(echo "$EXCEPTION" | jq -r '.license') | |
| # echo "Comparing licenses for $pkg:" | |
| # echo " EXCEPTION_LICENSE='${EXCEPTION_LICENSE}' (len=${#EXCEPTION_LICENSE})" | |
| # echo " LICENSE='${LICENSE}' (len=${#LICENSE})" | |
| # If the exceptions list has a license and doesn't match the current license | |
| if [ "$EXCEPTION_LICENSE" != "null" ] && [ "$EXCEPTION_LICENSE" != "$LICENSE" ]; then | |
| echo "ERROR: $pkg has license: $LICENSE" | |
| FAILED_PACKAGES=$((FAILED_PACKAGES + 1)) # Increment the counter | |
| fi | |
| else | |
| # If the package is not in the exceptions list | |
| echo "ERROR: $pkg has license: $LICENSE" | |
| FAILED_PACKAGES=$((FAILED_PACKAGES + 1)) # Increment the counter | |
| fi | |
| fi | |
| done | |
| # After all packages are processed, check if there were any errors | |
| if [ "$FAILED_PACKAGES" -gt 0 ]; then | |
| echo "ERROR: $FAILED_PACKAGES packages were flagged." | |
| exit 1 # Fail the build | |
| else | |
| echo "All packages were checked." | |
| fi | |
| - name: Clean up OVPhysX wheelhouse | |
| if: always() | |
| shell: bash | |
| run: | | |
| rm -rf "${{ steps.extract-wheelhouse.outputs.wheelhouse_root }}" |