0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【C言語×GitHub Actions CI#5】組込みC言語プロジェクトにCIを導入する:GitLab経験者向けワークフロー構文解説

0
Last updated at Posted at 2026-05-28

はじめに

本記事は全5部構成シリーズの最終回です。

筆者はGitLab CIを業務で使っており、stages / artifacts / needs / extends / rules などを活用した経験があります。今回GitHub Actionsを初めて使うにあたり、「GitLab CIのあの概念はGitHub Actionsではどう書くのか」という視点で理解を整理しました。同じような背景を持つ方の参考になれば幸いです。

サンプルコードはこちらです。
https://github.com/YusukeHarada/c-sample


全体構造の対応関係

まずファイルと全体構造の対応から整理します。

GitLab CI GitHub Actions 備考
.gitlab-ci.yml .github/workflows/ci.yml ファイルの置き場所が異なる
stages jobs(暗黙的な順序) GitHub Actionsはstagesという概念がない
job job 内の steps 粒度が異なる(後述)
script run コマンドの記述キー
image runs-on + container ランナーの指定方法が異なる
artifacts actions/upload-artifact アクションとして実装されている
needs needs ほぼ同じ概念
rules if 条件分岐の書き方が異なる
extends 再利用ワークフロー / with GitHub Actionsには直接の対応物がない
allow_failure: false continue-on-error: false(デフォルト) デフォルト動作が異なる
before_script run の複数行 / 別ステップ GitHub Actionsにbefore_scriptはない
CI_COMMIT_TAG などの変数 github.ref などのコンテキスト 変数体系が異なる

最大の違い:「ジョブとステップ」の概念

GitLab CIではひとつの job にひとまとまりの script を書きますが、GitHub Actionsでは job の中に複数の steps を持つ構造になっています。

GitLab CI:

lint-cppcheck:
  stage: analyze
  before_script:
    - apt-get update && apt-get install -y cppcheck
  script:
    - cppcheck --enable=all main.c
    - cat cppcheck_result.txt
  artifacts:
    paths:
      - cppcheck_result.txt

GitHub Actions(同等の処理):

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Install cppcheck          # before_scriptに相当
        run: sudo apt-get install -y cppcheck

      - name: Run cppcheck              # scriptに相当
        run: cppcheck --enable=all main.c

      - name: Upload artifact           # artifactsに相当
        uses: actions/upload-artifact@v4
        with:
          name: cppcheck-result
          path: cppcheck_result.txt

GitLab CIの job ひとつが、GitHub Actionsでは steps の集合体として表現されるイメージです。


ci.yml 各キーワードの解説

今回作成したci.ymlを例に、各キーワードの意味を解説します。

on:トリガー条件

GitLab CIでは rulesonly / except でトリガーを制御しますが、GitHub Actionsでは on キーでワークフロー全体のトリガーを定義します。

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

GitLab CIの以下に相当します。

rules:
  - if: '$CI_COMMIT_BRANCH == "main"'
  - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

runs-on:実行環境の指定

GitLab CIの image に近い概念ですが、Dockerイメージではなくランナーの種類を指定します。

runs-on: ubuntu-latest

GitLab CIのように特定のDockerイメージを使いたい場合は container キーを別途指定します。今回はGitHub提供のubuntuランナーをそのまま使っているため container は不要です。

uses:アクションの呼び出し

GitHub Actionsには「アクション」という再利用可能なステップが豊富に公開されています。GitLab CIに直接対応する概念はありませんが、extends でテンプレートを再利用する感覚に近いです。

- uses: actions/checkout@v4

actions/checkout@v4 はリポジトリのコードをチェックアウトする公式アクションです。GitLab CIではランナーが自動でcloneしてくれますが、GitHub Actionsでは明示的に呼ぶ必要があります。

- uses: actions/upload-artifact@v4
  with:
    name: coverage-report
    path: out/coverage/

actions/upload-artifact はGitLab CIの artifacts に相当します。with キーでアクションへのパラメータを渡します。

idsteps.<id>.outcome:ステップ結果の参照

id はステップに名前をつける仕組みです。後続のステップからその名前を使って実行結果を参照するために使います。

- name: Run unit tests
  id: test          # このステップに "test" という名前をつける
  run: make test

- name: Final status check
  if: always()
  run: |
    echo "${{ steps.test.outcome }}"  # "test" という名前で結果を参照

steps.<id>.outcome には実行結果として以下のいずれかが入ります。

意味
success ステップが正常に完了した
failure ステップが失敗した
skipped 条件により実行されなかった
cancelled キャンセルされた

GitLab CIとの違い

GitLab CIの needs はジョブ単位の依存関係を表しますが、GitHub Actionsの id同一ジョブ内のステップ間での結果参照に使います。スコープが異なる点に注意が必要です。

# GitLab CI:ジョブ単位での依存
report:
  needs:
    - test
    - lint-cppcheck

# GitHub Actions:同一ジョブ内のステップ単位での結果参照
- name: Final status check
  run: |
    if [[ "${{ steps.test.outcome }}" == "success" &&
          "${{ steps.cppcheck.outcome }}" == "success" ]]; then
      echo "🎉 All checks passed!"
    fi

今回のci.ymlでの使い方

Final status check ステップで「テスト・静的解析・警告チェックがすべて成功したか」をまとめて判定するために使っています。

- name: Run unit tests
  id: test
  run: make test

- name: Static code analysis with cppcheck
  id: cppcheck
  run: cppcheck ...

- name: Build check with strict warnings
  id: build_check
  run: gcc -Wall -Wextra -Werror ...

- name: Run coverage measurement
  id: coverage
  run: make coverage
  continue-on-error: true    # 失敗してもワークフローを止めない

- name: Final status check
  if: always()
  run: |
    if [[ "${{ steps.test.outcome }}" == "success" &&
          "${{ steps.cppcheck.outcome }}" == "success" &&
          "${{ steps.build_check.outcome }}" == "success" ]]; then
      echo "🎉 All CI checks passed successfully!"
    else
      echo "❌ Some CI checks failed!"
      exit 1
    fi

カバレッジは continue-on-error: true を指定しているため、仮に失敗しても outcomefailure になるだけでワークフロー全体は止まりません。Final status check の判定対象からも外しているため、カバレッジが取れなくてもCIとしては成功扱いになる設計です。

$GITHUB_OUTPUT:ステップ間での値の受け渡し

同一ジョブ内のステップ間で値を渡すには $GITHUB_OUTPUT を使います。GitLab CIの dotenv アーティファクトや変数の受け渡しに近い概念です。

- name: Run unit tests
  id: test
  run: |
    make test
    echo "test_status=passed" >> $GITHUB_OUTPUT   # 値を書き出す

- name: Check result
  run: |
    echo "${{ steps.test.outputs.test_status }}"  # 別ステップで参照

if: always():失敗時でも実行

GitLab CIの when: always に相当します。前のステップが失敗してもそのステップを必ず実行したい場合に使います。

- name: Clean up
  if: always()
  run: make clean

continue-on-error:失敗を許容する

GitLab CIの allow_failure: true に相当します。ステップが失敗してもワークフロー全体を失敗扱いにしないようにします。

- name: Run coverage measurement
  run: make coverage
  continue-on-error: true   # カバレッジが取れなくてもCIを止めない

hashFiles():ファイル存在チェック

特定のファイルやディレクトリが存在する場合にのみステップを実行したい場合に使います。

- uses: actions/upload-artifact@v4
  if: always() && hashFiles('out/coverage/**') != ''

hashFiles('out/coverage/**') はマッチするファイルが存在すればハッシュ値を、存在しなければ空文字を返します。GitLab CIには直接対応する構文はなく、script 内でシェルスクリプトで判定するケースが多いです。


stages がない?ジョブの実行順序

GitLab CIではステージを定義することでジョブの実行順序を制御しますが、GitHub Actionsには stages という概念がありません。

GitHub Actionsでは needs キーで依存関係を明示することで順序を制御します。

jobs:
  build:
    runs-on: ubuntu-latest
    steps: ...

  test:
    needs: build          # buildジョブが完了してから実行
    runs-on: ubuntu-latest
    steps: ...

  deploy:
    needs: [build, test]  # 両方完了してから実行
    runs-on: ubuntu-latest
    steps: ...

今回のci.ymlはすべてのステップを1つの build ジョブにまとめているため needs は使っていませんが、処理を複数ジョブに分割する場合はこの形になります。


extends に相当するものは?

GitLab CIでは .default_rules のようなテンプレートジョブを定義して extends で再利用できますが、GitHub Actionsには直接対応する機能がありません。

代替手段として以下があります。

再利用可能ワークフロー(Reusable Workflows): 別のワークフローファイルを呼び出す仕組みです。GitLab CIの extends よりも粒度が大きく、ワークフロー単位での再利用になります。

Composite Actions: 複数のステップをまとめてアクションとして定義できます。extends に近い使い方ができますが、別ファイルに切り出す必要があります。

今回のサンプルは単一ワークフローのシンプルな構成のため、これらは使用していません。


タグ条件の書き方

GitLab CIでは以下のようにタグ時のみ実行する条件を書けます。

rules:
  - if: '$CI_COMMIT_TAG'
    when: always
  - when: never

GitHub Actionsでの同等の書き方はこうなります。

on:
  push:
    tags:
      - 'v*'   # v始まりのタグ時のみ実行

または特定のジョブだけタグ時に実行したい場合は if で条件を指定します。

jobs:
  deploy:
    if: startsWith(github.ref, 'refs/tags/')
    runs-on: ubuntu-latest
    steps: ...

まとめ:GitLab CI → GitHub Actions 対応表(再掲)

やりたいこと GitLab CI GitHub Actions
実行環境の指定 image runs-on
コマンド実行 script run
事前処理 before_script step として定義
実行順序の制御 stages needs
成果物の保存 artifacts actions/upload-artifact
成果物の取得 自動 actions/download-artifact
失敗を許容 allow_failure: true continue-on-error: true
常に実行 when: always if: always()
条件分岐 rules / only if / on
テンプレート再利用 extends Reusable Workflows / Composite Actions
ジョブ間の依存 needs needs
CI定義済み変数 $CI_COMMIT_BRANCH など ${{ github.ref }} など
変数の定義 variables env
複数処理の結果をまとめて判定 ジョブを分けて needs でつなぐ id + steps.<id>.outcome

id はGitLab CIの何に相当するか

id に厳密に対応するGitLab CIの機能はありません。発想として一番近いのは、needs で複数ジョブの結果をまとめて後続ジョブで処理するパターンです。

GitLab CIでは処理をジョブに分けて needs でつなぐことで、複数の処理結果をまとめて扱います。

# GitLab CI:ジョブを分けてneedsでつなぎ、reportジョブでまとめる
test:
  stage: test
  script:
    - ./mybinary > runlog.log

lint-cppcheck:
  stage: analyze
  script:
    - cppcheck --enable=all main.c

report:
  stage: post_stage
  needs:
    - test
    - lint-cppcheck
  script:
    - cat runlog.log
    - cat cppcheck_result.txt

一方GitHub Actionsでは、同じことを同一ジョブ内のステップとして書き、id で各ステップに名前をつけて結果を参照します。

# GitHub Actions:同一ジョブ内でidを使って結果をまとめる
- name: Run unit tests
  id: test
  run: make test

- name: Run cppcheck
  id: cppcheck
  run: cppcheck --enable=all main.c

- name: Final status check   # reportジョブに相当
  if: always()
  run: |
    if [[ "${{ steps.test.outcome }}" == "success" &&
          "${{ steps.cppcheck.outcome }}" == "success" ]]; then
      echo "🎉 All checks passed!"
    else
      echo "❌ Some checks failed!"
      exit 1
    fi

つまり「GitLab CIではジョブを分けてneedsでつなぐ」ところを、「GitHub Actionsではステップをidで識別してoutcomeで参照する」という設計の違いがあります。どちらも「複数の処理結果をまとめて判定する」という目的は同じです。


GitHub ActionsはGitLab CIと考え方は似ていますが、「ジョブの中にステップがある」という構造と、artifactsがアクションとして実装されている点が大きな違いです。また id + outcome のようにステップ単位で結果を扱える点はGitLab CIにはない特徴です。GitLab CIの経験があれば、この対応関係を押さえるだけで比較的スムーズに読み解けると思います。

本シリーズはこれで完結です。#1〜#5を通して、C言語プロジェクトへのCI導入から
GitLab CIとの比較まで一通りカバーしました。

0
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?