From cc5d1b4056bb2d43f0d667161cc8679d18a0077a Mon Sep 17 00:00:00 2001 From: Andrei Aristarkhov Date: Thu, 19 Mar 2026 16:33:16 -0700 Subject: [PATCH 01/17] Unify test and runtime container builds under compose --- deps/cloudxr/docker-compose.test.yaml | 7 ++++++- scripts/run_tests_with_cloudxr.sh | 26 ++++++++++++++------------ 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/deps/cloudxr/docker-compose.test.yaml b/deps/cloudxr/docker-compose.test.yaml index b631cc194..48635b8a4 100644 --- a/deps/cloudxr/docker-compose.test.yaml +++ b/deps/cloudxr/docker-compose.test.yaml @@ -31,8 +31,13 @@ services: capabilities: [ gpu ] # Test runner container - # Build with: docker build -t isaacteleop-tests:latest -f deps/cloudxr/Dockerfile.test . + # Build handled via docker compose using this service's build definition. isaacteleop-tests: + build: + context: ${CXR_BUILD_CONTEXT:?CXR_BUILD_CONTEXT must point to repository root} + dockerfile: deps/cloudxr/Dockerfile.test + args: + PYTHON_VERSION: image: isaacteleop-tests:latest pull_policy: never network_mode: host diff --git a/scripts/run_tests_with_cloudxr.sh b/scripts/run_tests_with_cloudxr.sh index a86b8e24a..6615982fd 100755 --- a/scripts/run_tests_with_cloudxr.sh +++ b/scripts/run_tests_with_cloudxr.sh @@ -248,22 +248,24 @@ fi export EXPECTED_ISAACTELEOP_VERSION log_info "Expected isaacteleop version from wheel artifact: $EXPECTED_ISAACTELEOP_VERSION" -# Build test container -log_info "Building test container..." +# Build CloudXR runtime + test services via compose +log_info "Building CloudXR runtime and test containers..." -BUILD_ARGS="-q" +COMPOSE_BUILD_ARGS="" if [ "$FORCE_BUILD" = true ]; then - BUILD_ARGS="$BUILD_ARGS --no-cache" + COMPOSE_BUILD_ARGS="--no-cache" fi -docker build \ - $BUILD_ARGS \ - --build-arg PYTHON_VERSION="$PYTHON_VERSION" \ - -t isaacteleop-tests:latest \ - -f deps/cloudxr/Dockerfile.test \ - . +docker compose \ + -p "$COMPOSE_PROJECT" \ + --env-file "$ENV_DEFAULT" \ + ${ENV_LOCAL:+--env-file "$ENV_LOCAL"} \ + ${ENV_TEST:+--env-file "$ENV_TEST"} \ + -f "$COMPOSE_RUNTIME" \ + -f "$COMPOSE_TEST" \ + build $COMPOSE_BUILD_ARGS cloudxr-runtime isaacteleop-tests -log_success "Test container built successfully" +log_success "CloudXR runtime and test containers built successfully" # Start CloudXR runtime services log_info "Starting CloudXR runtime services..." @@ -275,7 +277,7 @@ docker compose \ ${ENV_TEST:+--env-file "$ENV_TEST"} \ -f "$COMPOSE_RUNTIME" \ -f "$COMPOSE_TEST" \ - up --build -d cloudxr-runtime + up -d cloudxr-runtime # Wait for CloudXR runtime to be healthy log_info "Waiting for CloudXR runtime to be healthy..." From d4d4fff0addc122cd66e8f3b9ba8c8af43831f02 Mon Sep 17 00:00:00 2001 From: Andrei Aristarkhov Date: Thu, 19 Mar 2026 16:47:51 -0700 Subject: [PATCH 02/17] Add .dockerignore for faster incremental container builds --- .dockerignore | 23 +++++++++++++++++++++++ scripts/run_tests_with_cloudxr.sh | 6 +++--- 2 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..cae64ff81 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,23 @@ +# Keep Docker build contexts lean for CloudXR compose builds. +# Ignore everything by default, then allow only what current Dockerfiles need. + +* + +# Allow Docker metadata files. +!.dockerignore + +# Allow CloudXR Dockerfiles and runtime assets. +!deps/ +!deps/cloudxr/ +!deps/cloudxr/Dockerfile.runtime +!deps/cloudxr/Dockerfile.test +!deps/cloudxr/runtime/ +!deps/cloudxr/runtime/** + +# Allow build artifacts and tests consumed by Dockerfile.test and Dockerfile.runtime. +!install/ +!install/** +!examples/ +!examples/oxr/ +!examples/oxr/python/ +!examples/oxr/python/** diff --git a/scripts/run_tests_with_cloudxr.sh b/scripts/run_tests_with_cloudxr.sh index 6615982fd..b4ced5617 100755 --- a/scripts/run_tests_with_cloudxr.sh +++ b/scripts/run_tests_with_cloudxr.sh @@ -251,9 +251,9 @@ log_info "Expected isaacteleop version from wheel artifact: $EXPECTED_ISAACTELEO # Build CloudXR runtime + test services via compose log_info "Building CloudXR runtime and test containers..." -COMPOSE_BUILD_ARGS="" +COMPOSE_BUILD_ARGS=() if [ "$FORCE_BUILD" = true ]; then - COMPOSE_BUILD_ARGS="--no-cache" + COMPOSE_BUILD_ARGS+=(--no-cache) fi docker compose \ @@ -263,7 +263,7 @@ docker compose \ ${ENV_TEST:+--env-file "$ENV_TEST"} \ -f "$COMPOSE_RUNTIME" \ -f "$COMPOSE_TEST" \ - build $COMPOSE_BUILD_ARGS cloudxr-runtime isaacteleop-tests + build "${COMPOSE_BUILD_ARGS[@]}" cloudxr-runtime isaacteleop-tests log_success "CloudXR runtime and test containers built successfully" From 0522c038d5bfd5a60322dd5d7936d51c69696fed Mon Sep 17 00:00:00 2001 From: Andrei Aristarkhov Date: Thu, 19 Mar 2026 16:53:02 -0700 Subject: [PATCH 03/17] Reorder COPY commands in Dockerfile.test for better caching --- deps/cloudxr/Dockerfile.test | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deps/cloudxr/Dockerfile.test b/deps/cloudxr/Dockerfile.test index fb706dd6f..895ba5ca2 100644 --- a/deps/cloudxr/Dockerfile.test +++ b/deps/cloudxr/Dockerfile.test @@ -21,12 +21,12 @@ WORKDIR /app # Install uv for fast Python package management COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv -# Copy the install directory (contains wheels, libs, native test binaries, etc.) -COPY install/ /app/install/ - # Copy test files COPY examples/oxr/python/ /app/tests/ +# Copy the install directory (contains wheels, libs, native test binaries, etc.) +COPY install/ /app/install/ + # Install Python dependencies using uv WORKDIR /app/tests RUN uv venv --python $PYTHON_VERSION /app/venv && \ From 9c88ae940152cba58dea24ed229d45f3c7de0bc5 Mon Sep 17 00:00:00 2001 From: Andrei Aristarkhov Date: Thu, 19 Mar 2026 16:53:40 -0700 Subject: [PATCH 04/17] Remove redundant WORKDIR command in Dockerfile.test --- deps/cloudxr/Dockerfile.test | 2 -- 1 file changed, 2 deletions(-) diff --git a/deps/cloudxr/Dockerfile.test b/deps/cloudxr/Dockerfile.test index 895ba5ca2..69f8fc777 100644 --- a/deps/cloudxr/Dockerfile.test +++ b/deps/cloudxr/Dockerfile.test @@ -39,7 +39,5 @@ ENV PATH="/app/venv/bin:$PATH" ENV PYTHONPATH="/app/install/lib:$PYTHONPATH" ENV XR_RUNTIME_JSON="/openxr/openxr_cloudxr.json" -WORKDIR /app/tests - # Default command runs the test script CMD ["python", "test_extensions.py"] From d2e4a5bc1021dd9747afd2d67ee56ae4f3871f35 Mon Sep 17 00:00:00 2001 From: Andrei Aristarkhov Date: Thu, 19 Mar 2026 16:59:37 -0700 Subject: [PATCH 05/17] remove redundant lines from .dockerignore --- .dockerignore | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.dockerignore b/.dockerignore index cae64ff81..401f9118a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -7,17 +7,8 @@ !.dockerignore # Allow CloudXR Dockerfiles and runtime assets. -!deps/ !deps/cloudxr/ -!deps/cloudxr/Dockerfile.runtime -!deps/cloudxr/Dockerfile.test -!deps/cloudxr/runtime/ -!deps/cloudxr/runtime/** # Allow build artifacts and tests consumed by Dockerfile.test and Dockerfile.runtime. !install/ -!install/** !examples/ -!examples/oxr/ -!examples/oxr/python/ -!examples/oxr/python/** From 5e3b76417ece9987a31d2ece0662bf365e841fc4 Mon Sep 17 00:00:00 2001 From: Andrei Aristarkhov Date: Thu, 19 Mar 2026 17:01:37 -0700 Subject: [PATCH 06/17] Add src directory to .dockerignore for ros2 workflows --- .dockerignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.dockerignore b/.dockerignore index 401f9118a..1087ca588 100644 --- a/.dockerignore +++ b/.dockerignore @@ -12,3 +12,6 @@ # Allow build artifacts and tests consumed by Dockerfile.test and Dockerfile.runtime. !install/ !examples/ + +# Allow src for ros2 workflows +!src/ From 117451fc96d5c84da655af1ce9297692a7150a1b Mon Sep 17 00:00:00 2001 From: Andrei Aristarkhov Date: Mon, 30 Mar 2026 11:16:26 -0700 Subject: [PATCH 07/17] Allow .git directory in .dockerignore to compute isaacteleop package version --- .dockerignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.dockerignore b/.dockerignore index 1087ca588..45811bc76 100644 --- a/.dockerignore +++ b/.dockerignore @@ -15,3 +15,4 @@ # Allow src for ros2 workflows !src/ +!.git/ From fbbb7fa4f7f75fde946ab1f6b5cde80ca412cdaa Mon Sep 17 00:00:00 2001 From: Andrei Aristarkhov Date: Mon, 30 Mar 2026 11:22:23 -0700 Subject: [PATCH 08/17] Update .dockerignore to allow source builds --- .dockerignore | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.dockerignore b/.dockerignore index 45811bc76..4ef8f2099 100644 --- a/.dockerignore +++ b/.dockerignore @@ -13,6 +13,9 @@ !install/ !examples/ -# Allow src for ros2 workflows -!src/ +# Allow building from source for ros2 workflows !.git/ +!cmake/ +!deps/ +!src/ +!CMakeLists.txt From ea69e7a0f15385a2a682d6f87358b6cd3cad1abc Mon Sep 17 00:00:00 2001 From: Andrei Aristarkhov Date: Mon, 30 Mar 2026 11:29:18 -0700 Subject: [PATCH 09/17] Remove clang-format installation from Dockerfile --- examples/teleop_ros2/Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/teleop_ros2/Dockerfile b/examples/teleop_ros2/Dockerfile index a0fe4352d..81c3f23bc 100644 --- a/examples/teleop_ros2/Dockerfile +++ b/examples/teleop_ros2/Dockerfile @@ -64,7 +64,6 @@ ARG PYTHON_VERSION RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ - clang-format \ cmake \ git \ pkg-config \ From 358a422df2516d2377e89fc0cce41b39f0cb7266 Mon Sep 17 00:00:00 2001 From: Andrei Aristarkhov Date: Mon, 30 Mar 2026 11:41:27 -0700 Subject: [PATCH 10/17] remove git dependency from local version calculation --- cmake/IsaacTeleopVersion.cmake | 208 +++++++++++++++++---------------- 1 file changed, 108 insertions(+), 100 deletions(-) diff --git a/cmake/IsaacTeleopVersion.cmake b/cmake/IsaacTeleopVersion.cmake index b6efc6746..993e66b0c 100644 --- a/cmake/IsaacTeleopVersion.cmake +++ b/cmake/IsaacTeleopVersion.cmake @@ -14,7 +14,6 @@ # * RC (CI + branch release/X.Y.x): branch must match base version; Python version X.Y.PATCHrc, no local. # * Local working copy (non-CI): Python version X.Y+local and CMake version X.Y (patch omitted). function(isaac_teleop_read_version version_file out_cmake_version_var out_pyproject_version_var) - find_package(Git REQUIRED) get_filename_component(_isaac_teleop_version_file "${version_file}" ABSOLUTE) if(NOT EXISTS "${_isaac_teleop_version_file}") message(FATAL_ERROR "Version file not found: ${_isaac_teleop_version_file}") @@ -22,79 +21,12 @@ function(isaac_teleop_read_version version_file out_cmake_version_var out_pyproj file(READ "${_isaac_teleop_version_file}" _isaac_teleop_version_base) string(STRIP "${_isaac_teleop_version_base}" _isaac_teleop_version_base) - execute_process( - COMMAND "${GIT_EXECUTABLE}" -C "${CMAKE_CURRENT_SOURCE_DIR}" rev-parse --show-toplevel - OUTPUT_VARIABLE _isaac_teleop_git_root - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_QUIET - RESULT_VARIABLE _isaac_teleop_git_root_result - ) - if(NOT _isaac_teleop_git_root_result EQUAL 0 OR _isaac_teleop_git_root STREQUAL "") - message(FATAL_ERROR "Failed to determine git root. Ensure this is a git repository and git is available.") - endif() - execute_process( - COMMAND "${GIT_EXECUTABLE}" -C "${_isaac_teleop_git_root}" rev-list -n 1 HEAD -- "${_isaac_teleop_version_file}" - OUTPUT_VARIABLE _isaac_teleop_version_commit - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_QUIET - RESULT_VARIABLE _isaac_teleop_version_commit_result - ) - if(NOT _isaac_teleop_version_commit_result EQUAL 0 OR _isaac_teleop_version_commit STREQUAL "") - message(FATAL_ERROR "Failed to locate last commit for version file: ${_isaac_teleop_version_file}") - endif() - execute_process( - COMMAND "${GIT_EXECUTABLE}" -C "${_isaac_teleop_git_root}" rev-list --count "${_isaac_teleop_version_commit}..HEAD" - OUTPUT_VARIABLE _isaac_teleop_git_count - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_QUIET - RESULT_VARIABLE _isaac_teleop_git_count_result - ) - if(NOT _isaac_teleop_git_count_result EQUAL 0) - message(FATAL_ERROR "Failed to count commits since ${_isaac_teleop_version_commit}.") - endif() - if(NOT _isaac_teleop_git_count MATCHES "^[0-9]+$") - message(FATAL_ERROR "Invalid git commit count: '${_isaac_teleop_git_count}'") - endif() - - execute_process( - COMMAND "${GIT_EXECUTABLE}" -C "${_isaac_teleop_git_root}" rev-parse --abbrev-ref HEAD - OUTPUT_VARIABLE _isaac_teleop_git_branch - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_QUIET - RESULT_VARIABLE _isaac_teleop_git_branch_result - ) - if(NOT _isaac_teleop_git_branch_result EQUAL 0 OR _isaac_teleop_git_branch STREQUAL "") - message(FATAL_ERROR "Failed to determine git branch name.") - endif() - if(_isaac_teleop_git_branch STREQUAL "HEAD") - if(DEFINED ENV{GITHUB_REF_NAME} AND NOT "$ENV{GITHUB_REF_NAME}" STREQUAL "") - set(_isaac_teleop_git_branch "$ENV{GITHUB_REF_NAME}") - elseif(DEFINED ENV{GITHUB_HEAD_REF} AND NOT "$ENV{GITHUB_HEAD_REF}" STREQUAL "") - set(_isaac_teleop_git_branch "$ENV{GITHUB_HEAD_REF}") - elseif(DEFINED ENV{CI_COMMIT_REF_NAME} AND NOT "$ENV{CI_COMMIT_REF_NAME}" STREQUAL "") - set(_isaac_teleop_git_branch "$ENV{CI_COMMIT_REF_NAME}") - endif() - endif() - - execute_process( - COMMAND "${GIT_EXECUTABLE}" -C "${_isaac_teleop_git_root}" describe --tags --exact-match - OUTPUT_VARIABLE _isaac_teleop_git_tag - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_QUIET - RESULT_VARIABLE _isaac_teleop_git_tag_result - ) - if(NOT _isaac_teleop_git_tag_result EQUAL 0) - set(_isaac_teleop_git_tag "") - endif() - string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.x" _isaac_teleop_version_match "${_isaac_teleop_version_base}") if(NOT _isaac_teleop_version_match) message(FATAL_ERROR "Base version must be in MAJOR.MINOR.x format; actual content: '${_isaac_teleop_version_base}'") endif() set(_isaac_teleop_version_major "${CMAKE_MATCH_1}") set(_isaac_teleop_version_minor "${CMAKE_MATCH_2}") - set(_isaac_teleop_version_patch "${_isaac_teleop_git_count}") - set(_isaac_teleop_version "${_isaac_teleop_version_major}.${_isaac_teleop_version_minor}.${_isaac_teleop_version_patch}") set(_isaac_teleop_is_ci FALSE) if(DEFINED ENV{CI} AND NOT "$ENV{CI}" STREQUAL "") @@ -104,46 +36,122 @@ function(isaac_teleop_read_version version_file out_cmake_version_var out_pyproj endif() endif() - set(_isaac_teleop_pyproject_version "") + set(_isaac_teleop_git_count "0") + set(_isaac_teleop_git_branch "") + set(_isaac_teleop_git_tag "") + set(_isaac_teleop_version "${_isaac_teleop_version_major}.${_isaac_teleop_version_minor}") set(_isaac_teleop_build_kind "local") + set(_isaac_teleop_pyproject_version "${_isaac_teleop_version_major}.${_isaac_teleop_version_minor}+local") + + if(_isaac_teleop_is_ci) + find_package(Git REQUIRED) - if(_isaac_teleop_is_ci AND NOT _isaac_teleop_git_tag STREQUAL "") - if(NOT _isaac_teleop_git_tag MATCHES "^v([0-9]+)\\.([0-9]+)\\.([0-9]+)$") - message(FATAL_ERROR "Invalid release tag format: '${_isaac_teleop_git_tag}' (expected vMAJOR.MINOR.PATCH)") + execute_process( + COMMAND "${GIT_EXECUTABLE}" -C "${CMAKE_CURRENT_SOURCE_DIR}" rev-parse --show-toplevel + OUTPUT_VARIABLE _isaac_teleop_git_root + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + RESULT_VARIABLE _isaac_teleop_git_root_result + ) + if(NOT _isaac_teleop_git_root_result EQUAL 0 OR _isaac_teleop_git_root STREQUAL "") + message(FATAL_ERROR "Failed to determine git root. Ensure this is a git repository and git is available.") endif() - set(_isaac_teleop_tag_version "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}") - if(NOT _isaac_teleop_tag_version STREQUAL "${_isaac_teleop_version}") - message(FATAL_ERROR "Release tag ${_isaac_teleop_git_tag} does not match calculated version ${_isaac_teleop_version}.") + execute_process( + COMMAND "${GIT_EXECUTABLE}" -C "${_isaac_teleop_git_root}" rev-list -n 1 HEAD -- "${_isaac_teleop_version_file}" + OUTPUT_VARIABLE _isaac_teleop_version_commit + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + RESULT_VARIABLE _isaac_teleop_version_commit_result + ) + if(NOT _isaac_teleop_version_commit_result EQUAL 0 OR _isaac_teleop_version_commit STREQUAL "") + message(FATAL_ERROR "Failed to locate last commit for version file: ${_isaac_teleop_version_file}") endif() - set(_isaac_teleop_pyproject_version "${_isaac_teleop_tag_version}") - set(_isaac_teleop_build_kind "release") - elseif(_isaac_teleop_is_ci AND _isaac_teleop_git_branch MATCHES "^release/([0-9]+)\\.([0-9]+)\\.x$") - if(NOT "${CMAKE_MATCH_1}" STREQUAL "${_isaac_teleop_version_major}" OR NOT "${CMAKE_MATCH_2}" STREQUAL "${_isaac_teleop_version_minor}") - message(FATAL_ERROR "Release branch ${_isaac_teleop_git_branch} does not match base version ${_isaac_teleop_version_base}.") + execute_process( + COMMAND "${GIT_EXECUTABLE}" -C "${_isaac_teleop_git_root}" rev-list --count "${_isaac_teleop_version_commit}..HEAD" + OUTPUT_VARIABLE _isaac_teleop_git_count + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + RESULT_VARIABLE _isaac_teleop_git_count_result + ) + if(NOT _isaac_teleop_git_count_result EQUAL 0) + message(FATAL_ERROR "Failed to count commits since ${_isaac_teleop_version_commit}.") endif() - set(_isaac_teleop_pyproject_version "${_isaac_teleop_version_major}.${_isaac_teleop_version_minor}.${_isaac_teleop_version_patch}rc1") - set(_isaac_teleop_build_kind "rc") - elseif(_isaac_teleop_is_ci AND _isaac_teleop_git_branch STREQUAL "main") - set(_isaac_teleop_pyproject_version "${_isaac_teleop_version_major}.${_isaac_teleop_version_minor}.${_isaac_teleop_version_patch}a1") - set(_isaac_teleop_build_kind "alpha") - elseif(_isaac_teleop_is_ci) - string(TOLOWER "${_isaac_teleop_git_branch}" _isaac_teleop_label) - string(REGEX REPLACE "[^a-z0-9._-]" "." _isaac_teleop_label "${_isaac_teleop_label}") # replace disallowed chars with dots - string(REGEX REPLACE "[._-]+" "." _isaac_teleop_label "${_isaac_teleop_label}") # collapse separator runs to a single dot - string(REGEX REPLACE "^[._-]+" "" _isaac_teleop_label "${_isaac_teleop_label}") # trim leading separators - string(REGEX REPLACE "[._-]+$" "" _isaac_teleop_label "${_isaac_teleop_label}") # trim trailing separators - if(_isaac_teleop_label STREQUAL "") - set(_isaac_teleop_label "unknown") + if(NOT _isaac_teleop_git_count MATCHES "^[0-9]+$") + message(FATAL_ERROR "Invalid git commit count: '${_isaac_teleop_git_count}'") + endif() + + execute_process( + COMMAND "${GIT_EXECUTABLE}" -C "${_isaac_teleop_git_root}" rev-parse --abbrev-ref HEAD + OUTPUT_VARIABLE _isaac_teleop_git_branch + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + RESULT_VARIABLE _isaac_teleop_git_branch_result + ) + if(NOT _isaac_teleop_git_branch_result EQUAL 0 OR _isaac_teleop_git_branch STREQUAL "") + message(FATAL_ERROR "Failed to determine git branch name.") + endif() + if(_isaac_teleop_git_branch STREQUAL "HEAD") + if(DEFINED ENV{GITHUB_REF_NAME} AND NOT "$ENV{GITHUB_REF_NAME}" STREQUAL "") + set(_isaac_teleop_git_branch "$ENV{GITHUB_REF_NAME}") + elseif(DEFINED ENV{GITHUB_HEAD_REF} AND NOT "$ENV{GITHUB_HEAD_REF}" STREQUAL "") + set(_isaac_teleop_git_branch "$ENV{GITHUB_HEAD_REF}") + elseif(DEFINED ENV{CI_COMMIT_REF_NAME} AND NOT "$ENV{CI_COMMIT_REF_NAME}" STREQUAL "") + set(_isaac_teleop_git_branch "$ENV{CI_COMMIT_REF_NAME}") + endif() + endif() + + execute_process( + COMMAND "${GIT_EXECUTABLE}" -C "${_isaac_teleop_git_root}" describe --tags --exact-match + OUTPUT_VARIABLE _isaac_teleop_git_tag + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + RESULT_VARIABLE _isaac_teleop_git_tag_result + ) + if(NOT _isaac_teleop_git_tag_result EQUAL 0) + set(_isaac_teleop_git_tag "") + endif() + + set(_isaac_teleop_version_patch "${_isaac_teleop_git_count}") + set(_isaac_teleop_version "${_isaac_teleop_version_major}.${_isaac_teleop_version_minor}.${_isaac_teleop_version_patch}") + + if(NOT _isaac_teleop_git_tag STREQUAL "") + if(NOT _isaac_teleop_git_tag MATCHES "^v([0-9]+)\\.([0-9]+)\\.([0-9]+)$") + message(FATAL_ERROR "Invalid release tag format: '${_isaac_teleop_git_tag}' (expected vMAJOR.MINOR.PATCH)") + endif() + set(_isaac_teleop_tag_version "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}") + if(NOT _isaac_teleop_tag_version STREQUAL "${_isaac_teleop_version}") + message(FATAL_ERROR "Release tag ${_isaac_teleop_git_tag} does not match calculated version ${_isaac_teleop_version}.") + endif() + set(_isaac_teleop_pyproject_version "${_isaac_teleop_tag_version}") + set(_isaac_teleop_build_kind "release") + elseif(_isaac_teleop_git_branch MATCHES "^release/([0-9]+)\\.([0-9]+)\\.x$") + if(NOT "${CMAKE_MATCH_1}" STREQUAL "${_isaac_teleop_version_major}" OR NOT "${CMAKE_MATCH_2}" STREQUAL "${_isaac_teleop_version_minor}") + message(FATAL_ERROR "Release branch ${_isaac_teleop_git_branch} does not match base version ${_isaac_teleop_version_base}.") + endif() + set(_isaac_teleop_pyproject_version "${_isaac_teleop_version_major}.${_isaac_teleop_version_minor}.${_isaac_teleop_version_patch}rc1") + set(_isaac_teleop_build_kind "rc") + elseif(_isaac_teleop_git_branch STREQUAL "main") + set(_isaac_teleop_pyproject_version "${_isaac_teleop_version_major}.${_isaac_teleop_version_minor}.${_isaac_teleop_version_patch}a1") + set(_isaac_teleop_build_kind "alpha") + else() + string(TOLOWER "${_isaac_teleop_git_branch}" _isaac_teleop_label) + string(REGEX REPLACE "[^a-z0-9._-]" "." _isaac_teleop_label "${_isaac_teleop_label}") # replace disallowed chars with dots + string(REGEX REPLACE "[._-]+" "." _isaac_teleop_label "${_isaac_teleop_label}") # collapse separator runs to a single dot + string(REGEX REPLACE "^[._-]+" "" _isaac_teleop_label "${_isaac_teleop_label}") # trim leading separators + string(REGEX REPLACE "[._-]+$" "" _isaac_teleop_label "${_isaac_teleop_label}") # trim trailing separators + if(_isaac_teleop_label STREQUAL "") + set(_isaac_teleop_label "unknown") + endif() + set(_isaac_teleop_pyproject_version "${_isaac_teleop_version_major}.${_isaac_teleop_version_minor}.${_isaac_teleop_version_patch}.dev0+${_isaac_teleop_label}") + set(_isaac_teleop_build_kind "dev") endif() - set(_isaac_teleop_pyproject_version "${_isaac_teleop_version_major}.${_isaac_teleop_version_minor}.${_isaac_teleop_version_patch}.dev0+${_isaac_teleop_label}") - set(_isaac_teleop_build_kind "dev") - else() - set(_isaac_teleop_pyproject_version "${_isaac_teleop_version_major}.${_isaac_teleop_version_minor}+local") - set(_isaac_teleop_build_kind "local") - set(_isaac_teleop_version "${_isaac_teleop_version_major}.${_isaac_teleop_version_minor}") endif() set(${out_cmake_version_var} "${_isaac_teleop_version}" PARENT_SCOPE) set(${out_pyproject_version_var} "${_isaac_teleop_pyproject_version}" PARENT_SCOPE) - message(STATUS "IsaacTeleop version: ${_isaac_teleop_version} (${_isaac_teleop_version_base} + ${_isaac_teleop_git_count} commits) python: ${_isaac_teleop_pyproject_version} kind: ${_isaac_teleop_build_kind}") + if(_isaac_teleop_is_ci) + message(STATUS "IsaacTeleop version: ${_isaac_teleop_version} (${_isaac_teleop_version_base} + ${_isaac_teleop_git_count} commits) python: ${_isaac_teleop_pyproject_version} kind: ${_isaac_teleop_build_kind}") + else() + message(STATUS "IsaacTeleop version: ${_isaac_teleop_version} (${_isaac_teleop_version_base}; local build) python: ${_isaac_teleop_pyproject_version} kind: ${_isaac_teleop_build_kind}") + endif() endfunction() From d3ed299696ade04a20eadc92404de66231f78835 Mon Sep 17 00:00:00 2001 From: Andrei Aristarkhov Date: Mon, 30 Mar 2026 11:42:30 -0700 Subject: [PATCH 11/17] Remove git installation from Dockerfile and update .dockerignore to allow VERSION file --- .dockerignore | 2 +- examples/teleop_ros2/Dockerfile | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.dockerignore b/.dockerignore index 4ef8f2099..279452a02 100644 --- a/.dockerignore +++ b/.dockerignore @@ -14,8 +14,8 @@ !examples/ # Allow building from source for ros2 workflows -!.git/ !cmake/ !deps/ !src/ !CMakeLists.txt +!VERSION diff --git a/examples/teleop_ros2/Dockerfile b/examples/teleop_ros2/Dockerfile index 81c3f23bc..338b92d13 100644 --- a/examples/teleop_ros2/Dockerfile +++ b/examples/teleop_ros2/Dockerfile @@ -65,7 +65,6 @@ ARG PYTHON_VERSION RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ cmake \ - git \ pkg-config \ && rm -rf /var/lib/apt/lists/* From ebae3f307fd72981eee44d424c511b136b380bbc Mon Sep 17 00:00:00 2001 From: Andrei Aristarkhov Date: Mon, 30 Mar 2026 12:40:24 -0700 Subject: [PATCH 12/17] Update Docker Buildx action to version 4.0.0 in build workflow --- .github/workflows/build-ubuntu.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-ubuntu.yml b/.github/workflows/build-ubuntu.yml index 5c1f91411..21dee3151 100644 --- a/.github/workflows/build-ubuntu.yml +++ b/.github/workflows/build-ubuntu.yml @@ -165,7 +165,7 @@ jobs: ngc-cli-api-key: ${{ secrets.NGC_TELEOP_CORE_GITHUB_SERVICE_KEY }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v4.0.0 - name: Build teleop_ros2 image run: | @@ -208,7 +208,7 @@ jobs: tar -xvf isaacteleop-install.tar -C install - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v4.0.0 - name: Run Tests with CloudXR env: From a161b0b3bec074548a1473771409091e57a354ab Mon Sep 17 00:00:00 2001 From: Andrei Aristarkhov Date: Mon, 30 Mar 2026 12:45:46 -0700 Subject: [PATCH 13/17] Update Docker build step to use build-push-action for teleop_ros2 image --- .github/workflows/build-ubuntu.yml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-ubuntu.yml b/.github/workflows/build-ubuntu.yml index 21dee3151..59b647a66 100644 --- a/.github/workflows/build-ubuntu.yml +++ b/.github/workflows/build-ubuntu.yml @@ -168,11 +168,18 @@ jobs: uses: docker/setup-buildx-action@v4.0.0 - name: Build teleop_ros2 image - run: | - docker build -f examples/teleop_ros2/Dockerfile \ - --build-arg ROS_DISTRO=${{ matrix.ros_distro }} \ - --build-arg PYTHON_VERSION=${{ matrix.python_version }} \ - -t teleop_ros2_ref:${{ matrix.ros_distro }} . + uses: docker/build-push-action@v7 + with: + context: . + file: examples/teleop_ros2/Dockerfile + build-args: | + ROS_DISTRO=${{ matrix.ros_distro }} + PYTHON_VERSION=${{ matrix.python_version }} + tags: teleop_ros2_ref:${{ matrix.ros_distro }} + load: true + push: false + cache-from: type=gha,scope=teleop-ros2-${{ matrix.ros_distro }} + cache-to: type=gha,mode=max,scope=teleop-ros2-${{ matrix.ros_distro }} - name: Smoke test (ROS 2 + rclpy) run: | From c7973c4ad62f29de8456a7db7fe717770da241b8 Mon Sep 17 00:00:00 2001 From: Andrei Aristarkhov Date: Mon, 30 Mar 2026 12:59:35 -0700 Subject: [PATCH 14/17] Clean up build artifacts after installation in Dockerfile --- examples/teleop_ros2/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/teleop_ros2/Dockerfile b/examples/teleop_ros2/Dockerfile index 338b92d13..24df9caf7 100644 --- a/examples/teleop_ros2/Dockerfile +++ b/examples/teleop_ros2/Dockerfile @@ -83,7 +83,8 @@ RUN --mount=type=cache,target=/opt/isaacteleop/build,id=isaacteleop-teleop-ros2- -DENABLE_CLANG_FORMAT_CHECK=OFF \ -DISAAC_TELEOP_PYTHON_VERSION=${PYTHON_VERSION} \ && cmake --build build --config Release -j$(nproc) \ - && cmake --install build --config Release + && cmake --install build --config Release \ + && rm -rf build COPY --chmod=644 < Date: Mon, 30 Mar 2026 13:15:59 -0700 Subject: [PATCH 15/17] Update cache mode in build workflow and simplify Dockerfile build steps --- .github/workflows/build-ubuntu.yml | 2 +- examples/teleop_ros2/Dockerfile | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-ubuntu.yml b/.github/workflows/build-ubuntu.yml index 59b647a66..a9c1c55ba 100644 --- a/.github/workflows/build-ubuntu.yml +++ b/.github/workflows/build-ubuntu.yml @@ -179,7 +179,7 @@ jobs: load: true push: false cache-from: type=gha,scope=teleop-ros2-${{ matrix.ros_distro }} - cache-to: type=gha,mode=max,scope=teleop-ros2-${{ matrix.ros_distro }} + cache-to: type=gha,mode=min,scope=teleop-ros2-${{ matrix.ros_distro }} - name: Smoke test (ROS 2 + rclpy) run: | diff --git a/examples/teleop_ros2/Dockerfile b/examples/teleop_ros2/Dockerfile index 24df9caf7..338b92d13 100644 --- a/examples/teleop_ros2/Dockerfile +++ b/examples/teleop_ros2/Dockerfile @@ -83,8 +83,7 @@ RUN --mount=type=cache,target=/opt/isaacteleop/build,id=isaacteleop-teleop-ros2- -DENABLE_CLANG_FORMAT_CHECK=OFF \ -DISAAC_TELEOP_PYTHON_VERSION=${PYTHON_VERSION} \ && cmake --build build --config Release -j$(nproc) \ - && cmake --install build --config Release \ - && rm -rf build + && cmake --install build --config Release COPY --chmod=644 < Date: Mon, 30 Mar 2026 16:21:51 -0700 Subject: [PATCH 16/17] Use caching only for teleop_ros2 base stage in Docker build workflow --- .github/workflows/build-ubuntu.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-ubuntu.yml b/.github/workflows/build-ubuntu.yml index a9c1c55ba..510b3ea72 100644 --- a/.github/workflows/build-ubuntu.yml +++ b/.github/workflows/build-ubuntu.yml @@ -167,6 +167,19 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4.0.0 + - name: Cache teleop_ros2 base stage + uses: docker/build-push-action@v7 + with: + context: . + file: examples/teleop_ros2/Dockerfile + target: base + build-args: | + ROS_DISTRO=${{ matrix.ros_distro }} + PYTHON_VERSION=${{ matrix.python_version }} + cache-from: type=gha,scope=teleop-ros2-base-${{ matrix.ros_distro }}-py${{ matrix.python_version }} + cache-to: type=gha,mode=max,scope=teleop-ros2-base-${{ matrix.ros_distro }}-py${{ matrix.python_version }} + outputs: type=cacheonly + - name: Build teleop_ros2 image uses: docker/build-push-action@v7 with: @@ -178,8 +191,7 @@ jobs: tags: teleop_ros2_ref:${{ matrix.ros_distro }} load: true push: false - cache-from: type=gha,scope=teleop-ros2-${{ matrix.ros_distro }} - cache-to: type=gha,mode=min,scope=teleop-ros2-${{ matrix.ros_distro }} + cache-from: type=gha,scope=teleop-ros2-base-${{ matrix.ros_distro }}-py${{ matrix.python_version }} - name: Smoke test (ROS 2 + rclpy) run: | From 8ee44eb58fca806213400ddaa7029d27d0b825dc Mon Sep 17 00:00:00 2001 From: Andrei Aristarkhov Date: Mon, 30 Mar 2026 16:53:29 -0700 Subject: [PATCH 17/17] Refactor Docker build step for teleop_ros2 image to use direct docker command --- .github/workflows/build-ubuntu.yml | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build-ubuntu.yml b/.github/workflows/build-ubuntu.yml index 510b3ea72..c596c6b58 100644 --- a/.github/workflows/build-ubuntu.yml +++ b/.github/workflows/build-ubuntu.yml @@ -176,22 +176,18 @@ jobs: build-args: | ROS_DISTRO=${{ matrix.ros_distro }} PYTHON_VERSION=${{ matrix.python_version }} + tags: teleop_ros2_base:${{ matrix.ros_distro }}-py${{ matrix.python_version }} + load: true + push: false cache-from: type=gha,scope=teleop-ros2-base-${{ matrix.ros_distro }}-py${{ matrix.python_version }} cache-to: type=gha,mode=max,scope=teleop-ros2-base-${{ matrix.ros_distro }}-py${{ matrix.python_version }} - outputs: type=cacheonly - name: Build teleop_ros2 image - uses: docker/build-push-action@v7 - with: - context: . - file: examples/teleop_ros2/Dockerfile - build-args: | - ROS_DISTRO=${{ matrix.ros_distro }} - PYTHON_VERSION=${{ matrix.python_version }} - tags: teleop_ros2_ref:${{ matrix.ros_distro }} - load: true - push: false - cache-from: type=gha,scope=teleop-ros2-base-${{ matrix.ros_distro }}-py${{ matrix.python_version }} + run: | + docker build -f examples/teleop_ros2/Dockerfile \ + --build-arg ROS_DISTRO=${{ matrix.ros_distro }} \ + --build-arg PYTHON_VERSION=${{ matrix.python_version }} \ + -t teleop_ros2_ref:${{ matrix.ros_distro }} . - name: Smoke test (ROS 2 + rclpy) run: |