From a785fb7df9a46f0744c15d60b57d0f19d05b6ff3 Mon Sep 17 00:00:00 2001 From: Minggang Wang Date: Fri, 1 May 2026 18:42:43 +0800 Subject: [PATCH 01/10] Add ROS 2 Lyrical Luth --- .../workflows/linux-x64-build-and-test.yml | 56 ++++++++++--------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/.github/workflows/linux-x64-build-and-test.yml b/.github/workflows/linux-x64-build-and-test.yml index 3b67083a..c90bc0a7 100644 --- a/.github/workflows/linux-x64-build-and-test.yml +++ b/.github/workflows/linux-x64-build-and-test.yml @@ -17,6 +17,7 @@ jobs: runs-on: ubuntu-latest container: image: ${{ matrix.docker_image }} + continue-on-error: ${{ matrix.experimental == true }} strategy: fail-fast: false matrix: @@ -26,6 +27,7 @@ jobs: - humble - jazzy - kilted + - lyrical - rolling include: # Humble Hawksbill (May 2022 - May 2027) @@ -37,6 +39,11 @@ jobs: # Kilted Kaiju (May 2025 - Dec 2026) - docker_image: ubuntu:noble ros_distribution: kilted + # Lyrical Luth (May 2026 - May 2031, beta) - allow-failure until packages stabilize + - docker_image: ubuntu:26.04 + ros_distribution: lyrical + experimental: true + ros_tar_url: "https://github.com/ros2/ros2/releases/download/release-lyrical-beta-20260429-1/ros2-lyrical-2026-04-29-1-resolute-x86_64.tar.bz2" # Rolling Ridley (No End-Of-Life) - migrated to Ubuntu 26.04 (resolute) # to follow the Lyrical Luth target platform. # See: https://docs.ros.org/en/jazzy/Releases/Release-Lyrical-Luth.html @@ -51,40 +58,46 @@ jobs: architecture: ${{ matrix.architecture }} - name: Setup ROS2 - if: ${{ matrix.ros_distribution != 'rolling' }} + if: ${{ matrix.ros_distribution != 'rolling' && matrix.ros_distribution != 'lyrical' }} uses: ros-tooling/setup-ros@v0.7 with: required-ros-distributions: ${{ matrix.ros_distribution }} - - name: Install ROS2 Rolling Nightly - if: ${{ matrix.ros_distribution == 'rolling' }} + - name: Enable ROS2 apt repository (rolling / lyrical) + if: ${{ matrix.ros_distribution == 'rolling' || matrix.ros_distribution == 'lyrical' }} run: | apt-get update apt-get install -y software-properties-common curl - # Enable required repositories (per https://docs.ros.org/en/rolling/Installation/Alternatives/Ubuntu-Install-Binary.html) + # Enable required repositories (per https://docs.ros.org/en/lyrical/Installation/Ubuntu-Install-Debs.html) add-apt-repository universe ROS_APT_SOURCE_VERSION=$(curl -s https://api.github.com/repos/ros-infrastructure/ros-apt-source/releases/latest | grep -F "tag_name" | awk -F'"' '{print $4}') curl -L -o /tmp/ros2-apt-source.deb "https://github.com/ros-infrastructure/ros-apt-source/releases/download/${ROS_APT_SOURCE_VERSION}/ros2-apt-source_${ROS_APT_SOURCE_VERSION}.$(. /etc/os-release && echo ${UBUNTU_CODENAME:-${VERSION_CODENAME}})_all.deb" dpkg -i /tmp/ros2-apt-source.deb - - # Install prerequisites and apt packages BEFORE nightly tarball apt-get update apt-get install -y build-essential cmake tar bzip2 python3 python3-rosdep python3-colcon-common-extensions - # Extract nightly binary AFTER apt packages so nightly's newer libs overwrite apt's older ones - curl -sL "${{ matrix.ros_tar_url }}" -o /tmp/ros2-nightly.tar.bz2 - mkdir -p /opt/ros/rolling - tar xf /tmp/ros2-nightly.tar.bz2 --strip-components=1 -C /opt/ros/rolling - rm /tmp/ros2-nightly.tar.bz2 + - name: Install ROS2 from binary tarball (rolling / lyrical) + if: ${{ matrix.ros_distribution == 'rolling' || matrix.ros_distribution == 'lyrical' }} + run: | + # Install apt packages BEFORE the binary tarball + apt-get install -y ros-${{ matrix.ros_distribution }}-test-msgs + # mrpt_msgs may not be available for newer/beta distros (e.g. lyrical); install best-effort + apt-get install -y ros-${{ matrix.ros_distribution }}-mrpt-msgs || echo "ros-${{ matrix.ros_distribution }}-mrpt-msgs not yet available, skipping" + + # Extract binary tarball AFTER apt packages so its newer libs overwrite apt's older ones + curl -sL "${{ matrix.ros_tar_url }}" -o /tmp/ros2-${{ matrix.ros_distribution }}.tar.bz2 + mkdir -p /opt/ros/${{ matrix.ros_distribution }} + tar xf /tmp/ros2-${{ matrix.ros_distribution }}.tar.bz2 --strip-components=1 -C /opt/ros/${{ matrix.ros_distribution }} + rm /tmp/ros2-${{ matrix.ros_distribution }}.tar.bz2 # Install any remaining runtime dependencies using rosdep rosdep init || true rosdep update - rosdep install --rosdistro rolling --from-paths /opt/ros/rolling/share --ignore-src -y --skip-keys "cyclonedds fastcdr fastdds iceoryx_binding_c rmw_connextdds rti-connext-dds-7.3.0 rti-connext-dds-7.7.0 urdfdom_headers python3-pyqt6.qtsvg rosidl_buffer_py pybind11" + rosdep install --rosdistro ${{ matrix.ros_distribution }} --from-paths /opt/ros/${{ matrix.ros_distribution }}/share --ignore-src -y --skip-keys "cyclonedds fastcdr fastdds iceoryx_binding_c rmw_connextdds rti-connext-dds-7.3.0 rti-connext-dds-7.7.0 urdfdom_headers python3-pyqt6.qtsvg rosidl_buffer_py pybind11" - name: Install test-msgs and mrpt_msgs on Linux - if: ${{ matrix.ros_distribution != 'rolling' }} + if: ${{ matrix.ros_distribution != 'rolling' && matrix.ros_distribution != 'lyrical' }} run: | sudo apt install -y ros-${{ matrix.ros_distribution }}-test-msgs ros-${{ matrix.ros_distribution }}-mrpt-msgs @@ -101,18 +114,7 @@ jobs: - uses: actions/checkout@v6 - - name: Build and test rclnodejs (nightly) - if: ${{ matrix.ros_distribution == 'rolling' }} - run: | - uname -a - source /opt/ros/rolling/setup.bash - npm i - npm run lint - npm test - npm run clean - - name: Build and test rclnodejs - if: ${{ matrix.ros_distribution != 'rolling' }} run: | uname -a source /opt/ros/${{ matrix.ros_distribution }}/setup.bash @@ -121,10 +123,10 @@ jobs: npm test npm run clean - - name: Test with IDL ROS messages against rolling - if: ${{ matrix.ros_distribution == 'rolling' }} + - name: Test with IDL ROS messages (rolling / lyrical) + if: ${{ matrix.ros_distribution == 'rolling' || matrix.ros_distribution == 'lyrical' }} run: | - source /opt/ros/rolling/setup.bash + source /opt/ros/${{ matrix.ros_distribution }}/setup.bash npm i npm run test-idl npm run clean From cb8ca6ade943127ab54362e44eb9c1528956db98 Mon Sep 17 00:00:00 2001 From: Minggang Wang Date: Fri, 1 May 2026 18:58:32 +0800 Subject: [PATCH 02/10] Address comments --- .github/workflows/linux-x64-build-and-test.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linux-x64-build-and-test.yml b/.github/workflows/linux-x64-build-and-test.yml index c90bc0a7..ab2c920f 100644 --- a/.github/workflows/linux-x64-build-and-test.yml +++ b/.github/workflows/linux-x64-build-and-test.yml @@ -80,10 +80,12 @@ jobs: - name: Install ROS2 from binary tarball (rolling / lyrical) if: ${{ matrix.ros_distribution == 'rolling' || matrix.ros_distribution == 'lyrical' }} run: | - # Install apt packages BEFORE the binary tarball - apt-get install -y ros-${{ matrix.ros_distribution }}-test-msgs - # mrpt_msgs may not be available for newer/beta distros (e.g. lyrical); install best-effort - apt-get install -y ros-${{ matrix.ros_distribution }}-mrpt-msgs || echo "ros-${{ matrix.ros_distribution }}-mrpt-msgs not yet available, skipping" + # Install apt packages BEFORE the binary tarball (rolling only; + # test-msgs / mrpt-msgs are not yet published for lyrical and + # test_msgs is bundled in the lyrical tarball itself). + if [ "${{ matrix.ros_distribution }}" = "rolling" ]; then + apt-get install -y ros-rolling-test-msgs ros-rolling-mrpt-msgs + fi # Extract binary tarball AFTER apt packages so its newer libs overwrite apt's older ones curl -sL "${{ matrix.ros_tar_url }}" -o /tmp/ros2-${{ matrix.ros_distribution }}.tar.bz2 From dae156541bb80dfcac048f2112242da7d644634a Mon Sep 17 00:00:00 2001 From: Minggang Wang Date: Fri, 1 May 2026 19:29:18 +0800 Subject: [PATCH 03/10] Address comments --- lib/action/client.js | 9 +++++---- lib/node.js | 4 ++-- lib/subscription.js | 4 ++-- src/rcl_action_client_bindings.cpp | 8 ++++---- src/rcl_lifecycle_bindings.cpp | 2 +- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/lib/action/client.js b/lib/action/client.js index 28c5fd7a..d866a1a6 100644 --- a/lib/action/client.js +++ b/lib/action/client.js @@ -94,12 +94,13 @@ class ActionClient extends Entity { }; // Enable feedback subscription content filter optimization. - // Only supported on ROS2 Rolling and only effective when the native - // binding provides the required functions AND the RMW implementation - // actually supports content filtering on the feedback subscription. + // Only supported on ROS2 Lyrical or newer and only effective when the + // native binding provides the required functions AND the RMW + // implementation actually supports content filtering on the feedback + // subscription. this._enableFeedbackMsgOptimization = this._options.enableFeedbackMsgOptimization === true && - DistroUtils.getDistroId() >= DistroUtils.DistroId.ROLLING && + DistroUtils.getDistroId() >= DistroUtils.DistroId.LYRICAL && typeof rclnodejs.actionConfigureFeedbackSubFilterAddGoalId === 'function'; let type = this.typeClass.type(); diff --git a/lib/node.js b/lib/node.js index 2bc01ae7..d1b49fe0 100644 --- a/lib/node.js +++ b/lib/node.js @@ -1587,7 +1587,7 @@ class Node extends rclnodejs.ShadowNode { * @returns {Array} - list of clients */ getClientsInfoByService(service, noDemangle = false) { - if (DistroUtils.getDistroId() < DistroUtils.DistroId.ROLLING) { + if (DistroUtils.getDistroId() < DistroUtils.DistroId.LYRICAL) { console.warn( 'getClientsInfoByService is not supported by this version of ROS 2' ); @@ -1621,7 +1621,7 @@ class Node extends rclnodejs.ShadowNode { * @returns {Array} - list of servers */ getServersInfoByService(service, noDemangle = false) { - if (DistroUtils.getDistroId() < DistroUtils.DistroId.ROLLING) { + if (DistroUtils.getDistroId() < DistroUtils.DistroId.LYRICAL) { console.warn( 'getServersInfoByService is not supported by this version of ROS 2' ); diff --git a/lib/subscription.js b/lib/subscription.js index 8cd3a214..97eb4765 100644 --- a/lib/subscription.js +++ b/lib/subscription.js @@ -147,11 +147,11 @@ class Subscription extends Entity { /** * Check if content filtering is supported for this subscription. - * Requires ROS 2 Rolling or later. + * Requires ROS 2 Lyrical or later. * @returns {boolean} True if the subscription instance supports content filtering; otherwise false. */ isContentFilterSupported() { - if (DistroUtils.getDistroId() < DistroUtils.DistroId.ROLLING) { + if (DistroUtils.getDistroId() < DistroUtils.DistroId.LYRICAL) { return false; } return rclnodejs.isContentFilterSupported(this.handle); diff --git a/src/rcl_action_client_bindings.cpp b/src/rcl_action_client_bindings.cpp index 560b33f4..b106f8c9 100644 --- a/src/rcl_action_client_bindings.cpp +++ b/src/rcl_action_client_bindings.cpp @@ -250,7 +250,7 @@ Napi::Value ActionSendCancelRequest(const Napi::CallbackInfo& info) { return Napi::Number::New(env, static_cast(sequence_number)); } -#if ROS_VERSION >= 5000 // ROS2 Rolling +#if ROS_VERSION >= 2605 // ROS2 Lyrical or newer Napi::Value ActionConfigureFeedbackSubFilterAddGoalId( const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); @@ -309,7 +309,7 @@ Napi::Value ActionConfigureFeedbackSubFilterRemoveGoalId( return Napi::Boolean::New(env, true); } -#endif // ROS_VERSION >= 5000 +#endif // ROS_VERSION >= 2605 #if ROS_VERSION >= 2505 // ROS2 >= Kilted Napi::Value ConfigureActionClientIntrospection(const Napi::CallbackInfo& info) { @@ -369,14 +369,14 @@ Napi::Object InitActionClientBindings(Napi::Env env, Napi::Object exports) { exports.Set("configureActionClientIntrospection", Napi::Function::New(env, ConfigureActionClientIntrospection)); #endif // ROS_VERSION >= 2505 -#if ROS_VERSION >= 5000 // ROS2 Rolling +#if ROS_VERSION >= 2605 // ROS2 Lyrical or newer exports.Set( "actionConfigureFeedbackSubFilterAddGoalId", Napi::Function::New(env, ActionConfigureFeedbackSubFilterAddGoalId)); exports.Set( "actionConfigureFeedbackSubFilterRemoveGoalId", Napi::Function::New(env, ActionConfigureFeedbackSubFilterRemoveGoalId)); -#endif // ROS_VERSION >= 5000 +#endif // ROS_VERSION >= 2605 return exports; } diff --git a/src/rcl_lifecycle_bindings.cpp b/src/rcl_lifecycle_bindings.cpp index 57bf67a9..f9c9210c 100644 --- a/src/rcl_lifecycle_bindings.cpp +++ b/src/rcl_lifecycle_bindings.cpp @@ -71,7 +71,7 @@ Napi::Value CreateLifecycleStateMachine(const Napi::CallbackInfo& info) { const rosidl_service_type_support_t* gs = GetServiceTypeSupport("lifecycle_msgs", "GetState"); -#if ROS_VERSION >= 5000 // ROS2 Rolling +#if ROS_VERSION >= 2605 // ROS2 Lyrical or newer rcl_lifecycle_state_machine_options_t options = rcl_lifecycle_get_default_state_machine_options(); options.enable_com_interface = info[1].As().Value(); From c830cd1453a4359dc497a41d3e7281f9758d6584 Mon Sep 17 00:00:00 2001 From: Minggang Wang Date: Fri, 1 May 2026 20:44:15 +0800 Subject: [PATCH 04/10] Address comments --- rosidl_gen/templates/message-template.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rosidl_gen/templates/message-template.js b/rosidl_gen/templates/message-template.js index 242ff728..c3b53698 100644 --- a/rosidl_gen/templates/message-template.js +++ b/rosidl_gen/templates/message-template.js @@ -266,12 +266,12 @@ function generateMessage(data) { const currentTypedArrayElementType = getTypedArrayElementName(spec.baseType); // ROS 2 Rolling (ros2/rosidl#941) added is_rosidl_buffer / owns_rosidl_buffer - // to every primitive sequence struct. Emit the extra fields only for - // primitive-package types on Rolling+. + // to every primitive sequence struct. Lyrical inherits the same ABI change. + // Emit the extra fields only for primitive-package types on Lyrical+. const DistroUtils = require('../../lib/distro.js'); const needsRosidlBufferFields = isPrimitivePackage(spec.baseType) && - DistroUtils.getDistroId() >= DistroUtils.getDistroId('rolling'); + DistroUtils.getDistroId() >= DistroUtils.DistroId.LYRICAL; // Track required modules let existedModules = []; From 6e4485be4d4f8b1849c97739e037bd73feba26a9 Mon Sep 17 00:00:00 2001 From: Minggang Wang Date: Fri, 1 May 2026 22:21:50 +0800 Subject: [PATCH 05/10] Address comments --- .github/workflows/linux-x64-build-and-test.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/linux-x64-build-and-test.yml b/.github/workflows/linux-x64-build-and-test.yml index ab2c920f..1376bca3 100644 --- a/.github/workflows/linux-x64-build-and-test.yml +++ b/.github/workflows/linux-x64-build-and-test.yml @@ -80,13 +80,6 @@ jobs: - name: Install ROS2 from binary tarball (rolling / lyrical) if: ${{ matrix.ros_distribution == 'rolling' || matrix.ros_distribution == 'lyrical' }} run: | - # Install apt packages BEFORE the binary tarball (rolling only; - # test-msgs / mrpt-msgs are not yet published for lyrical and - # test_msgs is bundled in the lyrical tarball itself). - if [ "${{ matrix.ros_distribution }}" = "rolling" ]; then - apt-get install -y ros-rolling-test-msgs ros-rolling-mrpt-msgs - fi - # Extract binary tarball AFTER apt packages so its newer libs overwrite apt's older ones curl -sL "${{ matrix.ros_tar_url }}" -o /tmp/ros2-${{ matrix.ros_distribution }}.tar.bz2 mkdir -p /opt/ros/${{ matrix.ros_distribution }} From 2fd237a25fcee0c5db7156e4088c33d0fb0d44c8 Mon Sep 17 00:00:00 2001 From: Minggang Wang Date: Fri, 1 May 2026 23:26:44 +0800 Subject: [PATCH 06/10] Address comments --- test/test-subscription-content-filter.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/test-subscription-content-filter.js b/test/test-subscription-content-filter.js index 01b24b57..345a2a62 100644 --- a/test/test-subscription-content-filter.js +++ b/test/test-subscription-content-filter.js @@ -506,9 +506,11 @@ describe('subscription isContentFilterSupported', function () { const supported = subscription.isContentFilterSupported(); assert.strictEqual(typeof supported, 'boolean'); - // isContentFilterSupported requires rolling; on older distros it returns false - const isRolling = DistroUtils.getDistroId() >= DistroUtils.DistroId.ROLLING; - const expectedSupported = isRolling && isContentFilteringSupported(); + // isContentFilterSupported requires Lyrical or newer; on older distros it + // returns false. + const isLyricalOrNewer = + DistroUtils.getDistroId() >= DistroUtils.DistroId.LYRICAL; + const expectedSupported = isLyricalOrNewer && isContentFilteringSupported(); assert.strictEqual(supported, expectedSupported); done(); From cb7c6245e13f1984e3bf128576e45e3f9c78f1c2 Mon Sep 17 00:00:00 2001 From: Minggang Wang Date: Fri, 1 May 2026 23:55:25 +0800 Subject: [PATCH 07/10] Address comments --- .github/workflows/linux-x64-build-and-test.yml | 12 ++++++++++-- test/test-graph.js | 4 ++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linux-x64-build-and-test.yml b/.github/workflows/linux-x64-build-and-test.yml index 1376bca3..0ed375ac 100644 --- a/.github/workflows/linux-x64-build-and-test.yml +++ b/.github/workflows/linux-x64-build-and-test.yml @@ -39,7 +39,11 @@ jobs: # Kilted Kaiju (May 2025 - Dec 2026) - docker_image: ubuntu:noble ros_distribution: kilted - # Lyrical Luth (May 2026 - May 2031, beta) - allow-failure until packages stabilize + # Lyrical Luth (May 2026 - May 2031, beta) - allow-failure until packages stabilize. + # NOTE: the tarball URL below is a date-stamped beta snapshot and must + # be refreshed manually until upstream publishes a stable "latest" + # download (or until GA), at which point it can be replaced with the + # stable URL similar to the rolling nightly redirect. - docker_image: ubuntu:26.04 ros_distribution: lyrical experimental: true @@ -69,7 +73,11 @@ jobs: apt-get update apt-get install -y software-properties-common curl - # Enable required repositories (per https://docs.ros.org/en/lyrical/Installation/Ubuntu-Install-Debs.html) + # Enable required repositories. The same setup applies to both the + # rolling nightly tarball and the lyrical beta tarball; see the + # per-distro install docs for reference: + # rolling: https://docs.ros.org/en/rolling/Installation/Alternatives/Ubuntu-Install-Binary.html + # lyrical: https://docs.ros.org/en/lyrical/Installation/Ubuntu-Install-Debs.html add-apt-repository universe ROS_APT_SOURCE_VERSION=$(curl -s https://api.github.com/repos/ros-infrastructure/ros-apt-source/releases/latest | grep -F "tag_name" | awk -F'"' '{print $4}') curl -L -o /tmp/ros2-apt-source.deb "https://github.com/ros-infrastructure/ros-apt-source/releases/download/${ROS_APT_SOURCE_VERSION}/ros2-apt-source_${ROS_APT_SOURCE_VERSION}.$(. /etc/os-release && echo ${UBUNTU_CODENAME:-${VERSION_CODENAME}})_all.deb" diff --git a/test/test-graph.js b/test/test-graph.js index 189c879a..425ce016 100644 --- a/test/test-graph.js +++ b/test/test-graph.js @@ -64,7 +64,7 @@ describe('rclnodejs graph test suite', function () { it('Get clients info by service', function () { if ( rclnodejs.DistroUtils.getDistroId() < - rclnodejs.DistroUtils.DistroId.ROLLING + rclnodejs.DistroUtils.DistroId.LYRICAL ) { this.skip(); } @@ -86,7 +86,7 @@ describe('rclnodejs graph test suite', function () { it('Get servers info by service', function () { if ( rclnodejs.DistroUtils.getDistroId() < - rclnodejs.DistroUtils.DistroId.ROLLING + rclnodejs.DistroUtils.DistroId.LYRICAL ) { this.skip(); } From 89802c22beba42c4eada25675c0472f446fe2c46 Mon Sep 17 00:00:00 2001 From: Minggang Wang Date: Sat, 2 May 2026 16:27:11 +0800 Subject: [PATCH 08/10] Address comments --- .../workflows/linux-arm64-build-and-test.yml | 46 ++++++++++++++++++- .../workflows/linux-x64-build-and-test.yml | 2 +- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux-arm64-build-and-test.yml b/.github/workflows/linux-arm64-build-and-test.yml index ea4cd700..35234533 100644 --- a/.github/workflows/linux-arm64-build-and-test.yml +++ b/.github/workflows/linux-arm64-build-and-test.yml @@ -17,6 +17,7 @@ jobs: runs-on: ubuntu-24.04-arm container: image: ${{ matrix.docker_image }} + continue-on-error: ${{ matrix.experimental == true }} strategy: fail-fast: false matrix: @@ -26,6 +27,7 @@ jobs: - humble - jazzy - kilted + - lyrical include: # Humble Hawksbill (May 2022 - May 2027) - docker_image: ubuntu:jammy @@ -36,6 +38,14 @@ jobs: # Kilted Kaiju (May 2025 - Dec 2026) - docker_image: ubuntu:noble ros_distribution: kilted + # Lyrical Luth (May 2026 - May 2031, beta) - allow-failure until packages stabilize. + # NOTE: the tarball URL below is a date-stamped beta snapshot and must + # be refreshed manually until upstream publishes a stable "latest" + # download (or until GA). + - docker_image: ubuntu:26.04 + ros_distribution: lyrical + experimental: true + ros_tar_url: "https://github.com/ros2/ros2/releases/download/release-lyrical-beta-20260430/ros2-lyrical-2026-04-30-resolute-aarch64.tar.bz2" steps: - name: Setup Node.js ${{ matrix.node-version }} on ${{ matrix.architecture }} @@ -45,16 +55,48 @@ jobs: architecture: ${{ matrix.architecture }} - name: Setup ROS2 + if: ${{ matrix.ros_distribution != 'lyrical' }} uses: ros-tooling/setup-ros@v0.7 with: required-ros-distributions: ${{ matrix.ros_distribution }} + - name: Enable ROS2 apt repository (lyrical) + if: ${{ matrix.ros_distribution == 'lyrical' }} + run: | + apt-get update + apt-get install -y software-properties-common curl + + # Enable required repositories for the lyrical beta tarball; see: + # https://docs.ros.org/en/lyrical/Installation/Ubuntu-Install-Debs.html + add-apt-repository universe + ROS_APT_SOURCE_VERSION=$(curl -s https://api.github.com/repos/ros-infrastructure/ros-apt-source/releases/latest | grep -F "tag_name" | awk -F'"' '{print $4}') + curl -L -o /tmp/ros2-apt-source.deb "https://github.com/ros-infrastructure/ros-apt-source/releases/download/${ROS_APT_SOURCE_VERSION}/ros2-apt-source_${ROS_APT_SOURCE_VERSION}.$(. /etc/os-release && echo ${UBUNTU_CODENAME:-${VERSION_CODENAME}})_all.deb" + dpkg -i /tmp/ros2-apt-source.deb + apt-get update + apt-get install -y build-essential cmake tar bzip2 python3 python3-rosdep python3-colcon-common-extensions + + - name: Install ROS2 from binary tarball (lyrical) + if: ${{ matrix.ros_distribution == 'lyrical' }} + run: | + curl -sL "${{ matrix.ros_tar_url }}" -o /tmp/ros2-lyrical.tar.bz2 + mkdir -p /opt/ros/lyrical + tar xf /tmp/ros2-lyrical.tar.bz2 --strip-components=1 -C /opt/ros/lyrical + rm /tmp/ros2-lyrical.tar.bz2 + + rosdep init || true + rosdep update + rosdep install --rosdistro lyrical --from-paths /opt/ros/lyrical/share --ignore-src -y --skip-keys "cyclonedds fastcdr fastdds iceoryx_binding_c rmw_connextdds rti-connext-dds-7.3.0 rti-connext-dds-7.7.0 urdfdom_headers python3-pyqt6.qtsvg rosidl_buffer_py pybind11" + - name: Install test-msgs and mrpt_msgs on Linux + if: ${{ matrix.ros_distribution != 'lyrical' }} + run: | + sudo apt install -y ros-${{ matrix.ros_distribution }}-test-msgs ros-${{ matrix.ros_distribution }}-mrpt-msgs + + - name: Install Electron test dependencies run: | - sudo apt install ros-${{ matrix.ros_distribution }}-test-msgs ros-${{ matrix.ros_distribution }}-mrpt-msgs # Adjust dependencies based on Ubuntu version LIBASOUND_PKG="libasound2" - if grep -q "24.04" /etc/os-release; then + if grep -Eq "24\.04|26\.04" /etc/os-release; then LIBASOUND_PKG="libasound2t64" fi sudo apt install -y xvfb libgtk-3-0 libnss3 $LIBASOUND_PKG libgbm-dev diff --git a/.github/workflows/linux-x64-build-and-test.yml b/.github/workflows/linux-x64-build-and-test.yml index 0ed375ac..d59f3514 100644 --- a/.github/workflows/linux-x64-build-and-test.yml +++ b/.github/workflows/linux-x64-build-and-test.yml @@ -47,7 +47,7 @@ jobs: - docker_image: ubuntu:26.04 ros_distribution: lyrical experimental: true - ros_tar_url: "https://github.com/ros2/ros2/releases/download/release-lyrical-beta-20260429-1/ros2-lyrical-2026-04-29-1-resolute-x86_64.tar.bz2" + ros_tar_url: "https://github.com/ros2/ros2/releases/download/release-lyrical-beta-20260430/ros2-lyrical-2026-04-30-resolute-x86_64.tar.bz2" # Rolling Ridley (No End-Of-Life) - migrated to Ubuntu 26.04 (resolute) # to follow the Lyrical Luth target platform. # See: https://docs.ros.org/en/jazzy/Releases/Release-Lyrical-Luth.html From 3da8a981cc6ab650df490111f8f319661bc19d6e Mon Sep 17 00:00:00 2001 From: Minggang Wang Date: Sat, 2 May 2026 16:44:31 +0800 Subject: [PATCH 09/10] Address comments --- .github/workflows/windows-build-and-test.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/windows-build-and-test.yml b/.github/workflows/windows-build-and-test.yml index 7ea265b1..53dc36da 100644 --- a/.github/workflows/windows-build-and-test.yml +++ b/.github/workflows/windows-build-and-test.yml @@ -11,6 +11,7 @@ on: jobs: build: runs-on: windows-2025 + continue-on-error: ${{ matrix.experimental == true }} strategy: fail-fast: false matrix: @@ -18,6 +19,7 @@ jobs: ros_distribution: - jazzy - kilted + - lyrical - rolling include: - ros_distribution: jazzy @@ -26,6 +28,12 @@ jobs: - ros_distribution: kilted ros_zip_url: "https://github.com/ros2/ros2/releases/download/release-kilted-20250728/ros2-kilted-20250728-windows-release-amd64.zip" run_tests: false + # Lyrical Luth (May 2026 - May 2031, beta) - allow-failure until packages stabilize. + # Reference: https://docs.ros.org/en/lyrical/Installation/Windows-Install-Binary.html + - ros_distribution: lyrical + ros_zip_url: "https://github.com/ros2/ros2/releases/download/release-lyrical-beta-20260430/ros2-lyrical-2026-04-30-windows-AMD64.zip" + run_tests: false + experimental: true - ros_distribution: rolling ros_zip_url: "https://github.com/ros2/ros2/releases/download/release-rolling-nightlies/ros2-rolling-nightly-windows-amd64.zip" run_tests: false @@ -52,9 +60,21 @@ jobs: choco install 7zip -y Invoke-WebRequest -Uri "${{ matrix.ros_zip_url }}" -OutFile ros2.zip 7z x ros2.zip -y -oC:\pixi_ws + if (!(Test-Path C:\pixi_ws\ros2-windows\setup.bat)) { + $setupScript = Get-ChildItem -Path C:\pixi_ws -Recurse -Filter setup.bat | Select-Object -First 1 + if ($null -eq $setupScript) { + throw "Unable to find ROS 2 setup.bat after extracting ${{ matrix.ros_zip_url }}" + } + Move-Item -Path $setupScript.Directory.FullName -Destination C:\pixi_ws\ros2-windows + } Invoke-WebRequest -Uri "https://raw.githubusercontent.com/ros2/ros2/refs/heads/${{ matrix.ros_distribution }}/pixi.toml" -OutFile C:\pixi_ws\pixi.toml Push-Location C:\pixi_ws pixi install + if (Test-Path C:\pixi_ws\ros2-windows\preinstall_setup_windows.py) { + Push-Location C:\pixi_ws\ros2-windows + pixi run python preinstall_setup_windows.py + Pop-Location + } Pop-Location - name: Prebuild - Setup VS Dev Environment From 8c3a72f3e02ceb7907d6de6d132e9ae4a7c13fb8 Mon Sep 17 00:00:00 2001 From: Minggang Wang Date: Sun, 3 May 2026 21:57:35 +0800 Subject: [PATCH 10/10] Address comments --- .github/workflows/linux-arm64-build-and-test.yml | 4 +--- .github/workflows/linux-x64-build-and-test.yml | 4 +--- .github/workflows/windows-build-and-test.yml | 4 +--- src/rcl_graph_bindings.cpp | 16 ++++++++-------- src/rcl_subscription_bindings.cpp | 4 ++-- src/rcl_utilities.cpp | 8 ++++---- src/rcl_utilities.h | 4 ++-- types/distro.d.ts | 16 +++++++++++++++- 8 files changed, 34 insertions(+), 26 deletions(-) diff --git a/.github/workflows/linux-arm64-build-and-test.yml b/.github/workflows/linux-arm64-build-and-test.yml index 35234533..f9c7edc1 100644 --- a/.github/workflows/linux-arm64-build-and-test.yml +++ b/.github/workflows/linux-arm64-build-and-test.yml @@ -17,7 +17,6 @@ jobs: runs-on: ubuntu-24.04-arm container: image: ${{ matrix.docker_image }} - continue-on-error: ${{ matrix.experimental == true }} strategy: fail-fast: false matrix: @@ -38,13 +37,12 @@ jobs: # Kilted Kaiju (May 2025 - Dec 2026) - docker_image: ubuntu:noble ros_distribution: kilted - # Lyrical Luth (May 2026 - May 2031, beta) - allow-failure until packages stabilize. + # Lyrical Luth (May 2026 - May 2031, beta) # NOTE: the tarball URL below is a date-stamped beta snapshot and must # be refreshed manually until upstream publishes a stable "latest" # download (or until GA). - docker_image: ubuntu:26.04 ros_distribution: lyrical - experimental: true ros_tar_url: "https://github.com/ros2/ros2/releases/download/release-lyrical-beta-20260430/ros2-lyrical-2026-04-30-resolute-aarch64.tar.bz2" steps: diff --git a/.github/workflows/linux-x64-build-and-test.yml b/.github/workflows/linux-x64-build-and-test.yml index d59f3514..0f70f445 100644 --- a/.github/workflows/linux-x64-build-and-test.yml +++ b/.github/workflows/linux-x64-build-and-test.yml @@ -17,7 +17,6 @@ jobs: runs-on: ubuntu-latest container: image: ${{ matrix.docker_image }} - continue-on-error: ${{ matrix.experimental == true }} strategy: fail-fast: false matrix: @@ -39,14 +38,13 @@ jobs: # Kilted Kaiju (May 2025 - Dec 2026) - docker_image: ubuntu:noble ros_distribution: kilted - # Lyrical Luth (May 2026 - May 2031, beta) - allow-failure until packages stabilize. + # Lyrical Luth (May 2026 - May 2031, beta) # NOTE: the tarball URL below is a date-stamped beta snapshot and must # be refreshed manually until upstream publishes a stable "latest" # download (or until GA), at which point it can be replaced with the # stable URL similar to the rolling nightly redirect. - docker_image: ubuntu:26.04 ros_distribution: lyrical - experimental: true ros_tar_url: "https://github.com/ros2/ros2/releases/download/release-lyrical-beta-20260430/ros2-lyrical-2026-04-30-resolute-x86_64.tar.bz2" # Rolling Ridley (No End-Of-Life) - migrated to Ubuntu 26.04 (resolute) # to follow the Lyrical Luth target platform. diff --git a/.github/workflows/windows-build-and-test.yml b/.github/workflows/windows-build-and-test.yml index 53dc36da..b6f530d7 100644 --- a/.github/workflows/windows-build-and-test.yml +++ b/.github/workflows/windows-build-and-test.yml @@ -11,7 +11,6 @@ on: jobs: build: runs-on: windows-2025 - continue-on-error: ${{ matrix.experimental == true }} strategy: fail-fast: false matrix: @@ -28,12 +27,11 @@ jobs: - ros_distribution: kilted ros_zip_url: "https://github.com/ros2/ros2/releases/download/release-kilted-20250728/ros2-kilted-20250728-windows-release-amd64.zip" run_tests: false - # Lyrical Luth (May 2026 - May 2031, beta) - allow-failure until packages stabilize. + # Lyrical Luth (May 2026 - May 2031, beta) # Reference: https://docs.ros.org/en/lyrical/Installation/Windows-Install-Binary.html - ros_distribution: lyrical ros_zip_url: "https://github.com/ros2/ros2/releases/download/release-lyrical-beta-20260430/ros2-lyrical-2026-04-30-windows-AMD64.zip" run_tests: false - experimental: true - ros_distribution: rolling ros_zip_url: "https://github.com/ros2/ros2/releases/download/release-rolling-nightlies/ros2-rolling-nightly-windows-amd64.zip" run_tests: false diff --git a/src/rcl_graph_bindings.cpp b/src/rcl_graph_bindings.cpp index cd06f39b..455bca7e 100644 --- a/src/rcl_graph_bindings.cpp +++ b/src/rcl_graph_bindings.cpp @@ -33,12 +33,12 @@ typedef rcl_ret_t (*rcl_get_info_by_topic_func_t)( const char* topic_name, bool no_mangle, rcl_topic_endpoint_info_array_t* info_array); -#if ROS_VERSION > 2505 +#if ROS_VERSION >= 2605 typedef rcl_ret_t (*rcl_get_info_by_service_func_t)( const rcl_node_t* node, rcutils_allocator_t* allocator, const char* service_name, bool no_mangle, rcl_service_endpoint_info_array_t* info_array); -#endif // ROS_VERSION > 2505 +#endif // ROS_VERSION >= 2605 Napi::Value GetPublisherNamesAndTypesByNode(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); @@ -264,7 +264,7 @@ Napi::Value GetSubscriptionsInfoByTopic(const Napi::CallbackInfo& info) { "subscriptions", rcl_get_subscriptions_info_by_topic); } -#if ROS_VERSION > 2505 +#if ROS_VERSION >= 2605 Napi::Value GetInfoByService( Napi::Env env, rcl_node_t* node, const char* service_name, bool no_mangle, const char* type, rcl_get_info_by_service_func_t rcl_get_info_by_service) { @@ -300,9 +300,9 @@ Napi::Value GetInfoByService( return ConvertToJSServiceEndpointInfoList(env, &info_array); } -#endif // ROS_VERSION > 2505 +#endif // ROS_VERSION >= 2605 -#if ROS_VERSION > 2505 +#if ROS_VERSION >= 2605 Napi::Value GetClientsInfoByService(const Napi::CallbackInfo& info) { RclHandle* node_handle = RclHandle::Unwrap(info[0].As()); rcl_node_t* node = reinterpret_cast(node_handle->ptr()); @@ -322,7 +322,7 @@ Napi::Value GetServersInfoByService(const Napi::CallbackInfo& info) { return GetInfoByService(info.Env(), node, service_name.c_str(), no_mangle, "servers", rcl_get_servers_info_by_service); } -#endif // ROS_VERSION > 2505 +#endif // ROS_VERSION >= 2605 Napi::Object InitGraphBindings(Napi::Env env, Napi::Object exports) { exports.Set("getPublisherNamesAndTypesByNode", @@ -341,12 +341,12 @@ Napi::Object InitGraphBindings(Napi::Env env, Napi::Object exports) { Napi::Function::New(env, GetPublishersInfoByTopic)); exports.Set("getSubscriptionsInfoByTopic", Napi::Function::New(env, GetSubscriptionsInfoByTopic)); -#if ROS_VERSION > 2505 +#if ROS_VERSION >= 2605 exports.Set("getClientsInfoByService", Napi::Function::New(env, GetClientsInfoByService)); exports.Set("getServersInfoByService", Napi::Function::New(env, GetServersInfoByService)); -#endif // ROS_VERSION > 2505 +#endif // ROS_VERSION >= 2605 return exports; } diff --git a/src/rcl_subscription_bindings.cpp b/src/rcl_subscription_bindings.cpp index 078e89ab..607f0442 100644 --- a/src/rcl_subscription_bindings.cpp +++ b/src/rcl_subscription_bindings.cpp @@ -265,7 +265,7 @@ Napi::Value GetSubscriptionTopic(const Napi::CallbackInfo& info) { return Napi::String::New(env, topic); } -#if ROS_VERSION > 2505 // Rolling only +#if ROS_VERSION >= 2605 // ROS2 Lyrical or newer Napi::Value IsContentFilterSupported(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); @@ -491,7 +491,7 @@ Napi::Object InitSubscriptionBindings(Napi::Env env, Napi::Object exports) { exports.Set("rclTakeRaw", Napi::Function::New(env, RclTakeRaw)); exports.Set("getSubscriptionTopic", Napi::Function::New(env, GetSubscriptionTopic)); -#if ROS_VERSION > 2505 // Rolling only +#if ROS_VERSION >= 2605 // ROS2 Lyrical or newer exports.Set("isContentFilterSupported", Napi::Function::New(env, IsContentFilterSupported)); #endif diff --git a/src/rcl_utilities.cpp b/src/rcl_utilities.cpp index ad84792a..4f4d86b6 100644 --- a/src/rcl_utilities.cpp +++ b/src/rcl_utilities.cpp @@ -124,7 +124,7 @@ Napi::Value ConvertToJSTopicEndpoint( return endpoint; } -#if ROS_VERSION > 2505 +#if ROS_VERSION >= 2605 Napi::Value ConvertToJSServiceEndpointInfo( Napi::Env env, const rmw_service_endpoint_info_t* service_endpoint_info) { Napi::Object endpoint = Napi::Object::New(env); @@ -164,7 +164,7 @@ Napi::Value ConvertToJSServiceEndpointInfo( return endpoint; } -#endif // ROS_VERSION > 2505 +#endif // ROS_VERSION >= 2605 uv_lib_t g_lib; Napi::Env g_env = nullptr; @@ -308,7 +308,7 @@ Napi::Array ConvertToJSTopicEndpointInfoList( return list; } -#if ROS_VERSION > 2505 +#if ROS_VERSION >= 2605 Napi::Array ConvertToJSServiceEndpointInfoList( Napi::Env env, const rmw_service_endpoint_info_array_t* info_array) { Napi::Array list = Napi::Array::New(env, info_array->size); @@ -319,7 +319,7 @@ Napi::Array ConvertToJSServiceEndpointInfoList( } return list; } -#endif // ROS_VERSION > 2505 +#endif // ROS_VERSION >= 2605 char** AbstractArgsFromNapiArray(const Napi::Array& jsArgv) { size_t argc = jsArgv.Length(); diff --git a/src/rcl_utilities.h b/src/rcl_utilities.h index 568824ea..7d8b7b19 100644 --- a/src/rcl_utilities.h +++ b/src/rcl_utilities.h @@ -51,10 +51,10 @@ void ExtractNamesAndTypes(rcl_names_and_types_t names_and_types, Napi::Array ConvertToJSTopicEndpointInfoList( Napi::Env env, const rmw_topic_endpoint_info_array_t* info_array); -#if ROS_VERSION > 2505 +#if ROS_VERSION >= 2605 Napi::Array ConvertToJSServiceEndpointInfoList( Napi::Env env, const rmw_service_endpoint_info_array_t* info_array); -#endif // ROS_VERSION > 2505 +#endif // ROS_VERSION >= 2605 Napi::Value ConvertToQoS(Napi::Env env, const rmw_qos_profile_t* qos_profile); diff --git a/types/distro.d.ts b/types/distro.d.ts index c3f16107..58ad4154 100644 --- a/types/distro.d.ts +++ b/types/distro.d.ts @@ -3,7 +3,16 @@ declare module 'rclnodejs' { /** * Valid ROS 2 distro short names */ - type DistroName = 'eloquent' | 'foxy' | 'galactic' | 'humble' | 'rolling'; + type DistroName = + | 'eloquent' + | 'foxy' + | 'galactic' + | 'humble' + | 'iron' + | 'jazzy' + | 'kilted' + | 'lyrical' + | 'rolling'; /** * rclnodejs distro ID numbers @@ -14,7 +23,12 @@ declare module 'rclnodejs' { FOXY = 2006, GALACTIC = 2105, HUMBLE = 2205, + IRON = 2305, + JAZZY = 2405, + KILTED = 2505, + LYRICAL = 2605, ROLLING = 5000, + FUTURE = 9999, } /**