GitHub Actionsのワークフロー共用化とは?別リポジトリのworkflowを呼び出す仕組みを基礎から解説

GitHub Actionsを複数リポジトリで運用していると、必ずぶつかるのが「同じようなworkflowファイルがあちこちに散らばり、メンテナンスが追いつかない」という問題です。

本記事では、workflowの基本的な動作原理から、別リポジトリのworkflowを呼び出す仕組み、そしてタグを使った安全なバージョン管理までを、初学者向けに順を追って解説します。

目次

そもそもGitHub Actionsのworkflowとは何か

GitHub Actionsのworkflowとは、リポジトリ内で発生したイベント(pushやプルリクエストなど)をきっかけに、自動的に処理を実行するための仕組みです。実体はYAML形式のテキストファイルで、リポジトリの.github/workflows/というディレクトリに配置します。

重要なのは、このパスに置くだけでGitHubが自動的に検知してくれるという点です。特別な登録作業は不要で、ファイルをpushした瞬間からworkflowは有効になります。

リポジトリ .github/ workflows/ build.yml deploy.yml push GitHubが自動検知 ymlを読み込み トリガー条件を登録 イベント待機 実行 仮想マシン Ubuntu等で ジョブを実行

リポジトリ .github/ workflows/ build.yml deploy.yml push GitHubが自動検知 ymlを読み込み トリガー条件を登録 イベント待機 実行 仮想マシン Ubuntu等で ジョブを実行

トリガーの仕組み:いつworkflowは動くのか

workflowが動くタイミングは、YAMLファイルの中のon:というキーで指定します。以下は典型的な例です。

name: Build Service
on:
  push:
    branches:
      - main
      - develop
  pull_request:
    branches:
      - main
  schedule:
    - cron: '0 9 * * 1'
  workflow_dispatch:
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm install
      - run: npm test

この設定をリポジトリに置いてpushすると、以降は次のような動きが自動で行われます。

  • mainまたはdevelopブランチにpushされた瞬間にビルドジョブが実行される
  • main宛のプルリクエストが作成・更新されるとビルドジョブが実行される
  • 毎週月曜9時に定期実行される
  • GitHubのActionsタブに手動実行ボタンが出現する

主要なトリガーイベントは他にも、Issueの作成、リリースの発行、他のworkflowからの呼び出し、レビューの提出など多数用意されています。ユースケースに応じて使い分けます。

workflowはどこで実行されるのか

runs-on: ubuntu-latestと記述すると、GitHubが用意している使い捨ての仮想マシンが起動し、その中に空の環境が作られます。

最初のactions/checkout@v4というstepで自分のリポジトリをその仮想マシンにcloneし、以降のstepで各種コマンドを実行します。ジョブが終わると仮想マシンはそのまま破棄されるため、毎回クリーンな状態から処理が始まります。

別リポジトリのworkflowは呼び出せるのか

結論から言うと、呼び出せます。ただし、呼び出す仕組みは大きく分けて2種類あり、それぞれ性格が異なります。この違いを理解することが、ワークフロー共用化を語る上での鍵です。

Reusable Workflow(再利用可能workflow)

呼ばれる側のworkflowがon: workflow_call:を宣言している場合、他のリポジトリから丸ごと呼び出せます。workflow単位で共通化したいときに使います。

呼ばれる側の例:

on:
  workflow_call:
    inputs:
      service_name:
        required: true
        type: string
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Building ${{ inputs.service_name }}"

呼び出し側の例:

on:
  push:
    branches: [main]
jobs:
  call-shared:
    uses: org-name/shared-actions/.github/workflows/build.yml@v1.0.0
    with:
      service_name: my-service

Composite Action(複合アクション)

こちらはworkflowではなく、「複数のstepをひとつの部品にまとめたもの」です。action.ymlという名前で定義し、呼び出し側のstepの中でuses:を使って参照します。よく使う処理の手順を部品化したいときに便利です。

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: org-name/shared-actions/.github/composite_action/docker_build@v1.0.0
        with:
          image_name: my-app

Reusable Workflowはジョブごと共通化するのに対し、Composite Actionは各サービスの固有workflowを残したままstep単位で部品を差し込めるという柔軟性があります。どちらを選ぶかは、共通化したい粒度によって決まります。

@記号の後ろが持つ重要な意味

別リポジトリを参照するときのuses:の末尾に付く@は、「借りてくる部品のどの時点の状態を使うか」を指定する部分です。指定できる方式は3種類あります。

ブランチ指定 @main ブランチの 最新状態を参照 影響:大 相手の更新が 即座に反映される (予期せぬ変更の恐れ) タグ指定 @v1.0.0 タグが指す 特定コミットに固定 影響:中 タグ貼替えがなければ 安定 (最もバランス良) コミットハッシュ @a3f2b1c… 完全に特定の コミットに固定 影響:ゼロ 書換え不可能 最も安全だが 更新も手動

ブランチ指定 @main ブランチの 最新状態を参照 影響:大 相手の更新が 即座に反映される (予期せぬ変更の恐れ) タグ指定 @v1.0.0 タグが指す 特定コミットに固定 影響:中 タグ貼替えがなければ 安定 (最もバランス良) コミットハッシュ @a3f2b1c… 完全に特定の コミットに固定 影響:ゼロ 書換え不可能 最も安全だが 更新も手動

ブランチ指定は一見便利ですが、参照先のリポジトリが更新された瞬間に自分たちの環境にも影響が及びます。共通部品の提供側が改修を入れた途端、予期せず挙動が変わるリスクがあるため、本番環境では避けるのが定石です。

タグ指定は、特定のバージョンに紐付けて参照するため、いつ新しいバージョンを取り込むかを自分たちでコントロールできます。多くのプロジェクトが採用する方式です。

コミットハッシュ指定は最も厳密で、サプライチェーン攻撃への耐性も高い反面、更新には毎回ハッシュを書き換える作業が発生します。

ワークフロー共用化が解決する具体的な課題

リポジトリが数十個規模になると、各リポジトリに同じようなworkflowファイルをコピペして運用する方式には限界が訪れます。外部アクションのバージョンアップや共通処理の修正が発生するたびに、すべてのリポジトリを個別に直す必要があり、メンテナンス工数が膨れ上がるからです。

ワークフロー共用化を導入すると、共通処理は1箇所のリポジトリに集約され、各サービスはそれをuses:で参照するだけになります。修正が必要になったときは共通リポジトリを1箇所直せばよく、呼び出し側は参照するタグを書き換えるだけで新しい処理を取り込めます。エディタの一括置換機能を使えば、数十のリポジトリへの反映も短時間で済みます。

中間層を設ける設計パターン

より大規模な組織では、共通部品を直接呼び出すのではなく、中間層となる共用リポジトリを挟む設計がよく採用されます。 呼び出し側 各サービスの リポジトリ uses 中間層 自チームが管理 取り込みタイミングを コントロール uses 共通部品 共同運営チーム が管理

なぜ中間層が必要なのでしょうか。共通部品のリポジトリが別チームや横断組織によって管理されている場合、そのチームの都合で改修が入ることがあります。呼び出し側が直接参照していると、知らないうちに挙動が変わってしまう危険があります。

呼び出し側 各サービスの リポジトリ uses 中間層 自チームが管理 取り込みタイミングを コントロール uses 共通部品 共同運営チーム が管理

そこで自チームが管理する中間層を挟むことで、上流の変更をいつ取り込むかを自分たちで決められるようになります。中間層は単なるラッパーとして機能し、安定版と評価できたタイミングで最下層の新バージョンを取り込んで、自分の中間層にも新しいタグを打つ、という運用になります。

タグを使った開発環境と本番環境の切り分け

共用リポジトリを開発用と本番用で物理的に分けると、管理が二重になって煩雑です。そこで、リポジトリ自体は1つにまとめ、タグで使い分ける運用がよく採られます。

典型的な例は、dev-versionprod-versionという2つの可変タグを用意し、それぞれをfeatureブランチからdevelopブランチへのマージ時、developからmainへのマージ時に自動で最新コミットに貼り替える、というものです。呼び出し側は開発環境なら@dev-version、本番環境なら@prod-versionと書いておくだけで、常に適切なバージョンを参照できます。

このタグ付けは手作業では運用が破綻するため、専用のGitHub Actionを作って自動化するのが一般的です。mainマージ時にバージョン番号を付与してGitHub Releaseを自動生成する仕組みと組み合わせると、さらに運用がスムーズになります。

まとめ

GitHub Actionsのworkflowは、.github/workflows/にYAMLを置くだけで自動的に有効になり、on:で指定したイベントをきっかけに使い捨ての仮想マシンで処理が実行されます。別リポジトリの部品を呼び出す仕組みにはReusable WorkflowとComposite Actionの2種類があり、それぞれ共通化したい粒度に応じて使い分けます。@記号の後ろで指定するブランチ・タグ・コミットハッシュは、参照の安定性と更新の反映速度のトレードオフを決める重要なポイントです。

複数リポジトリ運用で工数に悩んでいるなら、ワークフロー共用化は確実に効果が出る施策です。まずは小さな共通部品をComposite Actionとして切り出し、タグ指定で呼び出すところから始めてみるのがおすすめです。

目次