GitHub Actions を使った ROS2 パッケージの CI/CD 構築ガイド

# GitHub Actions を使った ROS2 パッケージの CI/CD 構築ガイド

GitHub Actions を使用して、ROS2 パッケージの継続的インテグレーション（CI）と継続的デプロイ（CD）を実現する方法を解説する。


## そもそもCI/CD とは？

### **CI（継続的インテグレーション）**
CI とは、開発者がコードをリポジトリに統合するたびに、自動でビルドやテストを実行するプロセスを指す。
このプロセスにより、コードの変更が他の部分に影響を及ぼさないかを素早く確認できる。

### **CD（継続的デプロイ/デリバリー）**
CD は、変更されたコードを本番環境またはステージング環境に自動でデプロイするプロセスを指す。
これにより、手動のデプロイ作業を減らし、変更を迅速にリリースすることができます。

### **CI/CD を導入するメリット**
1. **品質の向上**
   - 自動ビルドとテストにより、コードの問題を早期に発見可能。
2. **エラーの早期検出**
   - 問題が発生した時点で通知されるため、大きな障害になる前に対応可能。
3. **一貫性の確保**
   - 自動化により、手動ミスがなくなる。


## GitHub Actions とは？

GitHub Actions は、GitHub に統合された CI/CD プラットフォームで、リポジトリ内のコードの変更をトリガーとして、自動でビルド、テスト、デプロイを実行できる。

### **GitHub Actions の特徴**

- **簡単な設定**: リポジトリ内に `.github/workflows` ディレクトリを作成し、YAML ファイルで設定を記述するだけ。
- **柔軟なトリガー**: プッシュやプルリクエスト、スケジュールなど、さまざまな条件でワークフローを実行可能。
- **統合環境**: GitHub リポジトリに直接統合され、外部ツールが不要。
- **カスタマイズ性**: 自分でアクション（ジョブ）を作成したり、GitHub Marketplace から再利用可能なアクションを利用可能。

### **使用時間制限と料金**

GitHub Actions の実行時間には制限があります。以下は主な制限と料金プランです。（記事を書いた時点で）

1. **無料プラン**:
   - パブリックリポジトリの場合: 無料で無制限に利用可能。
   - プライベートリポジトリの場合: 月間 2,000 分まで無料。

2. **有料プラン**:
   - 制限を超えた場合、追加料金が発生します（GitHub のプランによります）。
   - 詳細は [GitHub Actions の料金ページ](https://github.com/pricing) を参照してください。

3. **実行環境の制約**:
   - 仮想マシン上で実行されるため、物理デバイスに依存するジョブ（シリアルポートや特定のハードウェアを必要とするジョブ）は動作しない。
   - 使用可能なランナーには `ubuntu-22.04`、`macos-latest`、`windows-latest` などがある。


## 概要

### **この記事で実現すること**

1. **ROS2 パッケージのビルドを自動化**
   - ROS2 Humble 環境で `colcon build` を自動実行。
2. **ノードの動作確認を自動化**
   - 各ノードが正常に起動するか確認。
   - シリアルポートなどの物理デバイスに依存するノードはスキップ。

## 前提条件

1. GitHub に ROS2 パッケージのリポジトリがあること。
2. ROS2 Humble を使用していること。
3. GitHub Actions を有効にしていること。

## 手順

### **1. GitHub Actions ワークフローの作成**

リポジトリのルートディレクトリに `.github/workflows/main.yml` を作成する。

以下のset up a worflow yourselfをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3336552/014eb422-13fe-0b2c-6ca7-467f34b66718.png)


以下は、完成したワークフローのコードである。
このコードをもとに、記事で各部分を詳しく解説していく。

```yaml
name: Validate ROS2 Package

on:
  schedule:
    - cron: '0 22 * * *'  # 毎日日本時間朝7:00に実行 (UTC 22:00)
  push:
    branches:
      - main

jobs:
  validate_ros2_package:
    runs-on: ubuntu-22.04

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Set up ROS2 Humble
        run: |
          sudo apt update && sudo apt install -y curl gnupg lsb-release
          sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo gpg --dearmor -o /usr/share/keyrings/ros-archive-keyring.gpg
          echo "deb [signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/ros2-latest.list > /dev/null
          sudo apt update
          sudo apt install -y ros-humble-desktop python3-colcon-common-extensions python3-rosdep
          sudo rosdep init || true
          rosdep update

      - name: Build workspace
        run: |
          source /opt/ros/humble/setup.bash
          colcon build

      - name: Validate Roboware_node
        run: |
          source /opt/ros/humble/setup.bash
          source install/setup.bash
          nohup ros2 run Robowarepkg Roboware_node > roboware_node.log 2>&1 &
          sleep 5
          pkill -f "ros2 run Robowarepkg Roboware_node"
          if grep -q "ERROR" roboware_node.log; then
            cat roboware_node.log
            exit 1
          fi

      - name: Skip serial_send_node validation
        run: |
          echo "Skipping serial_send_node validation as it depends on serial port hardware."

      - name: Validate web_socket_node
        run: |
          source /opt/ros/humble/setup.bash
          source install/setup.bash
          nohup ros2 run Robowarepkg web_socket_node > web_socket_node.log 2>&1 &
          sleep 5
          pkill -f "ros2 run Robowarepkg web_socket_node"
          if grep -q "ERROR" web_socket_node.log; then
            cat web_socket_node.log
            exit 1
          fi
```

### **2. 各ステップの詳細解説**

#### **(1) コードのチェックアウト**

まず、リポジトリのコードをクローンする。

```yaml
- name: Checkout code
  uses: actions/checkout@v3
```

#### **(2) ROS2 Humble のセットアップ**

GitHub Actions の仮想環境に ROS2 Humble をインストール。仮想環境はクリーンな状態で開始されるため、毎回 ROS2 のインストールが必要。

```yaml
- name: Set up ROS2 Humble
  run: |
    sudo apt update && sudo apt install -y curl gnupg lsb-release
    sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo gpg --dearmor -o /usr/share/keyrings/ros-archive-keyring.gpg
    echo "deb [signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/ros2-latest.list > /dev/null
    sudo apt update
    sudo apt install -y ros-humble-desktop python3-colcon-common-extensions python3-rosdep
    sudo rosdep init || true
    rosdep update
```

#### **(3) ビルドの実行**

`colcon build` を使用して ROS2 ワークスペースをビルド。

```yaml
- name: Build workspace
  run: |
    source /opt/ros/humble/setup.bash
    colcon build
```

#### **(4) ノードの起動と検証**

各ノードをバックグラウンドで起動し、動作を確認します。ログファイルにエラーが含まれていればテストを失敗として終了する。

```yaml
- name: Validate Roboware_node
  run: |
    source /opt/ros/humble/setup.bash
    source install/setup.bash
    nohup ros2 run Robowarepkg Roboware_node > roboware_node.log 2>&1 &
    sleep 5
    pkill -f "ros2 run Robowarepkg Roboware_node"
    if grep -q "ERROR" roboware_node.log; then
      cat roboware_node.log
      exit 1
    fi
```

#### **(5) シリアルポート依存のノードをスキップ**

シリアルポートなどのハードウェアに依存するノードは仮想環境では実行できないため、明示的にスキップします。

```yaml
- name: Skip serial_send_node validation
  run: |
    echo "Skipping serial_send_node validation as it depends on serial port hardware."
```

---

### **3. ワークフローの実行確認**

ワークフローをリポジトリにプッシュすると、自動的に GitHub Actions の「Actions」タブで実行が開始される。

以下例

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3336552/f8ace0f6-f767-2859-6c61-aae772807824.png)


## まとめ

GitHub Actions を使用することで、ROS2 パッケージのビルドと基本的な動作確認を自動化できる。この仕組みを活用すれば、毎回手動でテストを行う必要がなくなり、開発効率が向上する。また、スケジュール実行を設定することで、日々の変更がシステム全体に与える影響をすぐに検出できる。ぜひロボコンなどの開発で使ってみよう。