Skip to content

Verify optional ROS 2 overlay template #41

Verify optional ROS 2 overlay template

Verify optional ROS 2 overlay template #41

name: verify_template_ros2_overlay
run-name: Verify optional ROS 2 overlay template
on:
workflow_dispatch:
push:
branches:
- "master"
- "main"
- "develop"
tags:
- "v*.*.*"
paths:
- CMakeLists.txt
- cmake/**
- src/**
- ros2/**
- build_ros2.sh
- add_ros2_support.sh
- generate_version.sh
- tailor_template_cleanup.sh
- doc/ros2_overlay.md
- doc/template_usage.md
- doc/bootstrap_prompts.md
- README.md
- AGENTS.md
- CLAUDE.md
- python/COLCON_IGNORE
- lib/COLCON_IGNORE
- examples/COLCON_IGNORE
- tests/COLCON_IGNORE
- tests/cmake/VerifyTemplateProjectRos2Overlay.cmake
- tests/cmake/VerifyTemplateProjectNestedInstallHeaders.cmake
- tests/cmake/VerifyTemplateProjectCudaSources.cmake
- tests/template_test/testRos2OverlayStatic.py
- tests/template_test/testWorkflowTemplates.py
- .github/workflows/build_ros2_overlay.yml
- .github/workflows/build_ros2_overlay.yml.tpl
pull_request:
branches:
- "master"
- "main"
- "develop"
- "dev*"
paths:
- CMakeLists.txt
- cmake/**
- src/**
- ros2/**
- build_ros2.sh
- add_ros2_support.sh
- generate_version.sh
- tailor_template_cleanup.sh
- doc/ros2_overlay.md
- doc/template_usage.md
- doc/bootstrap_prompts.md
- README.md
- AGENTS.md
- CLAUDE.md
- python/COLCON_IGNORE
- lib/COLCON_IGNORE
- examples/COLCON_IGNORE
- tests/COLCON_IGNORE
- tests/cmake/VerifyTemplateProjectRos2Overlay.cmake
- tests/cmake/VerifyTemplateProjectNestedInstallHeaders.cmake
- tests/cmake/VerifyTemplateProjectCudaSources.cmake
- tests/template_test/testRos2OverlayStatic.py
- tests/template_test/testWorkflowTemplates.py
- .github/workflows/build_ros2_overlay.yml
- .github/workflows/build_ros2_overlay.yml.tpl
jobs:
overlay-build:
runs-on: ubuntu-24.04
container:
image: ros:jazzy
steps:
- name: Checkout repository
id: checkout_repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Trust checked-out Git worktree
id: trust_worktree
shell: bash
run: |
git config --global --add safe.directory "${GITHUB_WORKSPACE}"
git -C "${GITHUB_WORKSPACE}" rev-parse --is-inside-work-tree
- name: Install ROS 2 overlay dependencies
id: install_dependencies
run: |
apt-get update
apt-get install -y --no-install-recommends build-essential cmake git libeigen3-dev python3-colcon-common-extensions python3-pytest python3-yaml ros-dev-tools
- name: Synchronize ROS package metadata
id: sync_metadata
shell: bash
run: |
test -x ./generate_version.sh || {
echo "::error::generate_version.sh is missing or not executable."
exit 1
}
./generate_version.sh --sync-ros2
git diff --exit-code -- ros2/*/package.xml
- name: Resolve ROS 2 package dependencies
id: resolve_dependencies
run: |
rosdep update
rosdep install --from-paths ros2 -i -r -y --rosdistro jazzy
- name: Build and test ROS 2 overlay
id: build_overlay
shell: bash
run: ./build_ros2.sh --clean --no-version-sync
- name: Verify installed core header layout
id: verify_install_layout
shell: bash
run: |
metadata_dir_="${RUNNER_TEMP}/ros2-install-metadata"
cmake -S . -B "${metadata_dir_}" -DPROJECT_METADATA_ONLY=ON
core_cmake_name_="$(python3 - "${metadata_dir_}/CMakeCache.txt" <<'PY'
from pathlib import Path
import sys
values_ = {}
for line_ in Path(sys.argv[1]).read_text(encoding="utf-8").splitlines():
key_and_type_, separator_, value_ = line_.partition("=")
if not separator_:
continue
key_, type_separator_, _ = key_and_type_.partition(":")
if type_separator_:
values_[key_] = value_
print(values_["CMAKE_PROJECT_NAME"])
PY
)"
mapfile -t core_headers_ < <(
find ros2/install -type f \
-path "*/include/${core_cmake_name_}/wrapped_impl/CWrapperPlaceholder.h" \
-print
)
if [[ "${#core_headers_[@]}" -ne 1 ]]; then
echo "Expected exactly one installed core header, found ${#core_headers_[@]}." >&2
exit 1
fi
core_relative_path_="${core_headers_[0]#ros2/install/}"
core_ros_package_="${core_relative_path_%%/*}"
test ! -e "ros2/install/${core_ros_package_}/wrapped_impl/CWrapperPlaceholder.h" || {
echo "Core header leaked to the package install-prefix root." >&2
exit 1
}
- name: Run static ROS 2 overlay checks
id: static_contracts
shell: bash
run: |
python3 -m pytest -q \
tests/template_test/testRos2OverlayStatic.py \
tests/template_test/testWorkflowTemplates.py
expected_version="$(python3 - VERSION <<'PY'
from pathlib import Path
import sys
fields_ = {}
for line_ in Path(sys.argv[1]).read_text(encoding="utf-8").splitlines():
key_, separator_, value_ = line_.partition(":")
if separator_:
fields_[key_.strip()] = value_.strip()
version_ = fields_["Project version core"]
components_ = version_.split(".")
if len(components_) != 3 or not all(component_.isdecimal() for component_ in components_):
raise SystemExit("VERSION lacks a strict X.Y.Z project version core")
print(version_)
PY
)"
cmake \
-DTEST_TEMPLATE_SOURCE_DIR="${PWD}" \
-DTEST_BINARY_ROOT="${RUNNER_TEMP}/ros2_overlay_static" \
-DEXPECTED_VERSION="${expected_version}" \
-P tests/cmake/VerifyTemplateProjectRos2Overlay.cmake
rollout-rehearsal:
runs-on: ubuntu-24.04
container:
image: ros:jazzy
steps:
- name: Checkout repository
id: checkout_repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Trust checked-out Git worktree
id: trust_worktree
shell: bash
run: |
git config --global --add safe.directory "${GITHUB_WORKSPACE}"
git -C "${GITHUB_WORKSPACE}" rev-parse --is-inside-work-tree
- name: Install ROS 2 overlay dependencies
id: install_dependencies
run: |
apt-get update
apt-get install -y --no-install-recommends build-essential cmake git libeigen3-dev python3-colcon-common-extensions python3-pytest python3-yaml ros-dev-tools
- name: Synchronize ROS package metadata
id: sync_metadata
shell: bash
run: |
test -x ./generate_version.sh || {
echo "::error::generate_version.sh is missing or not executable."
exit 1
}
./generate_version.sh --sync-ros2
git diff --exit-code -- ros2/*/package.xml
- name: Resolve ROS 2 package dependencies
id: resolve_dependencies
run: |
rosdep update
rosdep install --from-paths ros2 -i -r -y --rosdistro jazzy
- name: Rehearse default-tailored overlay
id: tailored_overlay
shell: bash
run: |
set -Eeuo pipefail
scratch_dir="$(mktemp -d)"
target_dir="${scratch_dir}/target"
git clone --no-local "${GITHUB_WORKSPACE}" "${target_dir}"
git -C "${target_dir}" checkout --detach "${GITHUB_SHA}"
(cd "${target_dir}" && ./tailor_template_cleanup.sh --apply --yes --project-namespace tailored_project)
test -f "${target_dir}/.github/workflows/build_ros2_overlay.yml"
test ! -e "${target_dir}/.github/workflows/build_ros2_overlay.yml.tpl"
(cd "${target_dir}" && ./build_ros2.sh --clean --no-version-sync)
- name: Rehearse additive rollout
id: additive_rollout
shell: bash
run: |
set -Eeuo pipefail
scratch_dir="$(mktemp -d)"
target_dir="${scratch_dir}/target"
git clone --no-local "${GITHUB_WORKSPACE}" "${target_dir}"
git -C "${target_dir}" checkout --detach "${GITHUB_SHA}"
(cd "${target_dir}" && ./tailor_template_cleanup.sh --apply --yes --project-namespace tailored_project --remove-ros2)
./add_ros2_support.sh --root "${target_dir}" --apply --yes --verify
(cd "${target_dir}" && ./build_ros2.sh --clean --no-version-sync)
(cd "${target_dir}" && cmake -S . -B build_plain -DENABLE_TESTS=OFF && cmake --build build_plain -j2)