diff --git a/.github/workflows/check-ros-distribution.sh b/.github/workflows/check-ros-distribution.sh new file mode 100755 index 000000000..c8715133c --- /dev/null +++ b/.github/workflows/check-ros-distribution.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# +# ./check-ros-distribution.sh +# ROS distribution must match the directory name for this distribution +# in /opt. E.g. melodic. + +readonly ROS_DISTRIBUTION="$1" + +# GitHub Action is erroneously setting PYTHONHOME to C:\python37 +unset PYTHONHOME +source "/opt/ros/${ROS_DISTRIBUTION}/setup.bash" +rosstack list diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4fa6d1609..30b81578b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,6 +8,7 @@ on: schedule: # Run the CI automatically twice per day to look for flakyness. - cron: "0 */12 * * *" + workflow_dispatch: defaults: run: @@ -114,6 +115,15 @@ jobs: # Platforms are defined in REP 3: https://ros.org/reps/rep-0003.html include: + # ROS-O (ROS One) - ROS 1 for Ubuntu 20.04+ + - docker_image: ubuntu:jammy + ros_distribution: one + ros_version: 1 + + - docker_image: ubuntu:noble + ros_distribution: one + ros_version: 1 + # Humble Hawksbill (May 2022 - May 2027) - docker_image: ubuntu:jammy ros_distribution: humble diff --git a/README.md b/README.md index 24d338017..ceb7d8c01 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,9 @@ It also performs the following actions: - Setting the locale to `en_US.UTF-8` and, the timezone to UTC - GCC and clang default APT packages - Registering the Open Robotics APT repository + - For ROS-O (`one`), packages are installed from a separate APT repository + (`ros.packages.techfak.net`) maintained by the ROS-O community at CITEC + Bielefeld, not from the Open Robotics APT repository. - Installing ROS and ROS 2 system dependencies using APT - On macOS: - Installing ROS and ROS 2 system dependencies using [Homebrew] and [pip] diff --git a/__test__/main.test.ts b/__test__/main.test.ts index 0e81db8f9..3e73245d6 100644 --- a/__test__/main.test.ts +++ b/__test__/main.test.ts @@ -64,6 +64,7 @@ describe("required-ros-distributions/noetic workflow tests", () => { describe("validate distribution test", () => { it("test valid", async () => { await expect(utils.validateDistro(["noetic"])).toBe(true); + await expect(utils.validateDistro(["one"])).toBe(true); await expect(utils.validateDistro(["humble"])).toBe(true); await expect(utils.validateDistro(["iron"])).toBe(true); await expect(utils.validateDistro(["jazzy"])).toBe(true); diff --git a/dist/index.js b/dist/index.js index d9f4b3ed4..ec2fe9291 100644 --- a/dist/index.js +++ b/dist/index.js @@ -34607,6 +34607,7 @@ const pip3Packages = [ "colcon-recursive-crawl==0.2.1", "colcon-ros==0.3.23", "colcon-test-result==0.3.8", + "meson>=0.60.0,<0.64.0", "coverage", "cryptography", "empy<4", @@ -35073,6 +35074,23 @@ function installRosAptSourcePackageIfNeeded(ubuntuCodename, use_ros2_testing) { } }); } +/** + * Add ROS-O (ROS One) APT repository key. + * + * Downloads and installs the GPG key for the ROS-O repository. + */ +function addRosOneAptRepoKey() { + return __awaiter(this, void 0, void 0, function* () { + // Ensure the keyrings directory exists and ca-certificates is up to date + yield utils.exec("sudo", ["mkdir", "-p", "/etc/apt/keyrings"]); + yield utils.exec("sudo", ["update-ca-certificates"]); + yield utils.exec("sudo", [ + "bash", + "-c", + "curl -sSL https://ros.packages.techfak.net/gpg.key -o /etc/apt/keyrings/ros-one-keyring.gpg", + ]); + }); +} // Ubuntu distribution for ROS 1 const ros1UbuntuVersion = "focal"; /** @@ -35087,6 +35105,24 @@ function determineAptSourcePackageName(ubuntuCodename, use_ros2_testing) { } return `ros2${use_ros2_testing ? "-testing" : ""}-apt-source`; } +/** + * Add ROS-O (ROS One) APT repository. + * + * @param ubuntuCodename the Ubuntu version codename + * @param use_testing whether to use the testing repository + */ +function addRosOneAptRepo(ubuntuCodename, use_testing) { + return __awaiter(this, void 0, void 0, function* () { + const arch = yield utils.getArch(); + const repo = use_testing ? `${ubuntuCodename}-testing` : ubuntuCodename; + yield utils.exec("sudo", [ + "bash", + "-c", + `echo "deb [arch=${arch} signed-by=/etc/apt/keyrings/ros-one-keyring.gpg] https://ros.packages.techfak.net ${repo} main" > /etc/apt/sources.list.d/ros-one.list`, + ]); + yield utils.exec("sudo", ["apt-get", "update"]); + }); +} /** * Initialize rosdep. */ @@ -35104,6 +35140,20 @@ function rosdepInit() { yield utils.exec("sudo", ["rosdep", "init"]); }); } +/** + * Configure rosdep for ROS-O (ROS One). + * + * Adds custom rosdep source for ROS-O packages. + */ +function configureRosOneRosdep() { + return __awaiter(this, void 0, void 0, function* () { + yield utils.exec("sudo", [ + "bash", + "-c", + 'echo "yaml https://ros.packages.techfak.net/ros-one.yaml one" > /etc/ros/rosdep/sources.list.d/1-ros-one.list', + ]); + }); +} /** * Install ROS 1 or 2 (development packages and/or ROS binaries) on a Linux worker. */ @@ -35112,9 +35162,17 @@ function runLinux() { // Get user input & validate const use_ros2_testing = core.getInput("use-ros2-testing") === "true"; const installConnext = core.getInput("install-connext") === "true"; + const requiredDistros = utils.getRequiredRosDistributions(); + // ROS-O "one" uses a separate repository (ros.packages.techfak.net). + const needsRosOne = requiredDistros.includes("one"); yield configOs(); const ubuntuCodename = yield utils.determineDistribCodename(); yield installRosAptSourcePackageIfNeeded(ubuntuCodename, use_ros2_testing); + // Add ROS-O repository if needed + if (needsRosOne) { + yield addRosOneAptRepoKey(); + yield addRosOneAptRepo(ubuntuCodename, use_ros2_testing); + } if ("noble" !== ubuntuCodename && "resolute" !== ubuntuCodename) { // Temporary fix to avoid error mount: /var/lib/grub/esp: special device (...) does not exist. const arch = yield utils.getArch(); @@ -35131,7 +35189,11 @@ function runLinux() { yield pip.installPython3Dependencies(); } yield rosdepInit(); - for (const rosDistro of utils.getRequiredRosDistributions()) { + // Configure rosdep for ROS-O if needed + if (needsRosOne) { + yield configureRosOneRosdep(); + } + for (const rosDistro of requiredDistros) { yield apt.runAptGetInstall([`ros-${rosDistro}-desktop`]); } }); @@ -35463,6 +35525,7 @@ function getRequiredRosDistributions() { //list of valid linux distributions const validDistro = [ "noetic", + "one", "humble", "iron", "jazzy", diff --git a/src/package_manager/pip.ts b/src/package_manager/pip.ts index a19afd48c..42e483b27 100644 --- a/src/package_manager/pip.ts +++ b/src/package_manager/pip.ts @@ -27,6 +27,7 @@ const pip3Packages: string[] = [ "colcon-recursive-crawl==0.2.1", "colcon-ros==0.3.23", "colcon-test-result==0.3.8", + "meson>=0.60.0,<0.64.0", "coverage", "cryptography", "empy<4", diff --git a/src/setup-ros-ubuntu.ts b/src/setup-ros-ubuntu.ts index c0135e468..8f69a2cbc 100644 --- a/src/setup-ros-ubuntu.ts +++ b/src/setup-ros-ubuntu.ts @@ -101,6 +101,22 @@ async function installRosAptSourcePackageIfNeeded( } } +/** + * Add ROS-O (ROS One) APT repository key. + * + * Downloads and installs the GPG key for the ROS-O repository. + */ +async function addRosOneAptRepoKey(): Promise { + // Ensure the keyrings directory exists and ca-certificates is up to date + await utils.exec("sudo", ["mkdir", "-p", "/etc/apt/keyrings"]); + await utils.exec("sudo", ["update-ca-certificates"]); + await utils.exec("sudo", [ + "bash", + "-c", + "curl -sSL https://ros.packages.techfak.net/gpg.key -o /etc/apt/keyrings/ros-one-keyring.gpg", + ]); +} + // Ubuntu distribution for ROS 1 const ros1UbuntuVersion = "focal"; @@ -121,6 +137,26 @@ function determineAptSourcePackageName( return `ros2${use_ros2_testing ? "-testing" : ""}-apt-source`; } +/** + * Add ROS-O (ROS One) APT repository. + * + * @param ubuntuCodename the Ubuntu version codename + * @param use_testing whether to use the testing repository + */ +async function addRosOneAptRepo( + ubuntuCodename: string, + use_testing: boolean, +): Promise { + const arch = await utils.getArch(); + const repo = use_testing ? `${ubuntuCodename}-testing` : ubuntuCodename; + await utils.exec("sudo", [ + "bash", + "-c", + `echo "deb [arch=${arch} signed-by=/etc/apt/keyrings/ros-one-keyring.gpg] https://ros.packages.techfak.net ${repo} main" > /etc/apt/sources.list.d/ros-one.list`, + ]); + await utils.exec("sudo", ["apt-get", "update"]); +} + /** * Initialize rosdep. */ @@ -137,6 +173,19 @@ async function rosdepInit(): Promise { await utils.exec("sudo", ["rosdep", "init"]); } +/** + * Configure rosdep for ROS-O (ROS One). + * + * Adds custom rosdep source for ROS-O packages. + */ +async function configureRosOneRosdep(): Promise { + await utils.exec("sudo", [ + "bash", + "-c", + 'echo "yaml https://ros.packages.techfak.net/ros-one.yaml one" > /etc/ros/rosdep/sources.list.d/1-ros-one.list', + ]); +} + /** * Install ROS 1 or 2 (development packages and/or ROS binaries) on a Linux worker. */ @@ -145,11 +194,21 @@ export async function runLinux(): Promise { const use_ros2_testing = core.getInput("use-ros2-testing") === "true"; const installConnext = core.getInput("install-connext") === "true"; + const requiredDistros = utils.getRequiredRosDistributions(); + // ROS-O "one" uses a separate repository (ros.packages.techfak.net). + const needsRosOne = requiredDistros.includes("one"); + await configOs(); const ubuntuCodename = await utils.determineDistribCodename(); await installRosAptSourcePackageIfNeeded(ubuntuCodename, use_ros2_testing); + // Add ROS-O repository if needed + if (needsRosOne) { + await addRosOneAptRepoKey(); + await addRosOneAptRepo(ubuntuCodename, use_ros2_testing); + } + if ("noble" !== ubuntuCodename && "resolute" !== ubuntuCodename) { // Temporary fix to avoid error mount: /var/lib/grub/esp: special device (...) does not exist. const arch = await utils.getArch(); @@ -170,7 +229,12 @@ export async function runLinux(): Promise { await rosdepInit(); - for (const rosDistro of utils.getRequiredRosDistributions()) { + // Configure rosdep for ROS-O if needed + if (needsRosOne) { + await configureRosOneRosdep(); + } + + for (const rosDistro of requiredDistros) { await apt.runAptGetInstall([`ros-${rosDistro}-desktop`]); } } diff --git a/src/utils.ts b/src/utils.ts index 0bd521dcb..f7e065be2 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -43,6 +43,7 @@ export function getRequiredRosDistributions(): string[] { //list of valid linux distributions const validDistro: string[] = [ "noetic", + "one", "humble", "iron", "jazzy",