diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 415efc4d..72bb6e4b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,10 +7,11 @@ on: branches: [ main ] jobs: - no-ros: - name: ROS-independent Test + nix-matrix: + name: Generate Nix CI Matrix runs-on: ubuntu-latest - + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - name: Checkout repository uses: actions/checkout@v4 @@ -23,63 +24,22 @@ jobs: experimental-features = nix-command flakes accept-flake-config = true - - name: Setup sccache - if: env.ACT != 'true' - uses: mozilla-actions/sccache-action@v0.0.9 - - - name: Check Nix formatting - run: | - nix fmt -- --check flake.nix - - - name: Check Markdown formatting - run: | - nix develop '.#noRos-ci' -c markdownlint '**/*.md' - - - name: Check Rust formatting - run: | - nix develop '.#noRos-ci' -c cargo fmt --all -- --check - - - name: Clippy (default workspace) - run: | - nix develop '.#noRos-ci' -c cargo clippy --lib --bins --tests -- -D warnings - - - name: Check default workspace - run: | - nix develop '.#noRos-ci' -c cargo check - - - name: Build default workspace - run: | - nix develop '.#noRos-ci' -c cargo build - - - name: Build examples without ROS dependencies - run: | - nix develop '.#noRos-ci' -c cargo build --example z_custom_message - - - name: Run tests - run: | - nix develop '.#noRos-ci' -c cargo test - - - name: Check ros-z-msgs with bundled messages (no ROS required) - run: | - nix develop '.#noRos-ci' -c cargo check -p ros-z-msgs - nix develop '.#noRos-ci' -c cargo check -p ros-z-msgs --features bundled_msgs - nix develop '.#noRos-ci' -c cargo check -p ros-z-msgs --features common_interfaces + - name: Setup Magic Nix Cache + uses: DeterminateSystems/magic-nix-cache-action@v8 - - name: Build ros-z-msgs with individual bundled packages + - name: Generate CI matrix from flake + id: set-matrix run: | - nix develop '.#noRos-ci' -c cargo build -p ros-z-msgs --no-default-features --features std_msgs - nix develop '.#noRos-ci' -c cargo build -p ros-z-msgs --no-default-features --features geometry_msgs - nix develop '.#noRos-ci' -c cargo build -p ros-z-msgs --no-default-features --features sensor_msgs - nix develop '.#noRos-ci' -c cargo build -p ros-z-msgs --no-default-features --features nav_msgs + set -euo pipefail + matrix="$(nix eval --json '.#githubActions.matrix')" + echo "matrix=$matrix" >> "$GITHUB_OUTPUT" - with-ros: - name: ROS-dependent Test (${{ matrix.distro }}) + nix-build: + name: ${{ matrix.attr }} + needs: nix-matrix runs-on: ubuntu-latest strategy: - matrix: - distro: [jazzy] - # distro: [jazzy, rolling] # Uncomment to test rolling when stable - + matrix: ${{fromJSON(needs.nix-matrix.outputs.matrix)}} steps: - name: Checkout repository uses: actions/checkout@v4 @@ -99,50 +59,11 @@ jobs: with: name: ros authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' - skipPush: true - - - name: Setup sccache - if: env.ACT != 'true' - uses: mozilla-actions/sccache-action@v0.0.9 - - - name: Check rcl-z - run: | - nix develop '.#${{ matrix.distro }}-ci' -c cargo check -p rcl-z - - - name: Check ros-z-msgs (default bundled features) - run: | - nix develop '.#${{ matrix.distro }}-ci' -c cargo check -p ros-z-msgs - - - name: Check ros-z-msgs with external messages - run: | - nix develop '.#${{ matrix.distro }}-ci' -c cargo check -p ros-z-msgs --features external_msgs - nix develop '.#${{ matrix.distro }}-ci' -c cargo check -p ros-z-msgs --features example_interfaces + # Push build outputs to cachix for reuse + skipPush: false - - name: Check ros-z-msgs with all messages (bundled + external) - run: | - nix develop '.#${{ matrix.distro }}-ci' -c cargo check -p ros-z-msgs --features all_msgs - - - name: Check with protobuf feature - run: | - nix develop '.#${{ matrix.distro }}-ci' -c cargo check -p ros-z -p ros-z-msgs --features ros-z/protobuf,ros-z-msgs/protobuf - - - name: Check ros-z (with rcl-z feature) - run: | - nix develop '.#${{ matrix.distro }}-ci' -c cargo check -p ros-z --features rcl-z - - - name: Build ROS message examples - run: | - nix develop '.#${{ matrix.distro }}-ci' -c cargo build -p ros-z-msgs - nix develop '.#${{ matrix.distro }}-ci' -c cargo build --example twist_pub - nix develop '.#${{ matrix.distro }}-ci' -c cargo build --example battery_state_sub - nix develop '.#${{ matrix.distro }}-ci' -c cargo build --example laser_scan - nix develop '.#${{ matrix.distro }}-ci' -c cargo build --example z_srvcli --features external_msgs - - - name: Build protobuf demo - run: | - nix develop '.#${{ matrix.distro }}-ci' -c cargo build -p protobuf_demo + - name: Setup Magic Nix Cache + uses: DeterminateSystems/magic-nix-cache-action@v8 - # FIXME: This requires the installation of rmw_zenoh_cpp triggering a build from source... - # - name: Run unit tests - # run: | - # nix develop .#ci -c cargo test --all-features + - name: Run check + run: nix build -L '.#${{ matrix.attr }}' diff --git a/README.md b/README.md index af3c34af..915e1fe6 100644 --- a/README.md +++ b/README.md @@ -108,13 +108,12 @@ nix develop .#noRos-ci **Note on `ros-z-msgs`:** This package can build without ROS installed! When ROS is not available, it automatically falls back to using bundled message -definitions from the roslibrust repository. The build system searches for ROS -packages in this order: +definitions from the roslibrust git dependency. The build system searches for +ROS packages in this order: 1. System ROS installation (via `AMENT_PREFIX_PATH` or `CMAKE_PREFIX_PATH`) 2. Common ROS installation paths (`/opt/ros/{rolling,jazzy,iron,humble}`) -3. Local roslibrust checkout (`../../roslibrust/assets/`) -4. Roslibrust git dependency (`~/.cargo/git/checkouts/roslibrust-*/assets/`) +3. Roslibrust git dependency (`~/.cargo/git/checkouts/roslibrust-*/assets/`) This allows `ros-z-msgs` to generate message types even in environments without ROS 2 installed. The default `common_interfaces` feature includes `std_msgs`, diff --git a/ci.nix b/ci.nix new file mode 100644 index 00000000..a9940a12 --- /dev/null +++ b/ci.nix @@ -0,0 +1,181 @@ +# CI checks module +# This module defines all CI checks for ros-z project +{ + pkgs, + self, + commonBuildInputs, + mkRosEnv, + exportEnvVars, +}: +let + # Vendor Cargo dependencies for sandboxed builds + cargoVendorDir = pkgs.rustPlatform.importCargoLock { + lockFile = ./Cargo.lock; + outputHashes = { + "cdr-encoding-0.10.2" = "sha256-bpo8Fu3Qp5TapzFFAvyRJdSiO50G3YBBTSJNV/cNa4Y="; + "roslibrust-0.16.0" = "sha256-qi4h1ksC/iLwK1uiUs6LU9CX3RDYVOd6E4SRdUAbqZo="; + }; + }; + + # Fetch roslibrust git repo for assets directory (with submodules for ros2_common_interfaces) + roslibrustSrc = pkgs.fetchgit { + url = "https://github.com/YuanYuYuan/roslibrust"; + rev = "f08547babb04c3b19a77af9a55a10b8148908e55"; # dev/ros-z branch + hash = "sha256-qi4h1ksC/iLwK1uiUs6LU9CX3RDYVOd6E4SRdUAbqZo="; + fetchSubmodules = true; + }; +in +let + # Create a cargo check that runs in sandbox with vendored dependencies + mkCargoCheck = + { + name, + packages, + rosEnv ? null, + script, + extraAttrs ? { }, + }: + pkgs.stdenv.mkDerivation ( + { + name = "check-${name}"; + src = self; + nativeBuildInputs = packages ++ [ pkgs.nixfmt-rfc-style ]; # For format checks + buildInputs = pkgs.lib.optional (rosEnv != null) rosEnv; + + # Disable ROS setup hooks that interfere with Cargo builds + dontUseCmakeConfigure = true; + dontUseColconBuildSetup = true; + + buildPhase = '' + # Export environment variables + ${exportEnvVars} + + # Disable sccache in sandbox (no HOME directory) + unset RUSTC_WRAPPER + + # Setup ROS environment if provided + ${pkgs.lib.optionalString (rosEnv != null) '' + export AMENT_PREFIX_PATH="${rosEnv}" + export CMAKE_PREFIX_PATH="${rosEnv}" + ''} + + # Setup vendored cargo dependencies + export CARGO_HOME=$(pwd)/.cargo + mkdir -p .cargo + cat > .cargo/config.toml < PathBuf { } } - // Fallback: return the local path anyway, it will fail gracefully if it doesn't exist - println!("cargo:warning=Could not find roslibrust assets, packages may not be available"); - local_path + // Fallback: panic with helpful error message + panic!( + "Could not find roslibrust assets directory!\n\ + Make sure roslibrust is specified as a git dependency in Cargo.toml.\n\ + The build system searches for:\n\ + 1. ROSLIBRUST_ASSETS_DIR environment variable\n\ + 2. ~/.cargo/git/checkouts/roslibrust-*/*/assets/" + ); }