Skip to content

Build package

Build package #1663

Workflow file for this run

name: Build package
# Push builds run on the integration branches; everything else (topic branches)
# is covered by the pull_request trigger, so a PR does not run twice per commit.
on:
push:
branches:
- main
- 'release/**'
pull_request:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
defaults:
run:
shell: bash
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
name: "Build & test (${{ matrix.ros2_distro }} / Ubuntu)"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# Each maintained ROS 2 distribution on its REP-2000 Ubuntu. Lyrical
# (Ubuntu 26.04) has no GitHub runner yet and is built in a container in
# the build-lyrical job below.
include:
- ros2_distro: humble
os: ubuntu-22.04
- ros2_distro: jazzy
os: ubuntu-24.04
- ros2_distro: kilted
os: ubuntu-24.04
- ros2_distro: rolling
os: ubuntu-24.04
env:
# Compile the generated message sources through ccache (restored below).
CCACHE_DIR: ${{ github.workspace }}/.ccache
steps:
- uses: actions/checkout@v7
- name: Restore ccache
uses: actions/cache@v6
with:
path: ${{ github.workspace }}/.ccache
key: ccache-${{ matrix.ros2_distro }}-${{ github.run_id }}
restore-keys: ccache-${{ matrix.ros2_distro }}-
# Enable ccache through its compiler masquerade (/usr/lib/ccache, populated
# when ccache is installed with the deps below). We deliberately do NOT set
# CMAKE_<LANG>_COMPILER_LAUNCHER: the runners already put /usr/lib/ccache on
# PATH, so a launcher on top double-wraps the compiler (ccache invoking
# ccache) and intermittently breaks CMake's compiler check.
- name: Enable ccache compiler masquerade
run: echo "/usr/lib/ccache" >> "$GITHUB_PATH"
# Reduce apt flakiness: the GitHub runners run background apt/unattended
# upgrades that hold the dpkg/apt locks, which intermittently makes
# setup-ros's apt step fail ("Unable to lock /var/lib/apt/lists/") and
# leaves ROS partially installed (later "No module named ament_package /
# rosidl_adapter / ament_cmake_test"). Stop those services, wait for the
# locks, and make apt retry transient mirror errors.
- name: Free apt and enable retries
run: |
sudo tee /etc/apt/apt.conf.d/80-ci-retries >/dev/null <<'EOF'
Acquire::Retries "5";
Acquire::http::Timeout "30";
Acquire::https::Timeout "30";
EOF
sudo systemctl stop apt-daily.timer apt-daily-upgrade.timer 2>/dev/null || true
sudo systemctl stop unattended-upgrades.service apt-daily.service apt-daily-upgrade.service 2>/dev/null || true
sudo systemctl kill --kill-who=all apt-daily.service apt-daily-upgrade.service 2>/dev/null || true
for _ in $(seq 1 60); do
if ! sudo fuser /var/lib/apt/lists/lock /var/lib/dpkg/lock /var/lib/dpkg/lock-frontend >/dev/null 2>&1; then
break
fi
sleep 2
done
# setup-ros and action-ros-ci are retried to absorb transient
# infrastructure failures (ros-apt-source GitHub-API 404s, apt mirror
# hiccups, and randomly incomplete installs), which otherwise need a
# manual job re-run.
#
# setup-ros is run *without* required-ros-distributions: that input
# installs the whole ros-<distro>-desktop (rviz, Qt, ...), which is huge
# and pointless for an interface package. Instead it only sets up the ROS
# apt source + ros-dev-tools, and action-ros-ci's rosdep step below pulls
# just px4_msgs's actual dependencies — much faster.
- name: Setup ROS 2 (retried)
uses: Wandalen/wretry.action@v3
with:
attempt_limit: 3
attempt_delay: 15000
action: ros-tooling/setup-ros@v0.7
# Install px4_msgs's exact build/test dependencies directly by apt package
# name, rather than relying on action-ros-ci's rosdep resolution. This is
# what keeps the lean install (no desktop) reliable and fast: it avoids
# both the intermittent "No module named ament_cmake_test" incomplete
# installs and rosdep key-resolution gaps (e.g. rosidl_default_generators
# not resolving on Noble for Rolling). rmw-fastrtps-cpp pulls a concrete
# typesupport implementation, without which rosidl's get_used_typesupports
# fails at configure time ("No 'rosidl_typesupport_c' found"). Idempotent,
# with retries.
- name: Ensure px4_msgs build and test dependencies
run: |
d="${{ matrix.ros2_distro }}"
for _ in 1 2 3; do
sudo apt-get update && sudo apt-get install -y --no-install-recommends \
ccache \
"ros-${d}-ament-cmake" \
"ros-${d}-rosidl-default-generators" \
"ros-${d}-rosidl-default-runtime" \
"ros-${d}-rmw-fastrtps-cpp" \
"ros-${d}-builtin-interfaces" \
"ros-${d}-ament-cmake-test" \
"ros-${d}-ament-lint-auto" \
"ros-${d}-ament-lint-common" && break
sleep 15
done
- name: Build and test (retried)
uses: Wandalen/wretry.action@v3
with:
attempt_limit: 3
attempt_delay: 15000
action: ros-tooling/action-ros-ci@v0.4
with: |
package-name: px4_msgs
target-ros2-distro: ${{ matrix.ros2_distro }}
# Lyrical targets Ubuntu 26.04 (resolute), for which GitHub has no runner yet,
# so this job runs inside the official ros:lyrical container and uses the same
# standard action-ros-ci tooling there.
build-lyrical:
name: "Build & test (lyrical / Ubuntu 26.04 container)"
runs-on: ubuntu-latest
container:
image: ros:lyrical-ros-base
defaults:
run:
shell: bash
env:
CCACHE_DIR: ${{ github.workspace }}/.ccache
steps:
- uses: actions/checkout@v7
- name: Restore ccache
uses: actions/cache@v6
with:
path: ${{ github.workspace }}/.ccache
key: ccache-lyrical-${{ github.run_id }}
restore-keys: ccache-lyrical-
- name: Install colcon, rosdep and lint tooling
run: |
apt-get update
apt-get install -y --no-install-recommends \
sudo ccache python3-colcon-common-extensions \
python3-colcon-lcov-result python3-colcon-coveragepy-result \
python3-rosdep python3-vcstool \
ros-lyrical-ament-cmake-test \
ros-lyrical-ament-lint-auto \
ros-lyrical-ament-lint-common
rosdep init 2>/dev/null || true
rosdep update
# Enable ccache via its masquerade (no COMPILER_LAUNCHER, which would
# double-wrap). The container has no /usr/lib/ccache on PATH by default,
# so add it now that ccache is installed.
echo "/usr/lib/ccache" >> "$GITHUB_PATH"
- uses: ros-tooling/action-ros-ci@v0.4
with:
package-name: px4_msgs
target-ros2-distro: lyrical
build-windows:
name: "Build & test (${{ matrix.ros2_distro }} / Windows)"
# Pinned to windows-2022 on purpose: action-ros-ci@v0.4 wraps every command
# in `call "...\Microsoft Visual Studio\2022\Enterprise\...\vcvars64.bat"`,
# a hardcoded path. windows-latest has rolled to windows-2025 (Visual Studio
# 2026), where that path does not exist, so every action-ros-ci command fails
# instantly. windows-2022 ships VS 2022 Enterprise at the expected location.
runs-on: windows-2022
strategy:
fail-fast: false
matrix:
# Windows coverage targets Jazzy only. ros-tooling pins setuptools<60,
# which has no distutils on Python 3.12, so the stack must run on Python
# 3.11 (see setup-python below). Jazzy's Windows binaries are built for
# 3.11 and work; Humble's target 3.8 and Rolling's target 3.12, so
# neither is compatible with the 3.11 that ros-tooling requires.
ros2_distro: [jazzy]
steps:
- uses: actions/checkout@v7
# Pin Python 3.11 to match Jazzy's Windows binaries and avoid ros-tooling's
# setuptools<60 / missing-distutils breakage on Python 3.12.
- uses: actions/setup-python@v6
with:
python-version: '3.11'
# NOTE: not wrapped in a retry action here. wretry injects the GitHub
# context as INPUT_GITHUB_CONTEXT, which exceeds the Windows environment
# variable length limit and breaks setup-ros's chocolatey installs.
- uses: ros-tooling/setup-ros@v0.7
with:
required-ros-distributions: ${{ matrix.ros2_distro }}
- uses: ros-tooling/action-ros-ci@v0.4
with:
package-name: px4_msgs
target-ros2-distro: ${{ matrix.ros2_distro }}
# ROS 2 no longer publishes macOS Homebrew bottles, so macOS is built via
# RoboStack (ROS 2 packaged on conda-forge), which provides binaries for
# osx-arm64 and osx-64. RoboStack only ships released distros for macOS, so
# this targets Jazzy.
build-macos:
name: "Build & test (jazzy / macOS, RoboStack)"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, macos-15-intel]
defaults:
run:
shell: bash -el {0}
steps:
- uses: actions/checkout@v7
with:
path: src/px4_msgs
- uses: mamba-org/setup-micromamba@v3
with:
environment-name: ros_jazzy
# Cache the solved/downloaded conda environment so re-runs skip the
# (slow) solve + download of ros-jazzy-ros-base.
cache-environment: true
cache-downloads: true
condarc: |
channels:
- conda-forge
- robostack-jazzy
create-args: >-
python=3.11
ros-jazzy-ros-base
ros-jazzy-ament-cmake
ros-jazzy-rosidl-default-generators
ros-jazzy-builtin-interfaces
ros-jazzy-ament-lint-auto
ros-jazzy-ament-lint-common
colcon-common-extensions
cmake
ninja
c-compiler
cxx-compiler
- name: Build
run: colcon build --packages-select px4_msgs --event-handlers console_cohesion+
- name: Test
# The ament_xmllint linter validates package.xml against the schema at
# http://download.ros.org/schema/package_format3.xsd, but conda-forge's
# libxml2 is built without HTTP support, so the fetch always fails with
# "No such file or directory". This linter is therefore unsupported on
# RoboStack/macOS and is excluded; xmllint still runs on the Ubuntu jobs.
run: colcon test --packages-select px4_msgs --event-handlers console_cohesion+ --return-code-on-test-failure --ctest-args -E xmllint
pre-commit:
name: "Lint (pre-commit)"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v6
with:
python-version: '3.x'
# Cache the installed pre-commit hook environments (node/python/go tools)
# so they are not reinstalled on every run.
- uses: actions/cache@v6
with:
path: ~/.cache/pre-commit
key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
- uses: pre-commit/action@v3.0.1