diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7cebd7b..3200816 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -310,3 +310,31 @@ jobs: source /opt/ros/humble/setup.bash ros2 pkg list | grep ros_gz ign gazebo --version | grep 'version 6.*' + + test_install_ros_gz_vendor: + name: 'Install Harmonic on Jazzy through vendor packages' + env: + ROS_DISTROS: 'jazzy' + runs-on: ubuntu-latest + container: + image: ubuntu:noble + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4.0.3 + with: + node-version: '20.x' + - name: 'Install ROS 2 Jazzy' + uses: ros-tooling/setup-ros@v0.7 + with: + required-ros-distributions: ${{ env.ROS_DISTROS }} + - name: 'Install Gazebo with ros_gz' + uses: ./ + with: + required-gazebo-distributions: 'harmonic' + install-ros-gz: ${{ env.ROS_DISTROS }} + - name: Test Jazzy ros_gz installation + run: | + source /opt/ros/jazzy/setup.bash + ! [ $(apt list --installed gz-harmonic) ] + ros2 pkg list | grep ros_gz + gz sim --version | grep 'version 8.[0-9*].[0-9*]' diff --git a/README.md b/README.md index 7086a77..05f582c 100644 --- a/README.md +++ b/README.md @@ -246,6 +246,8 @@ This workflow shows how to use binaries from [pre-release] or [nightly] Gazebo r This workflow shows how to install ROS 2 using the GitHub action `ros-tooling/setup-ros` along with Gazebo installed using `setup-gazebo`. The `ros-gz` package can be installed by setting the input parameter `install-ros-gz` to the required ROS 2 distributions. +Starting with ROS 2 Jazzy, Gazebo is also available to be installed from ROS packages via [vendor packages]. When using `install-ros-gz` this action will check for availability of these Gazebo vendor packages and install them if available for the specified ROS 2 distribution. Only the default (recommended) Gazebo release is currently available for the ROS 2 releases using the vendor packages (i.e if ROS 2 Jazzy is used, only Gazebo Harmonic is the valid option). More information on vendor packages can be found in the [official documentation]. + ```yaml jobs: test_gazebo: @@ -282,19 +284,20 @@ This workflow shows how to install ROS 2 using the GitHub action `ros-tooling/se This workflow shows how to install Gazebo on a macOS worker using the Homebrew package manager which is installed by the action. To run, this action needs an input for `required-gazebo-distributions` parameter. ```yaml - test_gazebo: - runs-on: macos-13 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4.0.2 - with: - node-version: '20.x' - - name: 'Check Gazebo installation on MacOS runner' - uses: gazebo-tooling/setup-gazebo@v0.2.0 - with: - required-gazebo-distributions: 'harmonic' - - name: 'Test Gazebo installation' - run: 'gz sim --versions' + jobs: + test_gazebo: + runs-on: macos-13 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4.0.2 + with: + node-version: '20.x' + - name: 'Check Gazebo installation on MacOS runner' + uses: gazebo-tooling/setup-gazebo@v0.2.0 + with: + required-gazebo-distributions: 'harmonic' + - name: 'Test Gazebo installation' + run: 'gz sim --versions' ``` ### Windows @@ -304,23 +307,24 @@ This workflow shows how to install Gazebo on a Windows worker. The action requir #### Setting up worker to install Gazebo on Windows ```yaml - test_gazebo: - runs-on: windows-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4.0.2 - with: - node-version: '20.x' - - uses: conda-incubator/setup-miniconda@v3 - - name: 'Check Gazebo installation on Windows runner' - uses: gazebo-tooling/setup-gazebo@v0.2.0 - with: - required-gazebo-distributions: 'harmonic' - - name: 'Test Gazebo installation' - shell: pwsh - run: | - conda activate - gz sim --versions + jobs: + test_gazebo: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4.0.2 + with: + node-version: '20.x' + - uses: conda-incubator/setup-miniconda@v3 + - name: 'Check Gazebo installation on Windows runner' + uses: gazebo-tooling/setup-gazebo@v0.2.0 + with: + required-gazebo-distributions: 'harmonic' + - name: 'Test Gazebo installation' + shell: pwsh + run: | + conda activate + gz sim --versions ``` ## License @@ -332,3 +336,5 @@ The scripts and documentation in this project are released under the [Apache 2]( [best-effort]: https://gazebosim.org/docs/harmonic/releases#supported-platforms [pre-release]: https://packages.osrfoundation.org/gazebo/ubuntu-prerelease/ [nightly]: https://packages.osrfoundation.org/gazebo/ubuntu-nightly/ +[vendor packages]: https://gazebosim.org/docs/ionic/ros_installation/#ros-2-gazebo-vendor-packages +[official documentation]: https://gazebosim.org/docs/ionic/ros2_gz_vendor_pkgs/ diff --git a/__test__/main.test.ts b/__test__/main.test.ts index 2c4fdc2..50bde0b 100644 --- a/__test__/main.test.ts +++ b/__test__/main.test.ts @@ -106,6 +106,8 @@ describe("validate ROS 2 distribution test", () => { it("test valid distro", async () => { await expect(utils.validateROSDistro(["humble"])).toBe(true); await expect(utils.validateROSDistro(["iron"])).toBe(true); + await expect(utils.validateROSDistro(["jazzy"])).toBe(true); + await expect(utils.validateROSDistro(["rolling"])).toBe(true); await expect(utils.validateROSDistro(["humble", "iron"])).toBe(true); }); it("test invalid distro", async () => { @@ -177,13 +179,28 @@ describe("check for unstable repositories input", () => { describe("generate APT package names for ros_gz", () => { it("test ros_gz output package names list", async () => { await expect( - utils.generateROSAptPackageNames(["humble", "iron"], ["harmonic"]), - ).toEqual(["ros-humble-ros-gzharmonic", "ros-iron-ros-gzharmonic"]); + utils.generateROSGzAptPackageNames(["humble", "iron"], ["harmonic"]), + ).toEqual([ + "gz-harmonic", + "ros-humble-ros-gzharmonic", + "ros-iron-ros-gzharmonic", + ]); await expect( - utils.generateROSAptPackageNames(["humble"], ["fortress"]), - ).toEqual(["ros-humble-ros-gz"]); + utils.generateROSGzAptPackageNames(["humble"], ["fortress"]), + ).toEqual(["gz-fortress", "ros-humble-ros-gz"]); await expect( - utils.generateROSAptPackageNames(["iron"], ["fortress", "garden"]), - ).toEqual(["ros-iron-ros-gz", "ros-iron-ros-gzgarden"]); + utils.generateROSGzAptPackageNames(["iron"], ["fortress", "garden"]), + ).toEqual([ + "gz-fortress", + "ros-iron-ros-gz", + "gz-garden", + "ros-iron-ros-gzgarden", + ]); + await expect( + utils.generateROSGzAptPackageNames(["jazzy"], ["harmonic"]), + ).toEqual(["ros-jazzy-ros-gz"]); + await expect( + utils.generateROSGzAptPackageNames(["rolling"], ["harmonic"]), + ).toEqual(["ros-rolling-ros-gz"]); }); }); diff --git a/dist/index.js b/dist/index.js index d51d04a..c303f74 100644 --- a/dist/index.js +++ b/dist/index.js @@ -26487,16 +26487,23 @@ function runLinux() { // Add repo according to Ubuntu version const ubuntuCodename = yield utils.determineDistribCodename(); yield addAptRepo(ubuntuCodename); + // Get list of Gazebo distributions const gazeboDistros = yield utils.getRequiredGazeboDistributions(); + // Check compatibility with Ubuntu version yield utils.checkUbuntuCompatibility(gazeboDistros, ubuntuCodename); - for (const gazeboDistro of gazeboDistros) { - yield apt.runAptGetInstall([`gz-${gazeboDistro}`]); - } + // Look for ROS 2 distributions for installing ros_gz const rosGzDistros = utils.checkForROSGz(); if (rosGzDistros.length > 0) { - const rosAptPackageNames = utils.generateROSAptPackageNames(rosGzDistros, gazeboDistros); + // Check for Gazebo vendor packages and generate appropriate package names + const rosAptPackageNames = utils.generateROSGzAptPackageNames(rosGzDistros, gazeboDistros); yield apt.runAptGetInstall(rosAptPackageNames); } + else { + // Install Gazebo as usual + for (const gazeboDistro of gazeboDistros) { + yield apt.runAptGetInstall([`gz-${gazeboDistro}`]); + } + } }); } @@ -26799,7 +26806,7 @@ exports.getRequiredGazeboDistributions = getRequiredGazeboDistributions; exports.checkUbuntuCompatibility = checkUbuntuCompatibility; exports.checkForUnstableAptRepos = checkForUnstableAptRepos; exports.checkForROSGz = checkForROSGz; -exports.generateROSAptPackageNames = generateROSAptPackageNames; +exports.generateROSGzAptPackageNames = generateROSGzAptPackageNames; const actions_exec = __importStar(__nccwpck_require__(1514)); const core = __importStar(__nccwpck_require__(2186)); const yaml_1 = __nccwpck_require__(4083); @@ -26813,11 +26820,25 @@ const validROSGzDistrosList = [ rosDistro: "humble", officialROSGzWrappers: ["fortress"], unofficialROSGzWrappers: ["garden", "harmonic"], + vendorPackagesAvailable: false, }, { rosDistro: "iron", officialROSGzWrappers: ["fortress"], unofficialROSGzWrappers: ["garden", "harmonic"], + vendorPackagesAvailable: false, + }, + { + rosDistro: "jazzy", + officialROSGzWrappers: ["harmonic"], + unofficialROSGzWrappers: [], + vendorPackagesAvailable: true, + }, + { + rosDistro: "rolling", + officialROSGzWrappers: ["harmonic"], + unofficialROSGzWrappers: [], + vendorPackagesAvailable: true, }, ]; /** @@ -26997,19 +27018,25 @@ function checkForROSGz() { * Generate APT package name from ROS 2 and Gazebo distribution names * * @param rosGzDistrosList ROS 2 distro ros_gz packages to be installed - * @param requiredGazeboDistributionsList Installed Gazebo distributions + * @param requiredGazeboDistributionsList Gazebo distributions to be installed * @returns string [] List of APT package names */ -function generateROSAptPackageNames(rosGzDistrosList, requiredGazeboDistributionsList) { - const rosAptPackageNames = []; +function generateROSGzAptPackageNames(rosGzDistrosList, requiredGazeboDistributionsList) { + const rosGzAptPackageNames = []; for (const rosDistro of rosGzDistrosList) { const distroInfo = validROSGzDistrosList.find((distro) => distro.rosDistro === rosDistro); for (const gazeboDistro of requiredGazeboDistributionsList) { + if (!distroInfo.vendorPackagesAvailable) { + const gzPkgName = `gz-${gazeboDistro}`; + if (rosGzAptPackageNames.indexOf(gzPkgName) < 0) { + rosGzAptPackageNames.push(gzPkgName); + } + } if (distroInfo.officialROSGzWrappers.indexOf(gazeboDistro) > -1) { - rosAptPackageNames.push(`ros-${rosDistro}-ros-gz`); + rosGzAptPackageNames.push(`ros-${rosDistro}-ros-gz`); } else if (distroInfo.unofficialROSGzWrappers.indexOf(gazeboDistro) > -1) { - rosAptPackageNames.push(`ros-${rosDistro}-ros-gz${gazeboDistro}`); + rosGzAptPackageNames.push(`ros-${rosDistro}-ros-gz${gazeboDistro}`); } else { throw new Error("Impossible ROS 2 and Gazebo combination requested. \ @@ -27018,7 +27045,7 @@ function generateROSAptPackageNames(rosGzDistrosList, requiredGazeboDistribution } } } - return rosAptPackageNames; + return rosGzAptPackageNames; } diff --git a/src/setup-gazebo-linux.ts b/src/setup-gazebo-linux.ts index 6e7942b..853a976 100644 --- a/src/setup-gazebo-linux.ts +++ b/src/setup-gazebo-linux.ts @@ -105,20 +105,26 @@ export async function runLinux(): Promise { const ubuntuCodename = await utils.determineDistribCodename(); await addAptRepo(ubuntuCodename); + // Get list of Gazebo distributions const gazeboDistros = await utils.getRequiredGazeboDistributions(); + // Check compatibility with Ubuntu version await utils.checkUbuntuCompatibility(gazeboDistros, ubuntuCodename); - for (const gazeboDistro of gazeboDistros) { - await apt.runAptGetInstall([`gz-${gazeboDistro}`]); - } - + // Look for ROS 2 distributions for installing ros_gz const rosGzDistros = utils.checkForROSGz(); + if (rosGzDistros.length > 0) { - const rosAptPackageNames = utils.generateROSAptPackageNames( + // Check for Gazebo vendor packages and generate appropriate package names + const rosAptPackageNames = utils.generateROSGzAptPackageNames( rosGzDistros, gazeboDistros, ); await apt.runAptGetInstall(rosAptPackageNames); + } else { + // Install Gazebo as usual + for (const gazeboDistro of gazeboDistros) { + await apt.runAptGetInstall([`gz-${gazeboDistro}`]); + } } } diff --git a/src/utils.ts b/src/utils.ts index b44bbcc..2696064 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -14,16 +14,31 @@ const validROSGzDistrosList: { rosDistro: string; officialROSGzWrappers: string[]; unofficialROSGzWrappers: string[]; + vendorPackagesAvailable: boolean; }[] = [ { rosDistro: "humble", officialROSGzWrappers: ["fortress"], unofficialROSGzWrappers: ["garden", "harmonic"], + vendorPackagesAvailable: false, }, { rosDistro: "iron", officialROSGzWrappers: ["fortress"], unofficialROSGzWrappers: ["garden", "harmonic"], + vendorPackagesAvailable: false, + }, + { + rosDistro: "jazzy", + officialROSGzWrappers: ["harmonic"], + unofficialROSGzWrappers: [], + vendorPackagesAvailable: true, + }, + { + rosDistro: "rolling", + officialROSGzWrappers: ["harmonic"], + unofficialROSGzWrappers: [], + vendorPackagesAvailable: true, }, ]; @@ -232,25 +247,31 @@ export function checkForROSGz(): string[] { * Generate APT package name from ROS 2 and Gazebo distribution names * * @param rosGzDistrosList ROS 2 distro ros_gz packages to be installed - * @param requiredGazeboDistributionsList Installed Gazebo distributions + * @param requiredGazeboDistributionsList Gazebo distributions to be installed * @returns string [] List of APT package names */ -export function generateROSAptPackageNames( +export function generateROSGzAptPackageNames( rosGzDistrosList: string[], requiredGazeboDistributionsList: string[], ): string[] { - const rosAptPackageNames: string[] = []; + const rosGzAptPackageNames: string[] = []; for (const rosDistro of rosGzDistrosList) { const distroInfo = validROSGzDistrosList.find( (distro) => distro.rosDistro === rosDistro, ); for (const gazeboDistro of requiredGazeboDistributionsList) { + if (!distroInfo!.vendorPackagesAvailable) { + const gzPkgName = `gz-${gazeboDistro}`; + if (rosGzAptPackageNames.indexOf(gzPkgName) < 0) { + rosGzAptPackageNames.push(gzPkgName); + } + } if (distroInfo!.officialROSGzWrappers.indexOf(gazeboDistro) > -1) { - rosAptPackageNames.push(`ros-${rosDistro}-ros-gz`); + rosGzAptPackageNames.push(`ros-${rosDistro}-ros-gz`); } else if ( distroInfo!.unofficialROSGzWrappers.indexOf(gazeboDistro) > -1 ) { - rosAptPackageNames.push(`ros-${rosDistro}-ros-gz${gazeboDistro}`); + rosGzAptPackageNames.push(`ros-${rosDistro}-ros-gz${gazeboDistro}`); } else { throw new Error( "Impossible ROS 2 and Gazebo combination requested. \ @@ -260,5 +281,5 @@ export function generateROSAptPackageNames( } } } - return rosAptPackageNames; + return rosGzAptPackageNames; }