📚

10分でわかる「Composite Action」で失敗しない!運用の落とし穴と効率化テクニック

に公開

はじめに

こんにちは、Thinkings 技術研究チームの石井です。Thinkings では、sonar ATS の CI/CD に GitHub Actions を採用しています。

GitHub Actions では、ワークフローが増えてくると重複するステップを 1 か所にまとめたいというニーズが必ず生まれます。このニーズを満たす手段の一つにComposite Actionがあります。Composite Action は、複数ステップを部品化し、リポジトリ横断で再利用できる便利な仕組みです。

しかし実際に使ってみると、いくつかの落とし穴があることがわかります。この記事では 「転ばぬ先の杖」 として、Composite Action を導入する前に知っておきたいハマりどころと、その場で試せるシンプルな回避策をいくつかまとめました。

ログがフラットに出力される

通常、GitHub Actions のワークフローではステップ単位でログが出力されますが、Composite Action を使用するとログの出力結果がひとつのステップに集約されます。

e.g. サンプルの Composite Action

name: Sleep Composite Action

runs:
  using: "composite"
  steps:
    - name: Step1
      shell: bash
      run: |
        echo "Step1 start"
        sleep 10
        echo "Step1 finish"

    - name: Step2
      shell: bash
      run: |
        echo "Step2 start"
        sleep 10
        echo "Step2 finish"

    - name: Step3
      shell: bash
      run: |
        echo "Step3 start"
        sleep 10
        echo "Step3 finish"


ワークフロー実行結果のログ

この程度のアクションであれば問題はないのですが、実際にはビルドやテスト実行結果が出力されます。そうなるとどこまでが一つのアクションの区切りなのか識別するのが難しくなります。


e.g. 出力されるログが多くなるケース

対策

この問題の対策として、::group::を使用します。ステップ単位でグループ化することで、ログが多くなっても識別しやすくなります。
cf. Workflow commands for GitHub Actions | Grouping log lines - GitHub Docs

e.g. 対策を実施したサンプルの Composite Action

name: Sleep Composite Action

runs:
  using: "composite"
  steps:
    - name: Step1
      shell: bash
      run: |
        echo "::group::Step1 action"
        echo "Run Step1 action"
        sleep 10
        echo "::endgroup::"

    - name: Step2
      shell: bash
      run: |
        echo "::group::Step2 action"
        echo "Run Step2 action"
        sleep 10
        echo "::endgroup::"

    - name: Step3
      shell: bash
      run: |
        echo "::group::Step3 action"
        echo "Run Step3 action"
        sleep 10
        echo "::endgroup::"


対策実施後のワークフロー実行結果のログ

グループ化する前と比べると識別しやすくなりました。デバッグや分析のハードルを下げるためにも、Composite Action 内では::group::を必須にしておくほうが良いでしょう。

Composite Action 内のステップ実行時間が計測できない

ワークフローの実行結果はステップ単位で出力されますが、Composite Action 内で呼び出したステップは1つに集約されます。そのため、ステップ単位でどのくらい実行時間が経過したのか計測できません。時間が計測できないので、ワークフローのボトルネックがどこにあり、それがどの程度変化しているのか正確な情報を分析できません。

通常、ステップの実行時間は GitHub REST API で取得できます。Composite Action を使用した場合、Composite Action で一つのステップとして認識されるため、Composite Action 内の1ステップの実行時間が取得できなくなります。

e.g. REST API でステップの実行時間を取得した場合
Run composite actionで Composite Action を呼び出している。

 "steps": [
    {
      "name": "Set up job",
      "status": "completed",
      "conclusion": "success",
      "number": 1,
      "started_at": "2025-05-16T08:46:42Z",
      "completed_at": "2025-05-16T08:46:42Z"
    },
    {
      "name": "Visualizing Workflows Timeline",
      "status": "completed",
      "conclusion": "success",
      "number": 2,
      "started_at": "2025-05-16T08:46:42Z",
      "completed_at": "2025-05-16T08:46:42Z"
    },
    {
      "name": "Run actions/checkout@v4",
      "status": "completed",
      "conclusion": "success",
      "number": 3,
      "started_at": "2025-05-16T08:46:42Z",
      "completed_at": "2025-05-16T08:46:43Z"
    },
    {
      "name": "Run composite action",
      "status": "completed",
      "conclusion": "success",
      "number": 4,
      "started_at": "2025-05-16T08:46:44Z",
      "completed_at": "2025-05-16T08:47:13Z"
    },
   ...
]

REST API でも取得できないため、他の分析ツールなどを使用しても結果は同じになります。以下は GitHub Actions でワークフローのタイムラインを生成してくれるKesin11/actions-timelineの出力結果です。ここでもRun composite actionの実行時間が集約されていることがわかります。

対策

1つの Composite Action では実行時間の長いステップを複数実行しないようにします。また、多くのステップを実行するのも非推奨です。

原則、一つの Composite Action で実行する目的は一つにしましょう。ビルドを実行するならビルドに関するステップだけ、テストならテストに関するステップだけと、小さい単位でひとまとめにしたほうが分析しやすくなります。便利だからといってビルドとテストを一つの Composite Action で実行してしまうと、後々対策に苦労します。

inputs に boolean 型が使用できない

GitHub の YAML 構文ではinputsにパラメータを指定できます。Composite Action も同じように inputs でパラメータを指定できます。しかし、inputs に boolean 型のパラメータを定義した場合、string 型で解釈されます。
cf. Metadata syntax for GitHub Actions - GitHub Docs

次のような Composite Action を作成します。この Composite Action のパラメータinput-boolean-valuetrueを設定して呼び出すと、boolean ではなく string の値('true' or 'false')に変換されます。実行時に警告なども出力されません。

e.g. Composite Action の inputs で boolean のパラメータを使用する

name: Inputs boolean test Composite Action

inputs:
  input-boolean-value:
    required: true
    type: boolean
    default: false

runs:
  using: "composite"
  steps:
    - name: Check value
      shell: bash
      run: |
        # Value is False
        echo "$VALUE"         
        # Value is True string
        echo "$VALUE_STRING"
      env:
        VALUE: ${{ inputs.input-boolean-value == true && 'Value is True' || 'Value is False' }}
        VALUE_STRING: ${{ inputs.input-boolean-value == 'true' && 'Value is True string' || 'Value is False string' }}

対策

boolean 型の inputs を比較する場合、${{ inputs.<VARIABLE> == 'true' && TRUE CASE || FALSE CAS }}のように定義しなければなりません。非常に紛らわしいので boolean 型を使わないのが良いです。string や number で代用しましょう。

なお、この記事を作成時点でもこの事象は解消されていません。気長に待つしかなさそうです。
cf. Boolean inputs are not actually booleans in composite actions · Issue #2238 · actions/runner

まとめ

  • 問題: ログは 1 ステップに集約される
    • 対策: ::group::, ::endgroup:: でログをグループ化して可読性を確保しましょう。
  • 問題: ステップ単位の実行時間が計測できない
    • 対策: 一つの Composite Action = 一つの目的に絞り、重い処理を詰め込みすぎない設計にしましょう。
  • 問題: inputs の boolean 型は string 型で解釈される
    • 対策: boolean を使わず、string か number に置き換えましょう。

上記を押さえておけば、Composite Action の恩恵(再利用性・保守性)を享受しつつ、トラブルに時間を奪われるリスクを最小化できます。他にも調べると Composite Action を運用するうえでの課題が見つかるので、実際に使用する前にいくつかピックアップしておき、対策を考えておくと良さそうです。

Thinkingsテックブログ

Discussion