こんにちは、テクマトリックスの米田です。
CI/CDツールを利用して自動化の流れを検討・構築していると「特定のファイルやディレクトリに変更があった時だけ処理を実行したい」「必要なときだけ特定のジョブを実行したい」といったニーズが出てきます。今回はGitHub Actionsを利用して、このようなケースに直面した時のワークフローの記述方法について調べ、試してみました。GitHub Actionsの公式ドキュメントにも記載のある基本的な構文ばかりですが、本記事でまとめます。
目次
はじめに
GitHub Actionsは、GitHubで利用できるCI/CDツールとして広く利用されています。実行されるワークフローの効率化は、開発スピードの向上やコスト削減、リソースの有効活用といった多くのメリットをもたらします。特にクラウドベースのCI/CDツールを利用する場合、無駄なワークフローの実行は直接的なコストの増加や生産性の低下につながるため、出来る限り回避すべきです。
無駄なワークフロー実行による影響
1. 時間とリソースの浪費
不要なワークフローが実行されることで、開発者の待ち時間が増えます。たとえば、README.mdの修正やコメントの変更など、アプリケーション本体に影響しない変更でも、重たいビルドやテストが走る場合があります。この待ち時間がチーム全体に広がると、月単位・年単位の大きなロスになります。例えば、1回の無駄なワークフロー実行が5分で済むとしても、1日10回あれば50分、20営業日で約17時間のロスになります。
2. コストの増加
GitHub ActionsやCircleCIなどのクラウドベースのCI/CDツールは、無料枠を超えると使用時間や実行回数に応じて課金が発生します。
特に、モノレポ構成(1つのリポジトリに複数のプロジェクトが存在する構成)では、関係のない変更であってもすべてのワークフローが実行されることがあります。このような状況を放置すると、コストが大幅に増加してしまう可能性があります。
3. ワークフロー全体の混雑・遅延
ワークフローの実行数が増えすぎると、CIサービス側でジョブがキュー待ちの状態になることがあります。その結果、本当にワークフローを実行したいときに動かないという本末転倒な状態に陥ることもあります。
このような状況では、本来優先すべきリリース作業や緊急対応が後回しになり、プロジェクト全体の進行に影響を及ぼす可能性があります。
4. 無駄な通知の増加
多くのチームでは、CI/CDの実行結果をSlackやメールなどで通知する仕組みを導入していますが、通知が過剰に送られるとそれらがノイズになりかねません。関係のない変更による通知が増えることで、本当に重要な通知が埋もれてしまう危険性もあり、チームの情報共有にとって致命的な課題となる可能性があります。
無駄なワークフロー実行の回避方法
GitHub Actionsで無駄なワークフローの実行を回避するための基本的かつ効果的な方法を挙げます。
ファイルベースの実行制御(paths
/ paths-ignore
)
README.mdやドキュメントなどのファイル変更でワークフローが実行されないようにするには、paths
フィルターやpaths-ignore
フィルターを使います。ワークフローの実行を特定のファイルの変更だけに反応させることで、不要なワークフローの実行回数を削減できます。
paths
フィルターを使った以下の記述では、ソースコードが格納されているsrc
フォルダ内のファイルに変更があった場合のみワークフローが実行されます。
on:
push:
paths:
- 'src/**'
paths-ignore
フィルターを使った以下の記述では、README.md
やドキュメント類を格納しているdocs
フォルダ内のファイルに変更があった場合に、ワークフローが実行されないように制御できます。
on:
push:
paths-ignore:
- 'README.md'
- 'docs/**'
ブランチ・タグによる制御(branches
/ tags
)
Gitを利用した開発では、その作業に合わせてブランチを作成して作業を行うのが一般的です(例:Gitフロー、GitHubフロー)。GitHub Actionsを利用していくと、開発用・検証用・本番用など、異なるブランチごとに異なるワークフローが必要になる場合があります。このような場合、branches
フィルターにより対象のブランチを限定することで、不要なワークフローの実行を防止します。
branches
フィルターを利用した以下の記述では、main
ブランチに変更が push されたときだけワークフローが実行されます。例えばmain
ブランチにマージされた時だけある処理を実行したい場合など、ブランチごとに異なる処理の振り分ける際に活用できます。
on:
push:
branches:
- main
リリースのタイミングだけワークフローを実行したいときは、tags
フィルターを使用してタグ付きのpushに限定する方法が有効です。これにより、通常のpushやプルリクエスト(PR)ではワークフローは実行されず、タグがpushされたときだけワークフローが実行されます。
tagsフィルターを使った以下の記述では、v1.0.0
や v2.1.5
のような形式のタグが push されたときだけワークフローが実行されます。例えば、バージョンを明示したときだけリリース系の処理を実行したい場合に利用できます。
on:
push:
tags:
- 'v*.*.*'
実行条件の追加(if:
)
GitHub Actionsでは if:
を使った条件分岐によって、ワークフローに定義されたジョブごとに柔軟な実行条件を設定することができます。これにより、特定のイベントやブランチに応じた処理をジョブレベルで制御することができ、無駄なジョブの実行を回避し、リソースの節約や誤動作の防止に役立ちます。
例えば以下の設定では、deploy
ジョブに条件式を設定することで、main
ブランチへのpush(PRのマージ)時だけデプロイを行うように制御できます。
jobs:
deploy:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- run: echo "本番デプロイ処理を実行します"
長時間ジョブの強制終了(timeout-minutes
)
意図せずジョブが長時間実行され、無料枠を浪費してしまうのは避けたいところです。このような事態を未然に防止する手段として、タイムアウト時間を設定することは有効です。
(GitHub Actionsのジョブのタイムアウトの時間はデフォルトでは6時間です。デフォルトのタイムアウトに関する公式ドキュメントの記述はこちら。)
timeout-minutes
で実際の処理時間に応じた上限を設定しておくことで、一定時間でジョブを強制終了でき、無駄な実行やリソースの消費を防ぐことができます。
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 10 # 最大10分で強制終了
試してみる
上記で挙げた手法をいくつか踏襲して、GitHub Actionsのワークフローを実際に設定・実行してみます。
用意したリポジトリの構成とワークフローのymlファイルの内容を以下に示します。リポジトリにはJavaを用いたソースコードファイルを格納しており、JavaのビルドツールであるMavenを用いたビルドやテストを行います。
ワークフローでは以下の内容を確認します。
README.md
だけの変更ではワークフローの実行をスキップする- ソースコード本体(
src/
)の変更がdevelop
ブランチにpushされた場合はワークフローが実行され、test
ジョブのみ実行される develop
ブランチをmain
ブランチへマージするPR作成後、build-and-test
ジョブのみ実行されるmain
ブランチへのPRマージ時のみ、ワークフローはbuild-and-test
ジョブに加えてdeploy
ジョブも実行する
./
├── README.md
├── pom.xml # Mavenのビルド設定ファイル
├── src/
| └── main/java/com/mycompany/app/App.java # ソースコード
│ └── test/java/com/mycompany/app/AppTest.java # テストコード
└── .github/
└── workflows/
└── ci.yml # ワークフローファイル
name: Demo workflow
on:
# main・developブランチへpush時、src/**に変更がある場合のみ実行
push:
branches:
- main
- develop
paths:
- 'src/**'
# mainブランチへのPR作成・更新時に実行
pull_request:
branches:
- main
jobs:
build-and-test:
name: Run build and test
runs-on: ubuntu-latest
steps:
# 1. リポジトリをチェックアウト
- name: Checkout repository
uses: actions/checkout@v4
# 2. Javaのセットアップ
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
# 3. Mavenでビルドとテストの実行
- name: Build and Test with Maven
run: mvn -B clean install
# mainブランチにpushされた場合のみ実行
deploy:
name: Deploy to Production
runs-on: ubuntu-latest
needs: build-and-test
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Deploy to server
run: echo "mainブランチにマージされたのでデプロイジョブを実行しました"
① README.md
だけの変更ではワークフローの実行をスキップする
まずは、develop
ブランチ上でREADME.md
を変更してpushします。この変更ではソースコードに影響を与えないため、ワークフローが実行されないことを確認します。
実際にdevelop
ブランチ上でREADME.md
を編集してコミットをpushしたところ、GitHub Actions の「Actions」タブにはワークフローの実行履歴は表示されませんでした。これはci.yml
のpush
イベントにpaths: src/**
の指定があるため、README.md
の変更ではワークフローがトリガーされないためです。

develop
ブランチでREADME.md
を修正してもワークフローが実行されない様子② ソースコード本体(src/
)の変更がdevelop
ブランチにpushされた場合はワークフローが実行され、build-and-test
ジョブのみ実行される
次に、develop
ブランチでsrc
フォルダ内のApp.java
を編集し、同様にpushします。このファイルはソースコードの一部で、テストが必要な対象です。
リポジトリにpush後、GitHub Actions上でbuild-and-test
ジョブ(Run build and test)が自動的に実行されました。これはリポジトリにpushした変更内容がpaths: src/**
の条件に合致しているためで、ソースコードの変更が行われたときにのみワークフローが実行されるよう設定しているためです。

develop
ブランチでsrc
フォルダ内のApp.java
を修正し、ワークフローが実行される様子③ develop
ブランチをmain
ブランチにマージするPRを作成後、build-and-test
ジョブのみ実行される
続いて、develop
ブランチからmain
ブランチにマージするためのプルリクエスト(PR)を作成します。develop
ブランチには上記①,②で行ったREADME.md
とsrc
フォルダ内のApp.java
の修正が含まれています。
PR 作成後、ワークフローが起動し、build-and-test
ジョブが実行されました。これは pull_request
イベントで、main
ブランチにマージするための PR を作成した後にワークフローが実行される設定をしているためです。

develop
ブランチをmain
ブランチにマージするPR作成後にワークフローが実行される様子④ main
ブランチへのPRマージ時のみ、ワークフローはbuild-and-test
ジョブに加えてdeploy
ジョブも実行する
最後に③で作成したPRをmain
ブランチにマージします。この操作はmain
ブランチへのpushイベントとして扱われます。
マージ後、GitHub Actions上でtest
ジョブとdeploy
ジョブの両方が実行されました。これはpush
イベントがmain
ブランチを対象としており、さらにdeploy
ジョブにはif: github.event_name == 'push' && github.ref == 'refs/heads/main'
という条件が設定されているため、main
ブランチに対するpush(PRのマージ)のタイミングでのみdeploy
ジョブが動作しました。

main
ブランチにマージした時にワークフローが実行される様子このように、GitHub Actionsのbranches
フィルターやpaths
フィルター、pull_request
といったトリガー設定を適切に使い分けることで、不要なワークフローの実行を抑制しつつ、品質を保つために必要なタイミングでワークフローを実行させることが可能になります。
また、Mavenのような、ライブラリを使用するワークフローでは、各ジョブでキャッシュを設定することで、ダウンロード済みのライブラリを再利用できます。キャッシュを活用することで、より効率的にワークフローを実行することが見込めます。(GitHub Actionsのキャッシュに関する公式ドキュメントはこちら)
まとめ
GitHub Actionsによるワークフローの実行は、リポジトリ内に変更が加わると自動で実行されるので非常に便利です。しかし、その便利さゆえに、必要のないタイミングでワークフローが実行され、不要なコストや混乱が発生する場合があります。今回紹介した無駄なワークフローの実行を回避する手法は、いずれもGitHub Actionsの基本的な構文を利用したもので、すぐに取り入れられるものばかりです。無駄なワークフローの実行を回避することは意識すべき重要なポイントだと思うので、ぜひご参考ください。
弊社の開発基盤構築ソリューションチームでは、GitHub ActionsやJenkinsを利用したCI環境の構築を承っています。CI環境の導入や構築について気になることがあれば、ぜひお気軽にお問い合わせください。