Skip to content

Commit

Permalink
Installing ROS 2 and Gazebo side-by-side along with ros_gz (#65)
Browse files Browse the repository at this point in the history
* Addded check for ros_gz

Signed-off-by: Saurabh Kamat <[email protected]>

* Changed command to use callback for stdout output

Signed-off-by: Saurabh Kamat <[email protected]>

* Added exec options for getting ros distros

Signed-off-by: Saurabh Kamat <[email protected]>

* Added apt install on ros distros

Signed-off-by: Saurabh Kamat <[email protected]>

* Updated ros_gz install to take multiple ROS 2 distro inputs

Signed-off-by: Saurabh Kamat <[email protected]>

* Implemented check on ros_gz installtion

Signed-off-by: Saurabh Kamat <[email protected]>

* Updated tests for ros_gz

Signed-off-by: Saurabh Kamat <[email protected]>

* Fixed typo in package name

Signed-off-by: Saurabh Kamat <[email protected]>

* Updated workflow test

Signed-off-by: Saurabh Kamat <[email protected]>

* Changed test to install iron and rolling

Signed-off-by: Saurabh Kamat <[email protected]>

* Changed env variable

Signed-off-by: Saurabh Kamat <[email protected]>

* Testing different env variable

Signed-off-by: Saurabh Kamat <[email protected]>

* Updated workflow test

Signed-off-by: Saurabh Kamat <[email protected]>

* Added pkg name generation test

Signed-off-by: Saurabh Kamat <[email protected]>

* Testing ros_gz installation in workflow

Signed-off-by: Saurabh Kamat <[email protected]>

* Added additional tests for ros_gz

Signed-off-by: Saurabh Kamat <[email protected]>

* Updated README with ros_gz installation instructions

Signed-off-by: Saurabh Kamat <[email protected]>

* Added env variable for ros_gz workflow

Signed-off-by: Saurabh Kamat <[email protected]>

* Updated README with env var in ros_gz usage

Signed-off-by: Saurabh Kamat <[email protected]>

* Removed rolling and jazzy from ros distro list

Signed-off-by: Saurabh Kamat <[email protected]>

* Updated workflow tests

Signed-off-by: Saurabh Kamat <[email protected]>

* Fixed test command in workflow

Signed-off-by: Saurabh Kamat <[email protected]>

* Updated README

Signed-off-by: Saurabh Kamat <[email protected]>

* Changed Ros to ROS in variables names

Signed-off-by: Saurabh Kamat <[email protected]>

* Updated README

Signed-off-by: Saurabh Kamat <[email protected]>

* Added additional information about ros_gz install

Signed-off-by: Saurabh Kamat <[email protected]>

---------

Signed-off-by: Saurabh Kamat <[email protected]>
  • Loading branch information
sauk2 authored Sep 23, 2024
1 parent dc5f248 commit 876256c
Show file tree
Hide file tree
Showing 7 changed files with 325 additions and 1 deletion.
54 changes: 54 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,57 @@ jobs:
run: |
conda activate
gz sim --versions
test_install_ros_gz_unofficial:
name: 'Install Iron and Harmonic side-by-side'
env:
ROS_DISTROS: 'iron'
runs-on: ubuntu-latest
container:
image: ubuntu:jammy
steps:
- uses: actions/checkout@v4
- uses: actions/[email protected]
with:
node-version: '20.x'
- name: 'Install ROS 2 Iron'
uses: ros-tooling/[email protected]
with:
required-ros-distributions: ${{ env.ROS_DISTROS }}
- name: 'Install Gazebo Harmonic with ros_gz'
uses: ./
with:
required-gazebo-distributions: 'harmonic'
install-ros-gz: ${{ env.ROS_DISTROS }}
- name: Test Iron ros_gz installation
run: |
source /opt/ros/iron/setup.bash
ros2 pkg list | grep ros_gz
gz sim --version | grep 'version 8.[0-9*].[0-9*]'
test_install_ros_gz_official:
name: 'Install Humble and Fortress side-by-side'
env:
ROS_DISTROS: 'humble'
runs-on: ubuntu-latest
container:
image: ubuntu:jammy
steps:
- uses: actions/checkout@v4
- uses: actions/[email protected]
with:
node-version: '20.x'
- name: 'Install ROS 2 Humble'
uses: ros-tooling/[email protected]
with:
required-ros-distributions: ${{ env.ROS_DISTROS }}
- name: 'Install Gazebo with ros_gz'
uses: ./
with:
required-gazebo-distributions: 'fortress'
install-ros-gz: ${{ env.ROS_DISTROS }}
- name: Test Humble ros_gz installation
run: |
source /opt/ros/humble/setup.bash
ros2 pkg list | grep ros_gz
ign gazebo --version | grep 'version 6.*'
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ This action sets up a Gazebo environment.
1. [Setting up worker and installing a compatible Gazebo and Ubuntu combination](#Setting-up-worker-and-installing-a-compatible-Gazebo-and-Ubuntu-combination)
1. [Iterating on all Gazebo and Ubuntu combinations](#Iterating-on-all-gazebo-ubuntu-combinations)
1. [Using pre-release and/or nightly Gazebo binaries](#Using-pre-release-and/or-nightly-Gazebo-binaries)
1. [Installing ROS 2 and Gazebo side-by-side along with `ros_gz`](#Installing-ROS-2-and-Gazebo-side-by-side-along-with-ros_gz)
2. [macOS](#macOS)
1. [Setting up worker to install Gazebo on macOS](#Setting-up-worker-to-install-Gazebo-on-macOS)
3. [Windows](#Windows)
Expand All @@ -25,6 +26,7 @@ The `setup-gazebo` GitHub Action sets up an environment to install a Gazebo rele
- `required-gazebo-distributions`: A **required** parameter that specifies the Gazebo distribution to be installed.
- `use-gazebo-prerelease`: An **optional** parameter to install pre-release binaries from OSRF repository.
- `use-gazebo-nightly`: An **optional** parameter to install nightly binaries from OSRF repository.
- `install-ros-gz`: An **optional** parameter to install the ROS 2 Gazebo bridge (`ros_gz`). This will require a previous ROS installation which can be done using the [`setup-ros`](https://github.com/ros-tooling/setup-ros) GitHub action. Installation of the `ros_gz` bridge supports the ROS official and ROS non-official (from packages.osrfoundation.org) variants following the [Installing Gazebo with ROS](https://gazebosim.org/docs/ionic/ros_installation/#summary-of-compatible-ros-and-gazebo-combinations) documentation.

## Supported platforms

Expand All @@ -45,6 +47,7 @@ The `setup-gazebo` action performs the following tasks:
- Tapping into the [osrf/homebrew-simulation](https://github.com/osrf/homebrew-simulation) using Homebrew
- On Windows:
- Installing Gazebo using Conda from conda-forge

## Usage

See [action.yml](action.yml)
Expand Down Expand Up @@ -239,6 +242,39 @@ This workflow shows how to use binaries from [pre-release] or [nightly] Gazebo r
run: 'gz sim --versions'
```

#### Installing ROS 2 and Gazebo side-by-side along with `ros_gz`

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.

```yaml
jobs:
test_gazebo:
env:
ROS_DISTROS: 'iron'
runs-on: ubuntu-latest
container:
image: ubuntu:jammy
steps:
- uses: actions/checkout@v4
- uses: actions/[email protected]
with:
node-version: '20.x'
- name: 'Install ROS 2 Iron'
uses: ros-tooling/[email protected]
with:
required-ros-distributions: ${{ env.ROS_DISTROS }}
- name: 'Install Gazebo Harmonic with ros_gz'
uses: gazebo-tooling/[email protected]
with:
required-gazebo-distributions: 'harmonic'
install-ros-gz: ${{ env.ROS_DISTROS }}
- name: Test Iron ros_gz installation
run: |
source /opt/ros/iron/setup.bash
ros2 pkg list | grep ros_gz
gz sim --version | grep 'version 8.[0-9*].[0-9*]'
```

### macOS

#### Setting up worker to install Gazebo on macOS
Expand Down
38 changes: 37 additions & 1 deletion __test__/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ describe("workflow test with a invalid distro input", () => {
beforeAll(() => {
jest.spyOn(exec, "exec").mockImplementation(jest.fn());
jest.spyOn(core, "getInput").mockReturnValue("dome");
jest.spyOn(utils, "checkForROSGz").mockReturnValue([]);
});

afterAll(() => {
Expand All @@ -55,6 +56,7 @@ describe("workflow test with a valid distro input", () => {
beforeAll(() => {
jest.spyOn(exec, "exec").mockImplementation(jest.fn());
jest.spyOn(core, "getInput").mockReturnValue("harmonic");
jest.spyOn(utils, "checkForROSGz").mockReturnValue([]);
jest
.spyOn(utils, "determineDistribCodename")
.mockReturnValue(Promise.resolve("jammy"));
Expand All @@ -77,7 +79,7 @@ describe("workflow test with a valid distro input", () => {
});
});

describe("validate distribution test", () => {
describe("validate Gazebo distribution test", () => {
it("test valid distro", async () => {
await expect(utils.validateDistro(["citadel"])).resolves.not.toThrow();
await expect(utils.validateDistro(["fortress"])).resolves.not.toThrow();
Expand All @@ -100,10 +102,29 @@ describe("validate distribution test", () => {
});
});

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(["humble", "iron"])).toBe(true);
});
it("test invalid distro", async () => {
await expect(utils.validateROSDistro(["noetic"])).toBe(false);
await expect(utils.validateROSDistro(["foxy"])).toBe(false);
await expect(utils.validateROSDistro(["galactic"])).toBe(false);
await expect(utils.validateROSDistro(["doesNotExist"])).toBe(false);
await expect(utils.validateROSDistro(["noetic", "humble"])).toBe(false);
await expect(utils.validateROSDistro(["foxy", "galactic", "jazzy"])).toBe(
false,
);
});
});

describe("workflow test with incompatible Ubuntu combination", () => {
beforeAll(() => {
jest.spyOn(exec, "exec").mockImplementation(jest.fn());
jest.spyOn(core, "getInput").mockReturnValue("harmonic");
jest.spyOn(utils, "checkForROSGz").mockReturnValue([]);
jest
.spyOn(utils, "determineDistribCodename")
.mockReturnValue(Promise.resolve("focal"));
Expand All @@ -130,6 +151,7 @@ describe("check for unstable repositories input", () => {
.spyOn(utils, "checkForUnstableAptRepos")
.mockReturnValueOnce(["prerelease", "nightly"]);
jest.spyOn(core, "getInput").mockReturnValue("harmonic");
jest.spyOn(utils, "checkForROSGz").mockReturnValue([]);
jest
.spyOn(utils, "determineDistribCodename")
.mockReturnValue(Promise.resolve("jammy"));
Expand All @@ -151,3 +173,17 @@ describe("check for unstable repositories input", () => {
await expect(linux.runLinux()).resolves.not.toThrow();
});
});

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"]);
await expect(
utils.generateROSAptPackageNames(["humble"], ["fortress"]),
).toEqual(["ros-humble-ros-gz"]);
await expect(
utils.generateROSAptPackageNames(["iron"], ["fortress", "garden"]),
).toEqual(["ros-iron-ros-gz", "ros-iron-ros-gzgarden"]);
});
});
12 changes: 12 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ inputs:
Use nightly binaries from OSRF repository
required: false
default: 'false'
install-ros-gz:
description: |
Install the ROS 2 Gazebo bridge (ros_gz)
Allowed ROS 2 distributions
- humble
- iron
Multiple values can be passed using a whitespace delimited list
"humble iron".
required: false
default: ''
runs:
using: node20
main: dist/index.js
83 changes: 83 additions & 0 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26492,6 +26492,11 @@ function runLinux() {
for (const gazeboDistro of gazeboDistros) {
yield apt.runAptGetInstall([`gz-${gazeboDistro}`]);
}
const rosGzDistros = utils.checkForROSGz();
if (rosGzDistros.length > 0) {
const rosAptPackageNames = utils.generateROSAptPackageNames(rosGzDistros, gazeboDistros);
yield apt.runAptGetInstall(rosAptPackageNames);
}
});
}

Expand Down Expand Up @@ -26789,14 +26794,32 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.exec = exec;
exports.determineDistribCodename = determineDistribCodename;
exports.validateDistro = validateDistro;
exports.validateROSDistro = validateROSDistro;
exports.getRequiredGazeboDistributions = getRequiredGazeboDistributions;
exports.checkUbuntuCompatibility = checkUbuntuCompatibility;
exports.checkForUnstableAptRepos = checkForUnstableAptRepos;
exports.checkForROSGz = checkForROSGz;
exports.generateROSAptPackageNames = generateROSAptPackageNames;
const actions_exec = __importStar(__nccwpck_require__(1514));
const core = __importStar(__nccwpck_require__(2186));
const yaml_1 = __nccwpck_require__(4083);
// Collections file that contains all the valid Gazebo distributions along all compatiblity information
const collections_url = "https://raw.githubusercontent.com/gazebo-tooling/release-tools/master/jenkins-scripts/dsl/gz-collections.yaml";
// List of valid ROS 2 distributions and compatible Gazebo mapping
// For more information check the following link
// https://gazebosim.org/docs/latest/ros_installation/#summary-of-compatible-ros-and-gazebo-combinations
const validROSGzDistrosList = [
{
rosDistro: "humble",
officialROSGzWrappers: ["fortress"],
unofficialROSGzWrappers: ["garden", "harmonic"],
},
{
rosDistro: "iron",
officialROSGzWrappers: ["fortress"],
unofficialROSGzWrappers: ["garden", "harmonic"],
},
];
/**
* Execute a command and wrap the output in a log group.
*
Expand Down Expand Up @@ -26858,6 +26881,23 @@ function validateDistro(requiredGazeboDistributionsList) {
});
});
}
/**
* Validate all ROS distribution names
*
* @param rosGzDistrosList
* @returns boolean Validaity of the ROS distribution
*/
function validateROSDistro(rosGzDistrosList) {
if (rosGzDistrosList.length > 0) {
const validDistro = validROSGzDistrosList.map((obj) => obj.rosDistro);
for (const rosDistro of rosGzDistrosList) {
if (validDistro.indexOf(rosDistro) <= -1) {
return false;
}
}
}
return true;
}
/**
* Gets the input of the Gazebo distributions to be installed and
* validates them
Expand Down Expand Up @@ -26937,6 +26977,49 @@ function checkForUnstableAptRepos() {
}
return unstableRepos;
}
/**
* Check for inputs to install ros-gz
*
* @returns requiredROSDistroList list of valid ROS 2 distributions
*/
function checkForROSGz() {
let requiredROSDistroList = [];
const installROSGz = core.getInput("install-ros-gz");
if (installROSGz) {
requiredROSDistroList = installROSGz.split(RegExp("\\s"));
if (!validateROSDistro(requiredROSDistroList)) {
throw new Error("Input has invalid ROS 2 distribution names.");
}
}
return requiredROSDistroList;
}
/**
* 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
* @returns string [] List of APT package names
*/
function generateROSAptPackageNames(rosGzDistrosList, requiredGazeboDistributionsList) {
const rosAptPackageNames = [];
for (const rosDistro of rosGzDistrosList) {
const distroInfo = validROSGzDistrosList.find((distro) => distro.rosDistro === rosDistro);
for (const gazeboDistro of requiredGazeboDistributionsList) {
if (distroInfo.officialROSGzWrappers.indexOf(gazeboDistro) > -1) {
rosAptPackageNames.push(`ros-${rosDistro}-ros-gz`);
}
else if (distroInfo.unofficialROSGzWrappers.indexOf(gazeboDistro) > -1) {
rosAptPackageNames.push(`ros-${rosDistro}-ros-gz${gazeboDistro}`);
}
else {
throw new Error("Impossible ROS 2 and Gazebo combination requested. \
Please check the list of compatible combinations at \
https://gazebosim.org/docs/latest/ros_installation/#summary-of-compatible-ros-and-gazebo-combinations");
}
}
}
return rosAptPackageNames;
}


/***/ }),
Expand Down
11 changes: 11 additions & 0 deletions src/setup-gazebo-linux.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import * as core from "@actions/core";
import * as io from "@actions/io";
import * as actions_exec from "@actions/exec";
import * as im from "@actions/exec/lib/interfaces";

import * as apt from "./package_manager/apt";
import * as utils from "./utils";
Expand Down Expand Up @@ -110,4 +112,13 @@ export async function runLinux(): Promise<void> {
for (const gazeboDistro of gazeboDistros) {
await apt.runAptGetInstall([`gz-${gazeboDistro}`]);
}

const rosGzDistros = utils.checkForROSGz();
if (rosGzDistros.length > 0) {
const rosAptPackageNames = utils.generateROSAptPackageNames(
rosGzDistros,
gazeboDistros,
);
await apt.runAptGetInstall(rosAptPackageNames);
}
}
Loading

0 comments on commit 876256c

Please sign in to comment.