GitHub

GitHub ActionsのComposite Actionとは何か?基本概要と特徴をわかりやすく解説

目次

GitHub ActionsのComposite Actionとは何か?基本概要と特徴をわかりやすく解説

Composite Actionは、GitHub Actionsにおけるカスタムアクションの一種で、複数のワークフローステップを一つにまとめて再利用可能なアクションとして扱えるようにする仕組みです。通常、ワークフロー中で繰り返し登場する一連の処理(例えばコードのチェックアウトやセットアップなど)を共通の機能としてカプセル化し、別のワークフローからも呼び出せるのがComposite Actionの特徴です。これにより、重複するステップの記述を減らし、ワークフローファイルの簡素化やメンテナンス性の向上を図ることができます。

Composite Actionが登場した背景と目的: GitHub Actionsでのニーズの高まりと果たす役割

GitHub Actionsでは、CI/CDパイプラインで同じようなセットアップや後処理のステップを複数のワークフローで繰り返し記述することがしばしばあります。そうした重複する処理を一箇所にまとめて再利用したいというニーズに応えるために登場したのがComposite Actionです。従来、カスタムアクションを作成するにはDockerコンテナやJavaScriptで実装する必要がありましたが、Composite Actionの導入によりYAMLだけでアクションを記述できるようになり、より手軽に共通処理をパッケージ化できるようになりました。

Composite Actionが提供する主な機能と特徴: ワークフローの共通処理をカプセル化して再利用

Composite Actionの主な特徴として、複数のステップ(コマンド実行や他の公式/カスタムアクションの呼び出し)を一つのアクション内で定義できる点が挙げられます。アクションのメタデータで入力(inputs)や出力(outputs)も定義可能で、呼び出し元のワークフローからパラメータを受け取り、処理結果を出力値として返すこともできます。要するに、Composite Actionはワークフローの一連の処理を関数のようにまとめたものであり、一度定義すれば他のワークフローからuses:で呼び出して再利用できるようになります。これにより、複数のプロジェクト間で共通するビルド/デプロイ手順などを簡単に共有できるようになります。

Composite Actionを活用すべき場面: 重複する処理の共有でメンテナンス性向上に貢献するケース

それでは、どういった場面でComposite Actionを活用すると有効でしょうか。例えば、社内の複数リポジトリで共通するビルド手順やテスト手順がある場合、それらをComposite Actionとして一度実装すれば各リポジトリのワークフローから呼び出すだけで済み、手順の標準化とメンテナンス性向上に貢献します。また、オープンソースコミュニティ向けに汎用的なアクション(例えば特定のリンターやデプロイ手順)を提供したい場合にもComposite Actionは適しています。コードを書かずYAMLで実装できるため開発ハードルが低く、Workflowテンプレートより柔軟に再利用可能な部品を提供できる点で、複雑なCI/CD環境を整理する手段として有用です。

Composite Actionの基本構成: action.ymlメタデータとステップ定義の仕組みを解説

Composite Actionを実装するには、アクションとして必要なメタデータファイルとステップ定義を正しく構成する必要があります。基本となるのはアクションメタデータファイル(通常 action.ymlで、ここにアクションの入力や出力、実行内容(ステップ)をYAML形式で記述します。Composite Actionは runs: using: "composite" と指定して一連のステップを列挙する仕組みになっており、記述方法はワークフローのステップに似ていますが、いくつか固有のルールと制約があります。以下では、Composite Actionの構成要素とステップ記述のポイントについて詳しく見ていきます。

Actionメタデータファイル(action.yml)の役割と構成要素: 定義内容と含まれる情報の詳細

Composite Actionの中心となるのがメタデータ定義ファイルであるaction.ymlです。このファイルにはアクション名や説明、入力 (inputs)・出力 (outputs) の項目、そして実行方法 (runs) が定義されます。例えばnameにはアクションの名称、descriptionには用途の説明を記述します。inputsセクションではパラメータ名ごとにdescription(説明)、required(必須か否か)、default(デフォルト値)等を定義し、ワークフローから渡せる変数を宣言します。outputsセクションではアクションが出力する値を定義し、後でワークフロー側で参照できるようにします。これらに加え、runsセクションで実際の処理内容を指定します。Composite Actionの場合、runs: 内で using: "composite" を指定し、続けて steps: 配下に実行したい一連のステップを列挙します。action.ymlはComposite Actionの入口となる重要なファイルであり、この内容に従ってGitHub Actionsはアクションの実行内容を解釈します。

Composite Action内で定義するステップの書き方と実行順序: YAML上での記述方法と流れを解説

Composite Action内のsteps:には、通常のワークフローステップと同様にusesもしくはrunを用いたステップを記述できます。ステップは上から下に順番に実行され、定義された順序に従って直列に処理されます。各ステップには任意でname(ステップ名)やid(識別子)を付与できます。usesキーを使えば別のGitHub Action(たとえば公式のactions/checkout@v3など)を呼び出せ、runキーを使えばシェルコマンドを実行可能です。さらに、envで環境変数を渡したり、withで別のアクションへの入力を指定したりすることもできます。ただしComposite Actionでは各ステップにif条件を指定することは現時点でサポートされていません。そのため、全ステップが定義順に必ず実行される点に留意が必要です(エラーが発生した場合を除く)。

他のGitHub Actionやコマンドをステップに組み込む方法: 既存アクションの活用とシェルコマンド実行

Composite Actionのステップでは、GitHubが提供する公式アクションやコミュニティが公開するアクションをuses:経由で自由に利用できます。例えば、コードリポジトリのチェックアウトにはuses: actions/checkout@v3と記述すれば、Composite Action内でもリポジトリのクローンを行えます。また、自前のシェルスクリプトを実行したい場合はrun:ステップでスクリプトファイルを呼び出すことも可能です(事前にリポジトリ内にスクリプトを用意し、実行権限を付与しておく必要があります)。Composite Actionはこのように、既存のアクション機能とカスタムコマンドを組み合わせて一つの処理フローを構築できる柔軟性を持っています。外部アクションを利用する際は、そのアクションのバージョン指定(@v1など)も忘れずに明記しましょう。

Composite Action実行時の環境: 呼び出し元ワークフローのRunnerやジョブとの関連性

Composite Actionは呼び出し元ワークフローのジョブ内で実行されます。つまり、Composite Action自体にruns-onを指定することはなく、アクションを呼び出したジョブのRunner(例: ubuntu-latest)上でそのステップ群が実行されます。このため、ワークフローの作業ディレクトリやチェックアウトしたコード、ジョブの環境変数などはComposite Actionの中からも継続して利用できます。一方で、Composite Action内では呼び出し元ワークフローのsecretsコンテキストに直接アクセスすることはできません(シークレットを使いたい場合はワークフロー側で入力に渡す必要があります)。ログの出力も呼び出し元のジョブに統合され、Composite Action全体がひとつのステップとして扱われます。このように、Composite Actionはあくまで現在のジョブ環境を拡張する形で動作する点を押さえておきましょう。

Composite Actionのメリット・デメリット: 長所と短所を比較し、利用上の注意点を詳しく解説

Composite Actionを活用することで得られるメリットは多い一方で、いくつか知っておくべき制約やデメリットも存在します。ここではComposite Actionの長所と短所について整理します。

Composite Actionを利用するメリット: ワークフロー共有化による効率化と標準化の向上

まず、Composite Actionを導入する最大のメリットは、ワークフローにおける重複処理を一箇所にまとめられることによる効率化と標準化です。同じ手順を複数のワークフローでそれぞれ記述していた場合、Composite Actionとして共通化すれば一度の実装で済み、修正も一箇所直すだけで全体に反映されます。これによりヒューマンエラーの削減や保守性の向上につながります。また、Composite ActionはYAMLで定義できるため、わざわざJavaScriptやDockerイメージを用意しなくても手軽にカスタムアクションを作成できます。習得コストが低く既存のワークフロー知識で開発できるため、社内のDevOpsエンジニアが自前のツールチェーンを共有する手段としても有用です。さらに、完成したComposite Actionはバージョンタグを付けてGitHub上で公開することで、他のプロジェクトやコミュニティでも再利用してもらうことが可能になります(内部利用だけでなく、一般公開のアクションとしても活用できます)。

Composite Actionのデメリット: 実行上の制約と他のアクション手法に比べた弱点

一方、Composite Actionには留意すべき制約もあります。最大の短所は実行の柔軟性や機能面での制約でしょう。Composite Actionは一つのジョブの中のステップ集約に過ぎないため、複数ジョブの並行実行や独自の実行環境(Runner指定)はできません。また前述の通り、各ステップにif条件を設定できない、エラー時に途中の後続ステップをスキップする制御が難しい、といったワークフロー記述上の制限も存在します。さらに、Composite Action自体はsecretsを直接参照できないため(必要なら入力経由で渡す必要があります)、シークレットを多用する処理には不向きです。そして、後述するようにComposite Actionには公式な「事後処理 (post)」機構がなく、ジョブ終了時の後片付けを確実に実行したい場合には工夫が必要になります。これらの点から、Composite Actionは万能ではなく、場合によっては従来のJavaScript製アクションやReusable Workflowを選択したほうがよいケースもあります。自分たちのニーズに照らして、最適な手法を選ぶことが重要です。

再利用可能なアクションの作り方: Composite Action作成の手順とベストプラクティスを解説

それでは、実際にComposite Actionを作成するにはどのような手順を踏めばよいのでしょうか。ここでは、再利用可能なアクションを作成・公開するまでの流れと、実装時のベストプラクティスについて説明します。

アクション作成のリポジトリ構成と準備: ディレクトリ作成から初期ファイルまで

まずはアクションのコードを置く場所を決めます。Composite Actionは独立したリポジトリとして公開することも、既存プロジェクトのリポジトリ内に配置することも可能です。社内や特定プロジェクト内で使い回す程度であれば、既存リポジトリの.github/actionsディレクトリ(存在しなければ作成)以下に新しいフォルダを作り、その中にアクションのファイル群を置く方法が簡単です。一方、汎用的なアクションとして広く公開する場合や複数のComposite Actionをまとめて管理したい場合には、アクション専用のリポジトリを新規に作成する方法が適しています。いずれの場合も、action.yml(またはaction.yaml)ファイルと必要に応じてシェルスクリプトなどの実行ファイルを用意します。スクリプトを含める場合、忘れずに実行権限 (chmod +x) を付与し、Gitにコミットしておきましょう。リポジトリの準備が整ったら、次にメタデータファイルの中身を作成していきます。

action.ymlファイルの記述ポイント: アクション名・説明・入力と出力の定義方法

アクションの基本情報となるaction.ymlには、前述の通りnamedescriptionを記載します。名前と説明は、アクションの役割が一目で分かるよう具体的かつ簡潔に書くことが重要です。また、inputsセクションでは必要なパラメータをすべて洗い出し、それぞれに分かりやすいID名(例: config-pathenable-feature など)を付けます。適切なdescriptionを添えて何の値かを明示し、必要ならrequired: trueとデフォルト値defaultも設定しましょう。不要な入力は極力増やさず、利用者がシンプルに使える設計を心がけます。同様に、outputsセクションではアクションが外部に提供する結果を定義します。例えば、「テスト件数」や「生成されたバージョン番号」など、ワークフロー側で利用したい値に名前を付けてoutputsに列挙します。出力も説明文を添えて、利用者がワークフロー中でsteps..outputs.<名前>経由で参照する際に迷わないように配慮します。これらメタデータの記述により、アクションのインタフェースが決まります。

Composite Action内のステップ開発: シェルスクリプト実行と既存アクションの活用

メタデータの骨組みが書けたら、runs.steps配下に実際の処理手順を記述します。前のセクションでも触れたように、Composite Actionのステップではシェルコマンドを直接run:で書くこともできますし、他のアクションをuses:で呼び出すこともできます。例えば、まず依存ツールをインストールするためにrun:でスクリプトを実行し、その後uses: actions/setup-node@v3でNode.js環境をセットアップし、次にrun:でビルドコマンドを実行する、といった具合にステップを順序立てて並べます。長いコマンドや複雑なロジックは別途シェルスクリプト(例: build.sh)に切り出し、それをrun: ./build.shで呼び出すと見通しが良くなります。各ステップには必要に応じてidを付け、次のステップでその出力を参照したり(例: ${{ steps.setup.outputs.version }}のように)できます。ステップの開発段階では、想定通りに動作するかローカルでの検証やテスト用ワークフローで試すことも大切です。特に他のアクションを利用するステップでは、そのアクションのドキュメントを確認し、入力や事前条件が適切に満たされているか注意しましょう。

アクションのバージョン管理とリリース: タグ付けとGitHub Marketplace公開の手順

Composite Actionが完成したら、リポジトリにコミットしてバージョンタグを付けましょう。例えばv1というタグをGitで作成し、GitHubにプッシュすることで、そのバージョンを固定したアクションとして利用できるようになります。タグを付けておけば、ワークフローからuses: /@v1のように指定でき、あとでアクションの内部実装が変わっても、既存のワークフローに影響を与えず安定して動作させられます。もしアクションを一般公開したい場合は、リポジトリの公開設定を確認し、actionsというトピックを追加してGitHub Marketplaceに掲載するとよいでしょう。Marketplaceに公開すれば他のユーザーが検索して見つけやすくなります。公開しない社内利用のケースでも、タグによるバージョン管理は重要です。新しい機能追加や不具合修正の際には適宜タグを更新し、利用側で必要に応じてバージョンを上げる運用にすると、互換性のコントロールがしやすくなります。

Composite Actionにおけるinputとoutputの使い方: パラメータ受け渡しと結果の取り出し方

Composite Actionで外部からパラメータを受け取り(input)、結果を呼び出し元に返す(output)方法について詳しく見てみましょう。適切にinputsとoutputsを定義・活用することで、アクションをより汎用的かつ便利にできます。

Composite Actionのinputsセクション: パラメータの定義とデフォルト値の設定

Composite Actionのinputsセクションには、アクションが受け取る引数をすべて定義します。各入力には一意のID(キー名)を付け、必須であればrequired: true、任意ならrequired: false(または省略)とし、必要に応じてdefaultでデフォルト値も設定します。定義された入力パラメータは、Composite Action内で${{ inputs.入力名 }}という構文で参照できます。例えばinputs:pathという入力を定義した場合、後続のステップ内で${{ inputs.path }}と書けば、その値が挿入されます。ただし、シェルコマンド内で入力値を使う場合は注意が必要です。Composite ActionではデフォルトでINPUT_XXX形式の環境変数が自動セットされないため、必要に応じてステップにenv:を指定してINPUT_FOO: ${{ inputs.foo }}のように受け渡すことがあります。こうすることで、runスクリプト中で$INPUT_FOOを参照できるようになります。適切にinputsを定義することで、Composite Actionに柔軟な設定を与え、再利用範囲を広げることができます。

Composite Actionのoutputsセクション: ステップ実行結果を出力値として呼び出し元に引き渡す方法

Composite Actionが処理結果を呼び出し元に返すには、outputsセクションで出力値を定義します。outputs:の各エントリに対し、value: ${{ steps.<ステップID>.outputs.<出力名> }}という形で値を紐付けます。これは、Composite Action内の特定のステップの出力をアクション全体の出力として露出する設定です。例えば、あるステップにid: calcと付け、そのステップ内で結果という値を生成したなら、outputs:total: value: ${{ steps.calc.outputs.result }}のように記述できます。ただし、自前のrunステップから出力を設定する場合は、ステップ内で環境変数GITHUB_OUTPUTに書き込む必要があります。例えば以下のようにします:

 - id: calc
run: echo "count=$(ls | wc -l)" >> $GITHUB_OUTPUT

上記ではcalcステップの出力countを設定しています。対応するoutputsセクションではcount: ${{ steps.calc.outputs.count }}とマッピングすることで、呼び出し元ワークフローは${{ steps.<アクションstepID>.outputs.count }}でその値を取得できるようになります。このようにoutputsを正しく定義することで、Composite Actionは単に処理するだけでなく、その結果を後続のジョブやステップに受け渡して活用できるようになります。

ワークフローからComposite Actionへ入力を渡す方法: withキーワードによる値の指定

定義したComposite Actionを実際にワークフローで使う際は、uses:で参照するとともに、必要に応じてwith:句で入力パラメータを渡します。例えば、Composite Action側でinputs:env-nameという入力(デフォルト値あり)を定義している場合、ワークフローから呼び出す際に:

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: my-org/my-composite-action@v1
with:
env-name: "production"

のようにwith:以下に入力名: 値を指定します。これにより、Composite Action内では${{ inputs.env-name }}productionという値が参照できるようになります。複数の入力がある場合はwith:内にそれぞれのキーと値を列挙します。また、シークレット情報を渡したい場合は、ワークフローでwith:secret-key: ${{ secrets.MY_SECRET }}のように記述し、Composite Action側ではそれを通常の入力として受け取る設計にします。withキーワードを使って明示的に値を渡すことで、Composite Actionは様々なコンテキストで再利用可能な汎用性を持つことができます。

Composite Actionからワークフローへ出力を受け取る方法: outputs値の参照と利用

Composite Actionが出力する値は、ワークフロー側でsteps.<ステップID>.outputs.<名前>という形式で参照できます。Composite Actionを呼び出すステップにidを付与しておけば、後続のステップでそのidを用いて出力を取得可能です。例として、Composite Action側でoutputs:resultを定義していた場合、ワークフロー中では:

 - name: Use composite action
id: myaction
uses: my-org/my-composite-action@v1
...(省略)...
- run: echo "結果は ${{ steps.myaction.outputs.result }} です"

のように、steps.myaction.outputs.resultで値を参照できます。上記のechoコマンドはComposite Actionの出力resultを受け取り表示する例です。後続のジョブに引き継ぎたい場合には、ワークフローのjobs..outputsとしてジョブ間で受け渡すことも可能です。例えばジョブAoutputs.resultを設定し、後続ジョブBneeds: Aとしたうえで${{ needs.A.outputs.result }}と参照するような使い方です。このように、Composite Actionの出力はワークフロー全体の中で他のステップやジョブにデータを渡す手段として活用できます。

Composite Actionのファイル構成と配置場所: action.ymlとスクリプトのディレクトリ構成ガイド

Composite Actionのファイル配置は、作成場所によって若干異なります。同じリポジトリ内で定義する場合と、別リポジトリとして公開する場合、それぞれの推奨構成を見てみましょう。

単一リポジトリ内でComposite Actionを定義するフォルダ構成: .github/actionsディレクトリの活用

既存プロジェクトのリポジトリ内でComposite Actionを定義する場合は、ディレクトリ構成にひと工夫必要です。GitHubの推奨では、.github/actions フォルダを作成し、その配下にアクションごとのサブフォルダを置く構成が便利です。例えば、.github/actions/my-composite/ のようなフォルダを作り、その中にaction.ymlと必要なスクリプトファイルを配置します。action.ymlはサブフォルダ直下か、さらに深い階層でも構いませんが、ワークフローから参照するときにはそのパスを正しく指定する必要があります。複数のComposite Actionを同じリポジトリで管理する場合、.github/actions/以下にそれぞれ別のサブフォルダを作って整理するとわかりやすくなります。なお、.github/workflowsフォルダ内はワークフローファイル専用ですので、アクションのaction.ymlを誤ってworkflows内に置かないよう注意してください。

独立したアクション専用リポジトリを作成する場合の構成: リポジトリルートにaction.ymlを配置

Composite Actionを専用のリポジトリで公開・管理する場合、そのリポジトリ自体がアクションパッケージになります。一般的にはリポジトリのルートディレクトリにaction.ymlを置き、必要ならスクリプトファイルやREADMEなどを同じリポジトリに含めます。例えば、my-org/composite-build-action というリポジトリを作成し、その直下にaction.ymlとスクリプト類を配置する構成です。先述のHello World例では、hello-world-composite-action リポジトリ直下にaction.ymlgoodbye.shを置いています。複数のアクションを1つのリポジトリで提供することも可能ですが、その場合は各アクションごとにサブフォルダを作成し、それぞれにaction.ymlを配置する必要があります(リポジトリ内のどのaction.ymlを使うかを指定して呼び出す形になります)。単一リポジトリに一つのComposite Actionを置く場合は、特別な指定なしでuses: /@で呼び出せるため、利用者にとってもシンプルです。

action.ymlと付随スクリプトの配置場所: 相対パスの指定と管理方法

Composite Actionでスクリプトファイルを動かす場合、そのファイルのパス指定にも注意しましょう。Composite Actionが別リポジトリとして呼ばれる場合、アクション自身のファイルはgithub.action_pathというコンテキスト変数でパス参照できます。例えば、アクションと同じフォルダ内にscript.shを置いた場合、ステップでrun: ${{ github.action_path }}/script.shと指定すれば実行可能です。GitHub公式の推奨としては、$GITHUB_ACTION_PATH(環境変数)を$GITHUB_PATHに追記し、その後単にファイル名で呼び出す方法もあります。一方、同一リポジトリ内のComposite Actionでは、そのリポジトリがそのまま作業ディレクトリとしてクローンされているため、run: ./path/to/script.shのように相対パスで呼ぶことも可能です。いずれのケースでも、action.ymlやスクリプトの配置場所に合わせて正しいパスを指定することが重要です。ファイル構成を変更した際には、パスの修正漏れがないか確認しましょう。

ワークフローからのパス参照方法: uses: “./パス” による同一リポジトリ内アクション実行

同一リポジトリ内にあるComposite Actionをワークフローから利用するには、usesに相対パスを指定します。形式はuses: ./(アクションのパス)です。例えば、.github/actions/my-composite-action/フォルダにアクションがある場合、ワークフローのステップではuses: ./.github/actions/my-composite-actionと記述します。この場合、特定のタグやブランチではなく現在のリポジトリソースを参照するため、実行されるComposite Actionの内容は、そのワークフローが属するコミットの内容に固定されます。ローカルパス参照は開発中のアクションを素早く試す際に便利ですが、リポジトリ間で共有することはできません。他のリポジトリからも使い回す場合は、前述のようにアクション専用リポジトリを用意しuses: /@v1で呼び出す形にする必要があります。

Composite Actionでpost処理を実現する方法: 後処理を組み込むテクニック

GitHub Actionsでは、JavaScriptやDocker製のアクションには事前・事後処理(pre/post)を定義する仕組みがありますが、Composite Actionには公式には用意されていません。それでも、複数のステップを含むComposite Actionにおいて、前準備や後片付けが必要となるケースがあります。ここではComposite Actionで擬似的に前処理・後処理を実現する方法について解説します。

Composite Actionで後処理が必要となるケース: 後始末やリソース解放の要求

まず、どんな場合にComposite Action内で後処理が必要になるかを考えてみます。例えば、Composite Actionが一時ファイルを作成したり、一時的な環境設定を行うような場合、最後にそれらをクリーンアップする処理が求められます。また、外部サービスにログインするステップがある場合、その後ログアウト処理を入れておきたいこともあるでしょう。他にも、ジョブ全体としては常に実行したい終了処理(例えばデプロイ後の通知送信や、失敗時でも行うべきロールバック処理など)が考えられます。こうした後始末やリソース解放を行う必要があるケースでは、本来であればアクションのpostフックとして実装したいところですが、Composite Actionでは標準で提供されていないため工夫が必要になります。

Composite Actionで疑似的に前処理・後処理を行う手法: 最初と最後のステップにスクリプト配置

Composite Actionで前後処理を疑似的に実現する基本的な方法は、「最初のステップに前処理用のコマンドを、最後のステップに後処理用のコマンドを配置する」ことです。例えば、最初のステップで環境変数の設定や一時ディレクトリの作成を行い、最後のステップでその一時ディレクトリを削除するようにします。こうしておけば、Composite Actionを実行した際に、実質的に事前準備と事後整理が組み込まれることになります。具体例として:

steps:
- name: Pre-step (setup)
run: echo "Creating temp dir" && mkdir -p /tmp/mytemp
... (中略:メイン処理のステップ) ...
- name: Post-step (cleanup)
run: echo "Cleaning up" && rm -rf /tmp/mytemp

上記のように最初と最後にそれぞれセットアップとクリーンアップのコマンドを置けば、Composite Action全体として前後処理を含んだ動きを実現できます。ただし、この方法では途中のステップでエラーが発生してジョブ自体が中断した場合、最後のクリーンアップステップが実行されない可能性がある点に注意が必要です。

最後のステップでcleanupスクリプトを実行する実装例: 一時ファイル削除などの後処理

先述の例では、Pre-stepで作成した/tmp/mytempディレクトリを、最後のPost-stepで削除しています。このように、Composite Action内にクリーンアップコマンドを組み込んでおけば、少なくとも正常終了時には後始末が自動で行われます。例えばキャッシュファイルを消す、外部サービスからログアウトする、など任意の後処理を最後のステップに記述しておくことで、Composite Action終了時のリソースリークや副作用を減らすことができます。

失敗時にも後処理を実行する工夫: continue-on-errorの利用と制約

Composite Action内で途中のステップが失敗した場合でも後処理を実行させたい場合、現状では完全な解決策はありませんが、いくつか工夫が考えられます。一つは、主要なステップにcontinue-on-error: trueを指定し、エラーが発生してもComposite Action自体は継続させる方法です。これにより、最後のクリーンアップステップまで実行されます。しかし、この方法ではエラーが無視されてしまうため、ワークフロー上は成功扱いになってしまう点に注意が必要です。エラーを検知しつつ後処理も行いたい場合は、失敗フラグを変数に記録し、最後のステップでそのフラグを確認して適切な終了コードを返す、といった複雑な実装が必要になります。現実的には、Composite Actionで確実な後処理が必要なケースでは、JavaScriptアクションに切り替えてpostを実装するか、ワークフロー側でステップを分けてif: failure()付きのクリーンアップジョブを用意する、といった対応が取られることが多いです。Composite Action単体では後処理の完全な保証が難しいことを認識しておきましょう。

前後処理を含めたComposite Action開発上の注意点: if条件不使用による影響

以上のように、Composite Actionで前処理・後処理を実現するには一定の制約を伴います。特にif条件が使えないことの影響で、エラー時の挙動制御が難しい点は頭に入れておく必要があります。Composite Actionを設計する際には、「後処理が必須の重要なリソース操作は行わない」か「不測のエラーでも大きな問題とならない範囲で行う」ことが無難です。どうしても厳密な後処理が必要な場合には、前述のように別の方法を検討することも視野に入れ、Composite Actionの適用範囲を見極めて使いましょう。

Composite Actionと他のAction(Reusable Workflowなど)との違い: 適切な用途の選択指針

Composite Actionと並んで重複作業を減らす仕組みとして、GitHub Actionsには「再利用可能なワークフロー (Reusable Workflow)」があります。さらには従来型のDockerコンテナアクションやJavaScriptアクションとの使い分けも気になるところです。ここでは、特にReusable Workflowとの比較を中心に、Composite Actionとの違いを押さえましょう。

再利用可能なワークフロー(Reusable Workflow)とは何か: Composite Actionとの位置づけの違い

Reusable Workflow(再利用可能ワークフロー)とは、その名の通り「他のワークフローから呼び出せるワークフロー」のことです。通常のワークフローファイル(.github/workflows/ 配下のYAML)に対し、on:を省略し特定の呼び出し用名前を付けることで、別のワークフロー内からuses: /.github/workflows/.yml@という形式でそのワークフロー全体を呼び出すことができます。Reusable WorkflowはComposite Actionと同様に重複する処理をまとめる目的で登場しましたが、「ワークフロー全体」を再利用する点で、単一ジョブ内のステップをまとめるComposite Actionとは位置づけが異なります。簡単に言えば、Composite Actionが「カスタムのステップ集約(関数)」だとすれば、Reusable Workflowは「カスタムのジョブ集約(サブルーチンのようなもの)」と言えます。それぞれ用途やスコープが異なるため、次項以降で詳しく違いを見ていきます。

ジョブとステップ構成の違い: Reusable Workflowは複数ジョブ、Composite Actionは単一ステップ

最大の違いの一つは、含められる構造のレベルです。Composite Actionが内部にジョブを持てず、単一のジョブステップの集合体であるのに対し、Reusable Workflowは内部に複数のジョブを含めることができます。つまり、Reusable Workflowを呼び出すと、そのワークフロー内に定義された複数のジョブが一括で実行されます。例えばビルド→テスト→デプロイの3ジョブから成るCI/CDパイプラインをReusable Workflowとして作っておけば、各リポジトリからそれを一回呼び出すだけで3つのジョブが順次実行されます。一方、Composite Actionは一つのジョブ内の単一ステップとして実行され、その中で複数の処理を行いますが、並列ジョブなどの概念は含みません。「ジョブ」単位で再利用したい場合はReusable Workflow、「ステップ」単位で部品化したい場合はComposite Action、と覚えておくとよいでしょう。

実行環境(Runner)指定の違い: Composite Actionは呼び出し元Runnerに依存

実行環境についても大きな違いがあります。Composite Actionは前述の通り、呼び出し元ワークフローのジョブと同じRunner上で動作します。そのため、Composite Action自体ではruns-onを指定できず、呼び出し側のジョブが例えばubuntu-latestであれば、そのLinuxマシン上で全ステップが実行されます。一方、Reusable Workflowはそれ自体が一つのワークフローであり、中の各ジョブでruns-onを自由に指定できます。例えば、Reusable Workflow内でLinuxとWindowsの2ジョブを定義しておけば、呼び出し元から一度実行するだけで両方のOS上で処理を行わせることが可能です。つまり、異なるランナーや異なる実行環境が必要な一連の処理はReusable Workflowでなければ実現できません。なお、Reusable Workflowは一つのジョブ内のステップから直接呼び出されますが、そのジョブ内ではReusable Workflowを呼んだ後に追加のステップを続けて記述することはできない点にも注意が必要です。

シークレットやコンテキストの扱いの違い: Reusable Workflowでは利用可能、Composite Actionでは制限あり

セキュリティコンテキストの扱いにも差異があります。GitHubドキュメントによれば、Reusable Workflowではシークレットをそのまま利用できますが、Composite Actionではシークレットを直接参照できないとされています。Reusable Workflowを呼び出す際にはsecretsを明示的に渡したりinheritオプションで呼び出し元と同じシークレットを使えたりします。一方、Composite Actionで機密情報を使いたい場合、事前にワークフローから入力経由で値を渡す必要があります(実質的にシークレットを平文の入力に渡す形になるため、必要最小限に留めるべきです)。また、Reusable Workflowではgithubneedsなど標準のコンテキストも通常のワークフロー同様に利用できますが、Composite Actionでは実行時のコンテキストが呼び出し元ジョブに限定されます。例えばComposite Action内で別ジョブのneedsコンテキストにアクセスすることはできません。このように、コンテキストやシークレットの面ではReusable Workflowのほうが柔軟と言えます。

ログ出力とデバッグの違い: Composite Actionの内部ステップはまとめてログ表示

ログ出力やデバッグのしやすさにも違いがあります。Composite Actionを実行した場合、GitHub Actionsのログ上では呼び出し元ジョブの単一のステップとして表示され、その中の細かいステップログは折り畳まれた形になります。必要に応じて展開すれば各ステップのログも確認できますが、パッと見では一つの大きなステップとしてしか表示されません。一方、Reusable Workflowでは、呼び出されたワークフロー内の各ジョブ・各ステップが独立してログ表示されます。通常のワークフローと同様にリアルタイムでログが流れ、どのジョブのどのステップで失敗したかも明確に把握できます。Composite Actionは内部ステップが隠蔽されるぶんログがシンプルになりますが、逆にデバッグ時には原因箇所を探す手間が増える可能性があります。トラブルシューティングの観点では、複雑な処理ほどReusable Workflowの方が追いやすいと言えるでしょう。

ネスト呼び出しの違い: Composite Actionは10段階まで、Reusable Workflowは4段階まで

最後に、入れ子(ネスト)構造での呼び出し制限にも差があります。Composite Actionは別のComposite Actionを内部でusesしてさらにその中でComposite Actionを…という風に、最大で10階層まで入れ子にすることが可能です。これに対し、Reusable Workflowの再帰的な呼び出し(ワークフローが別のReusable Workflowを呼ぶ)は4段階までという制限があります。極端な入れ子構造を使うケースは稀かもしれませんが、大規模なワークフロー設計を行う際には覚えておくと良いでしょう。

Composite Actionの実装例(サンプルコードと具体的な設定例): Hello Worldアクションで学ぶ利用方法

最後に、Composite Actionの具体的な実装例を見てみましょう。ここではシンプルな「Hello World」アクションを題材に、Composite Actionのaction.ymlと、それを呼び出すワークフローの例を示します。さらに、もう少し複雑なシナリオでComposite Actionを応用する場合のイメージも紹介します。

Hello WorldなComposite Actionの例: 入力を挨拶メッセージにして出力するアクション

Composite Actionの例: 以下は、入力で受け取った名前に対して挨拶を行い、そのメッセージを出力として返すシンプルなComposite Actionのaction.ymlです。

name: Hello World
description: Greet someone and say goodbye
inputs:
who-to-greet:
description: Name of the person to greet
required: false
default: 'World'
outputs:
message:
description: Greeting message
value: ${{ steps.greet.outputs.msg }}
runs:
using: composite
steps:
- id: greet
run: echo "msg=Hello ${{ inputs.who-to-greet }}!" >> $GITHUB_OUTPUT
- name: Farewell
run: echo "Goodbye!"

このComposite Actionでは、who-to-greetという入力を受け取り、最初のステップgreetHello [名前]!という挨拶文を生成してmessage出力に設定しています。続くステップでは単に”Goodbye!”と表示するだけです。

上記Composite Actionを呼び出すワークフローの例: uses句での実行と出力値の利用

ワークフローでの呼び出し例: 次に、上記のComposite Actionを実際にワークフローから使う際の設定例です。

on: [push]
jobs:
greeting_job:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run Hello World Action
id: hello
uses: my-org/hello-world-composite-action@v1
with:
who-to-greet: "Alice"
- name: Show greeting
run: echo "Action said: ${{ steps.hello.outputs.message }}"

上記のワークフローでは、uses: my-org/hello-world-composite-action@v1によりComposite Actionを実行し、with:で入力にAliceという名前を渡しています。実行結果として、出力messageHello Alice!が設定されるため、最後のステップでそれを参照し表示しています。

応用編: 複数ステップを持つComposite Actionのサンプルシナリオ

応用例: Composite Actionは上記のような単純なケースだけでなく、より複雑な処理のカプセル化にも役立ちます。例えば、ビルドとテストをまとめたComposite Actionを考えてみましょう。最初に依存関係をセットアップし、次にアプリケーションをビルドし、その後単体テストを実行して結果をレポートするといった複数のステップを、一つのComposite Actionとしてパッケージ化できます。具体的には、Node.jsプロジェクト向けにactions/setup-node@v3でNode.jsをセットアップ→npm installで依存解決→npm run buildでビルド→npm testでテスト実行、といった一連の流れをComposite Action内にステップとして記述し、必要な入力(例えばテストカバレッジの閾値など)をパラメータ化しておくイメージです。こうしておけば各リポジトリのワークフローではそのComposite Actionを呼び出すだけでビルド&テストが走り、処理の統一と大幅な簡略化が図れます。

このように、Composite Actionの応用範囲は広く、繰り返し発生する複雑な手順を一度だけ実装して共有することで、ソフトウェア開発の効率と信頼性を高めることができます。

Composite Actionの注意点・ハマりやすいポイント: 事前に知っておくべき落とし穴と対策も解説

最後に、Composite Actionを扱う上で陥りがちなミスや注意すべきポイントをまとめます。これらを事前に把握しておくことで、開発や運用時のトラブルを未然に防ぐことができます。

Composite Actionでサポートされない機能: steps.if条件・シークレット使用制限などの制約

まず、Composite Actionにはサポートされていない機能がいくつかある点に注意しましょう。その代表がステップ単位のif条件です。ワークフローではif: を使って特定条件下でステップをスキップできますが、Composite Action内ではこれが使えません。同様に、secretsコンテキストも直接は利用できず、必要な場合はワークフローから明示的に入力経由で渡さねばなりません。また、Composite Actionは1ジョブ内の処理に限られるため、ジョブのmatrix(マトリックス戦略)や並列実行といったジョブレベルの機能も含められません。さらに、前述のようにComposite Actionにはpostpreの仕組みが無いため、アクション終了時に必ず実行したい処理がある場合には設計上の工夫や別手段の検討が必要です。これらの制約を念頭に置き、Composite Actionでは「あくまで直列のステップ実行のみができる」と理解しておきましょう。

action.yml記述時の注意: YAMLフォーマットや実行権限設定の落とし穴

Composite Actionの開発でありがちなミスとして、メタデータYAMLの記述ミスが挙げられます。action.ymlは厳密なYAMLフォーマットで書く必要があるため、インデントのずれやコロンの付け忘れなどで簡単にエラーになってしまいます。特にruns:セクション以下の記述が正しくインデントされていないと、Composite Actionとして認識されません。また、using: "composite"の指定を忘れるとComposite Actionとして動作しないので注意してください。さらに、スクリプトファイルを含む場合は実行権限の付与忘れもありがちな落とし穴です(権限がないとPermission deniedエラーになります)。Windows系Runnerでシェルスクリプトを動かそうとして失敗するケースもあるため、クロスプラットフォームを意識する場合はPowerShellスクリプトを用意するなどの配慮も必要です。最後に、action.ymlの変更をしたら忘れずにGitにコミット・プッシュすることも重要です(リポジトリの最新コミットに反映されていないと、期待通り更新されません)。

デバッグの難しさ: ログ出力の制約に対するトラブルシューティング方法

Composite Actionをデバッグする際には、ログ出力の見づらさに注意が必要です。Composite Action内でエラーが起きると、呼び出し元のワークフローでは「Composite Actionのステップが失敗しました」としか表示されず、詳細な原因を把握しづらい場合があります。対策として、Composite Action内に適宜echoによるログ出力を仕込んでおき、どのステップまで処理が進んだかや重要な変数の値を記録する方法が有効です。また、Composite Actionを開発中は小さなテスト用ワークフローを作り、個別に呼び出して挙動を確認するといった手順を踏むとデバッグが容易になります。必要であれば、一時的にComposite Actionを通常のワークフローステップに展開し、問題の切り分けを行うのも手です。ログが一括表示されるComposite Action特有の状況に慣れておき、エラー発生時にはGitHub ActionsのUIで該当ステップを展開して詳細ログを見るなど、適切にトラブルシュートしましょう。

アクションのバージョン指定と更新管理: バージョンピン留めとアップデート時の注意

Composite Actionをチームや社内で共有する場合、バージョン管理と更新時の配慮も重要です。ワークフローからComposite Actionを呼び出す際には、可能な限り特定のバージョンタグ(例: @v1)やコミットSHAを指定し、予期せぬ変更でワークフローが壊れないようにするのがベストプラクティスです。アクションの実装を更新して新機能追加や不具合修正を行った場合は、新たなタグ(例: v1.1や互換性が大きく変わる場合v2)を発行し、利用者にはタグを更新してもらう手順をとります。@mainのような可変の参照を使っていると、アクション側の変更が即座に全ワークフローに影響し、思わぬ不具合を招く可能性があります。したがって、Composite Actionを公開・共有する際はリリースノートを整備し、利用者が安心して特定バージョンをピン留めできるようにすることが望ましいです。

Reusable Workflowとの混同に注意: 適材適所で使い分けるための指針

最後に、Composite Actionと似た目的を持つReusable Workflowとの使い分けにも注意しましょう。両者を混同すると、思ったような結果が得られなかったり設計が冗長になったりします。ジョブ全体を再利用したい場合や、複数のRunner上で処理を行いたい場合はReusable Workflowが適しています。一方、単一ジョブ内の共通処理をカプセル化したい場合や、他者にも簡単に使ってもらえる小さな部品を作りたい場合にはComposite Actionが便利です。例えば、「ビルド→テスト→デプロイ」を丸ごと共有したいならReusable Workflow、「テスト結果をフォーマットしてSlack通知」する部分だけ共通化したいならComposite Action、といった具合に適材適所で使い分けるのがおすすめです。プロジェクトのニーズに合わせて最適な仕組みを選択し、混乱を避けましょう。

資料請求

RELATED POSTS 関連記事