@@ -15,14 +15,145 @@ concurrency:
1515
1616jobs :
1717 license-check :
18+ # Fork PRs cannot access NGC_API_KEY, so they cannot resolve the immutable
19+ # OVPhysX wheel required by the development extras.
20+ if : github.event.pull_request.head.repo.full_name == github.repository
1821 runs-on : ubuntu-24.04
22+ env :
23+ NGC_API_KEY : ${{ secrets.NGC_API_KEY }}
1924
2025 steps :
2126 - name : Checkout code
2227 uses : actions/checkout@v6
2328 with :
2429 filter : tree:0
2530
31+ - name : Load OVPhysX wheelhouse configuration
32+ id : config
33+ shell : bash
34+ run : |
35+ set -euo pipefail
36+ resource=$(yq -r .ovphysx_wheelhouse_resource .github/workflows/config.yaml)
37+ echo "wheelhouse_resource=${resource}" >> "$GITHUB_OUTPUT"
38+
39+ - name : Restore NGC CLI cache
40+ uses : actions/cache@v4
41+ with :
42+ path : ${{ runner.temp }}/ngc-cli-cache/ngccli_linux.zip
43+ key : ngc-cli-${{ runner.os }}-${{ runner.arch }}-4.20.0-5cf084c88998c58ad8abf7849d2d1b41d578423886eb03018df10194e341d35b
44+
45+ - name : Extract OVPhysX wheelhouse
46+ id : extract-wheelhouse
47+ shell : bash
48+ env :
49+ WHEELHOUSE_RESOURCE : ${{ steps.config.outputs.wheelhouse_resource }}
50+ run : |
51+ set -euo pipefail
52+
53+ if [ -z "${NGC_API_KEY:-}" ]; then
54+ echo "::error::NGC_API_KEY is unavailable; cannot download the configured OVPhysX wheelhouse"
55+ exit 1
56+ fi
57+
58+ NGC_CLI_VERSION="4.20.0"
59+ NGC_CLI_SHA256="5cf084c88998c58ad8abf7849d2d1b41d578423886eb03018df10194e341d35b"
60+ NGC_CLI_URL="https://api.ngc.nvidia.com/v2/resources/nvidia/ngc-apps/ngc_cli/versions/${NGC_CLI_VERSION}/files/ngccli_linux.zip"
61+
62+ wheelhouse_root="$(mktemp -d "${RUNNER_TEMP:-/tmp}/ovphysx-wheelhouse.XXXXXX")"
63+ download_root="$(mktemp -d "${RUNNER_TEMP:-/tmp}/ovphysx-wheelhouse-download.XXXXXX")"
64+ ngc_home="$(mktemp -d "${RUNNER_TEMP:-/tmp}/ovphysx-ngc-home.XXXXXX")"
65+ ngc_unpack_dir=""
66+ preserve_wheelhouse_root=false
67+ cleanup() {
68+ if [ "$preserve_wheelhouse_root" != "true" ]; then
69+ rm -rf "$wheelhouse_root"
70+ fi
71+ rm -rf "$download_root" "$ngc_home"
72+ if [ -n "$ngc_unpack_dir" ]; then
73+ rm -rf "$ngc_unpack_dir"
74+ fi
75+ }
76+ trap cleanup EXIT
77+
78+ cache_dir="${RUNNER_TEMP:-/tmp}/ngc-cli-cache"
79+ ngc_zip="${cache_dir}/ngccli_linux.zip"
80+ mkdir -p "$cache_dir"
81+ if [ ! -f "$ngc_zip" ]; then
82+ echo "Downloading NGC CLI ${NGC_CLI_VERSION}"
83+ curl -fsSL -o "$ngc_zip" "$NGC_CLI_URL"
84+ fi
85+ echo "${NGC_CLI_SHA256} ${ngc_zip}" | sha256sum -c -
86+ ngc_unpack_dir="$(mktemp -d "${RUNNER_TEMP:-/tmp}/ngc-cli.XXXXXX")"
87+ unzip -q "$ngc_zip" -d "$ngc_unpack_dir"
88+ export PATH="${ngc_unpack_dir}/ngc-cli:${PATH}"
89+
90+ export NGC_CLI_API_KEY="$NGC_API_KEY"
91+ export NGC_CLI_ORG=nvidian
92+ export NGC_CLI_TEAM=no-team
93+ export NGC_CLI_HOME="$ngc_home"
94+
95+ ngc --version
96+ echo "Downloading wheelhouse resource: $WHEELHOUSE_RESOURCE"
97+ ngc registry resource download-version "$WHEELHOUSE_RESOURCE" --dest "$download_root"
98+
99+ mapfile -t manifests < <(find "$download_root" -type f -name manifest.json)
100+ if [ "${#manifests[@]}" -ne 1 ]; then
101+ echo "::error::expected exactly one manifest.json in downloaded wheelhouse resource, found ${#manifests[@]}"
102+ printf '%s\n' "${manifests[@]}"
103+ exit 1
104+ fi
105+
106+ payload_dir="$(dirname "${manifests[0]}")"
107+ if [ ! -d "${payload_dir}/wheelhouse" ]; then
108+ echo "::error::downloaded wheelhouse resource is missing wheelhouse/ next to manifest.json"
109+ exit 1
110+ fi
111+
112+ mkdir -p "$wheelhouse_root/wheelhouse"
113+ cp "${payload_dir}/manifest.json" "$wheelhouse_root/manifest.json"
114+ cp "${payload_dir}/wheelhouse/"*.whl "$wheelhouse_root/wheelhouse/"
115+
116+ python3 - <<'PY' "$wheelhouse_root/manifest.json" "$wheelhouse_root/wheelhouse"
117+ import hashlib
118+ import json
119+ import pathlib
120+ import sys
121+
122+ manifest_path = pathlib.Path(sys.argv[1])
123+ wheelhouse_dir = pathlib.Path(sys.argv[2])
124+ manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
125+
126+ expected = {
127+ "artifact": "ovphysx-wheelhouse",
128+ "platform": "manylinux_2_35_x86_64",
129+ }
130+ for key, value in expected.items():
131+ actual = manifest.get(key)
132+ if actual != value:
133+ raise SystemExit(f"manifest {key!r} mismatch: expected {value!r}, got {actual!r}")
134+
135+ wheels = manifest.get("wheels")
136+ if not isinstance(wheels, list) or not wheels:
137+ raise SystemExit("manifest has no wheels list")
138+
139+ for wheel in wheels:
140+ filename = wheel.get("file")
141+ expected_sha = wheel.get("sha256")
142+ if not filename or not expected_sha:
143+ raise SystemExit(f"invalid wheel manifest entry: {wheel!r}")
144+ wheel_path = wheelhouse_dir / filename
145+ if not wheel_path.is_file():
146+ raise SystemExit(f"manifest wheel is missing from wheelhouse: {filename}")
147+ actual_sha = hashlib.sha256(wheel_path.read_bytes()).hexdigest()
148+ if actual_sha != expected_sha:
149+ raise SystemExit(f"sha256 mismatch for {filename}: expected {expected_sha}, got {actual_sha}")
150+
151+ print(f"Validated {len(wheels)} wheelhouse wheels from {manifest_path}")
152+ PY
153+
154+ echo "wheelhouse_root=$wheelhouse_root" >> "$GITHUB_OUTPUT"
155+ echo "wheelhouse_dir=$wheelhouse_root/wheelhouse" >> "$GITHUB_OUTPUT"
156+
26157 # - name: Install jq
27158 # run: sudo apt-get update && sudo apt-get install -y jq
28159
@@ -60,10 +191,13 @@ jobs:
60191 OMNI_KIT_ACCEPT_EULA : yes
61192 ACCEPT_EULA : Y
62193 ISAACSIM_ACCEPT_EULA : YES
194+ UV_FIND_LINKS : ${{ steps.extract-wheelhouse.outputs.wheelhouse_dir }}
63195 run : |
64196 uv sync --extra all
65- # Isaac Sim isn't in the dev pyproject; sync first so it isn't pruned.
66- uv pip install 'isaacsim[all,extscache]==${{ vars.ISAACSIM_BASE_VERSION || '6.0.0' }}'
197+ # Isaac Sim conflicts with --extra all under uv, so install it imperatively
198+ # after the sync. Read the pinned spec from pyproject (single source of truth).
199+ ISAACSIM_SPEC=$(.venv/bin/python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['optional-dependencies']['isaacsim'][0])")
200+ uv pip install "$ISAACSIM_SPEC"
67201 uv pip install pip-licenses pipdeptree \
68202 -r tools/template/requirements.txt \
69203 -r docs/requirements.txt
@@ -153,3 +287,9 @@ jobs:
153287 else
154288 echo "All packages were checked."
155289 fi
290+
291+ - name : Clean up OVPhysX wheelhouse
292+ if : always()
293+ shell : bash
294+ run : |
295+ rm -rf "${{ steps.extract-wheelhouse.outputs.wheelhouse_root }}"
0 commit comments