コピペでも使える!? GitHub Actionsのワークフロー
はじめに
こんにちは。フロントエンドエンジニア 2 年生の柿です。
今回は GitHub Actions を使ってすぐに品質管理の CI/CD を行うためのワークフローをご紹介しようと思います。
(CI/CD と言いたくなりますよね、なんとなく響きがいいですし!)
GitHub Actions とは
そもそも GitHub Actions とは何なんでしょうか?
私はカッコつけるためだけに認識していた程度です。
柿「あー、あれね?イケてるよね」
ここで改めて知っておきましょう。
GitHub Actions とは、GitHub が提供する自動化ツールです。
例えば、ビルドやテスト、デプロイなどの作業を自動で実行することができます。
GitHub Actions は何をするのか
GitHub Actions は、特定のイベントが発生したときに特定のアクションを実行することができます。
例えば、プルリクエストを作成したら、GitHub Actions が「よし、テストしとくぜ!」とばかりに動き出します。
特定のイベント
特定のイベントとは、例えば以下のようなものです。
- プルリクエストの作成
- プッシュ
- ラベル付与
などです。
特定のアクション
特定のアクションとは、例えば以下のようなものです。
- テストの実行
- ビルド
- 自動デプロイ
- 静的解析
など、日常的な作業を代わりにやってくれる頼れるやつです。
これらのアクションを組み合わせることで、以下のようなことが実現できます。
-
テストの自動実行: プルリクエストが作成された瞬間に、テストが自動で実行されます。手元で
pnpm test:ui
としていたのが懐かしいですね。 - 静的解析: プルリクエストを作成したときに、ESLint や Prettier があなたのコードをしっかりチェック。「このコード、ちょっと整ってないですよ?」とやんわり指摘してくれます。
- 自動デプロイ: "main" もしくは "master" ブランチにプッシュした瞬間、デプロイ作業が自動で進行。「スッコココ、デプロイ完了!」とお知らせが来るのを待つだけになります。
さらに、設定次第ではテストや静的解析に合格しないとマージできないようにすることも可能です。
少し大げさですが、あなたのコードを守る鉄壁の防御ラインを作ることができます。少しは魅力が伝わったでしょうか?
CI/CD とは?
GitHub Actions を理解するうえで欠かせない概念が CI/CD です。
スタバでも「今日は CI 回した?」なんて会話が聞こえてきそうです。(まともならスタバにはいない)
でも、なんとなく「CI/CD ってカッコいい!」と思っていた皆さん、一緒にちゃんと理解していきましょう。
私は雰囲気だけ人間でした!!
CI (継続的インテグレーション: Continuous Integration)
プログラマーがコードの変更を GitHub にプッシュしたときに、自動でテストやビルドを実行し、問題が無いかを確認してくれます。まるであなたのコードがいつも安全かどうかチェックしてくれる警備員のようです。
テストが失敗しているのにマージされてしまうといった問題を事前に防ぐことができるので、プロジェクトの品質を保つことができますね!
CD (継続的デリバリー: Continuous Delivery) / (継続的デプロイ: Continuous Deployment)
テストが成功したコードを自動的に本番環境や STG 環境にデプロイすることです。
CD には 2 つのパターンがあります。
- 継続的デリバリー (Continuous Delivery): テストがパスした後、手動で本番環境にデプロイする状態を自動で整えることです。
- 継続的デプロイ (Continuous Deployment): テストがパスしたコードを自動的に本番環境にデプロイすることです。
デプロイを自動化するかどうかが 2 つの違いです。
もうデプロイのたびに夜勤をする必要は無いかもしれません!
GtiHub Actions を使った CI/CD のメリット
GitHub Actions を使った CI/CD のメリットは以下の通りです。
- コードの品質向上: テストや静的解析を自動で実行することができ、問題が発生した場合にすぐに気付き、結果としてコードの品質が向上します。
- 効率的な開発: テストやビルド、デプロイなどの作業を自動で行うことができるので、開発者は本来の開発に集中することができます。
- チーム開発の促進: 複数の開発者が同じブランチに対して作業をしても、CI/CD でテストや政敵解析を行うので、開発者間でズレが生じることを防ぐことができます。
GitHub Actions の競合サービス
GitHub Actions は GitHub でしか使えません。
競合サービスとしては以下のものがあります。
- BitBucket Pipelines
- BitBucket 用の GitHub Actions のようなものです。
- GitLab CI
- GitLab 用の GitHub Actions のようなものです。
GitHub Actions の例
GitHub Actions のワークフローは、YAML ファイルで記述します。
ワークフローとは
GitHub Actions では、処理の流れを「ワークフロー(workflow)」と呼びます。
ワークフローは、自動で実行したい一連の処理を定義したものです。
例えば、以下は、プルリクエストを作成したときに、テストを自動で実行するワークフローの例です。
name: Test
on:
pull_request:
branches:
- main
types:
- opened
- synchronize
workflow_dispatch:
jobs:
test:
name: 'Run tests'
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install dependencies
run: npm install
- name: Run tests
run: npm run test
この例は、プルリクエストが作成されたときにテストを自動で実行するという一連の作業を「ワークフロー」として定義しています。
以下に、このワークフローの各部分について簡単に説明をします。
name
name
はワークフロー全体の名前をつける部分です。
上記の例では、Test
という名前をつけています。
この名前は GitHub Actions の UI 上に表示されるので、今なんのワークフローが実行されているかが分かりやすくなります。
on
on
はワークフローが実行されるタイミングを指定する部分です。
上記の例では、2 つのイベントがトリガーとなっています。
-
pull_request
- プルリクエストが作成または更新されたときにワークフローが実行されます。
-
branches
でmain
ブランチへのプルリクエストのみが対象となるように指定しています。 -
types
でopened
とsynchronize
のイベントがトリガーとなるように指定しています。-
opened
はプルリクエストが作成されたとき -
synchronize
はプルリクエストがコミットなどで更新されたとき
-
-
workflow_dispatch
- 手動でワークフローをトリガーすることができるようにしています。
- GitHub の UI からワークフローを手動で起動できます。
jobs
jobs
はワークフローの中で実行する一連の作業をまとめたものです。
上記の例では、test
という名前のジョブを定義しています。
ジョブは 1 つ以上のsteps
を含まなければなりません。
runs-on
runs-on
は、ジョブがどの環境で実行されるかを指定します。
上記の例では、ubuntu-latest
と指定しているので、Ubuntu の最新バージョンの実行環境でジョブが実行されることになります。
これは、テストやビルドなどを実行するための仮想環境になります。
steps
steps
はジョブの中で、どの手順で作業を進めるかを示す部分です。
ステップは順番に実行され、上記の例では以下の 4 つのステップが定義されています。
-
Checkout source code
- リポジトリのソースコードをチェックアウト(取得)します
-
actions/checkout@v4
は GitHub が提供するアクションで、ソースコードをワークフロー内で利用可能にします。
-
Set up Node.js
- プロジェクトで Node.js を使っているため、Node.js のセットアップを行います。
-
actions/setup-node@v4
は GitHub が提供するアクションで、Node.js のセットアップを行います。上記の例では、Node.js のバージョンを 18 に指定しています。
-
Install dependencies
-
npm install
を実行して、プロジェクトで必要な依存関係をインストールします。
-
-
Run tests
-
npm run test
を実行して、テストを実行します。
-
以上が、GitHub Actions のワークフローの例です。
すぐに使えそうなワークフローのご紹介
さぁ、ここまで GitHub Actions とは一体なんぞやという話や一例のご紹介をしておさらいをしました。
ここからはほぼコピペで使えそうなワークフローをご紹介していきたいと思います。
開発環境としては、以下のものが導入されていることを前提のものを紹介していくので、適宜必要な部分を取捨選択してください。
- TypeScript
- ESLint
- Prettier
- Biome
- Vitest
- pnpm
TypeScript
TypeScript の型チェックをするときのワークフローです。
まずは package.json に以下のスクリプトを追加します。
{
"scripts": {
"ci:typecheck": "tsc --noEmit",
}
}
次に、.github/workflows/typecheck.yml
を作成します。
name: Type Check
on:
pull_request:
branches:
- main
types:
- opened
- synchronize
workflow_dispatch:
env:
NODE_VERSION: 20.17.0
PNPM_VERSION: 9
jobs:
typecheck:
name: 'TypeScript Type Check'
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Set Node.js version to ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
- name: Install dependencies
run: pnpm install
- name: Run TypeScript type check
run: pnpm ci:typecheck
Vitest
Vitest でテストを実行するときのワークフローです。
まずは package.json に以下のスクリプトを追加します。
{
"scripts": {
"ci:test": "vitest",
}
}
次に、.github/workflows/test.yml
を作成します。
name: Run Tests
on:
pull_request:
branches:
- main
types:
- opened
- synchronize
workflow_dispatch:
env:
NODE_VERSION: 20.17.0
PNPM_VERSION: 9
jobs:
test:
name: 'Run Tests'
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Set Node.js version to ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
- name: Install dependencies
run: pnpm install
- name: Run Tests
run: pnpm ci:test
ESLint
ESLint で静的解析をするときのワークフローです。
まずは package.json に以下のスクリプトを追加します。
{
"scripts": {
"ci:lint": "eslint .",
}
}
次に、.github/workflows/lint.yml
を作成します。
name: Run ESLint
on:
pull_request:
branches:
- main
types:
- opened
- synchronize
workflow_dispatch:
env:
NODE_VERSION: 20.17.0
PNPM_VERSION: 9
jobs:
test:
name: 'Run ESLint'
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Set Node.js version to ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
- name: Install dependencies
run: pnpm install
- name: Run ESLint
run: pnpm ci:lint
Prettier
Prettier でフォーマットが適切か確認するときのワークフローです。
まずは package.json に以下のスクリプトを追加します。
{
"scripts": {
"ci:prettier": "prettier --check .",
}
}
次に、.github/workflows/prettier.yml
を作成します。
name: Run Prettier
on:
pull_request:
branches:
- main
types:
- opened
- synchronize
workflow_dispatch:
env:
NODE_VERSION: 20.17.0
PNPM_VERSION: 9
jobs:
test:
name: 'Run Prettier'
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Set Node.js version to ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
- name: Install dependencies
run: pnpm install
- name: Run Prettier
run: pnpm ci:prettier
Biome
Biome でコンポーネントのテストを実行するときのワークフローです。
まずは package.json に以下のスクリプトを追加します。
{
"scripts": {
"ci:biome": "biome check",
}
}
次に、.github/workflows/biome.yml
を作成します。
name: Run Biome
on:
pull_request:
branches:
- main
types:
- opened
- synchronize
workflow_dispatch:
env:
NODE_VERSION: 20.17.0
PNPM_VERSION: 9
jobs:
test:
name: 'Run Biome'
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Set Node.js version to ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
- name: Install dependencies
run: pnpm install
- name: Run Biome
run: pnpm ci:biome
Build
ビルドを実行するときのワークフローです。
.github/workflows/build.yml
を作成します。
name: Run Build
on:
pull_request:
branches:
- main
types:
- opened
- synchronize
workflow_dispatch:
env:
NODE_VERSION: 20.17.0
PNPM_VERSION: 9
jobs:
test:
name: 'Run Build'
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Set Node.js version to ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
- name: Install dependencies
run: pnpm install
- name: Run Build
run: pnpm build
以上、GitHub Actions のワークフローの例をご紹介しました。
これらの品質管理関連のワークフローを一つにまとめることもできます。
また、共通している処理を外部ファイルに切り出すこともできます。
例えば以下のようにできます。
.github/actions/install/action.yml
という依存関係をインストールする部分を外部ファイルに切り出してみます。
name: 'Install'
description: 'Setup Node.js, install pnpm, and install project dependencies'
inputs:
pnpm-version:
description: 'The version of pnpm to install'
required: false
default: 'lts/*'
node-version:
description: 'The version of Node.js to use'
required: false
default: 'lts/*'
husky:
description: 'Whether to disable Husky hooks during CI/CD'
required: false
default: 0
runs:
using: 'composite'
steps:
- name: Install pnpm
id: install-pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ inputs.pnpm-version }}
- name: Set Node.js version to ${{ inputs.node-version }}
id: setup-node
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: 'pnpm'
- name: Install dependencies
shell: bash
run: pnpm install
env:
HUSKY: ${{ inputs.husky }}
inputs
の部分は Props のようなもので、外部から値を受け取ることができます。
受け取らなかった場合のデフォルト値も設定可能です。
今回の共通処理では husky のフックを無効化して、影響を受けないようにしています。
この共通処理を使うと、各ワークフローの冗長な部分を削減することができます。
name: Run Tests
on:
pull_request:
branches:
- main
types:
- opened
- synchronize
workflow_dispatch:
jobs:
test:
name: 'Run Tests'
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Install dependencies
uses: ./.github/actions/install
- name: Run Tests
run: pnpm ci:test
ワークフローの可読性を向上させることができましたね。
では、最後に品質管理用としてまとめたワークフローをご紹介します。
- 型チェック
- テスト
- Biome のチェック
- Prettier のチェック
- Build が通るか
これらを確認するワークフローを例としてご紹介します。
name: 'Install'
description: 'Setup Node.js, install pnpm, and install project dependencies'
inputs:
# 使用する pnpm のバージョン
pnpm-version:
description: 'The version of pnpm to install'
required: false
default: 'lts/*'
# 使用する Node.js のバージョン
node-version:
description: 'The version of Node.js to use'
required: false
default: 'lts/*'
# CI/CD で Husky のフックを無効にするかどうか
husky:
description: 'Whether to disable Husky hooks during CI/CD'
required: false
default: 0
runs:
using: 'composite'
steps:
# pnpm のインストール
- name: Install pnpm
id: install-pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ inputs.pnpm-version }} # 入力された pnpm のバージョンを使用
# Node.js のバージョンを設定
- name: Set Node.js version to ${{ inputs.node-version }}
id: setup-node
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }} # 入力された Node.js のバージョンを使用
cache: 'pnpm' # pnpm 用のキャッシュを有効化
# プロジェクトの依存関係をインストール
- name: Install dependencies
shell: bash
run: pnpm install # pnpm を使って依存関係をインストール
env:
HUSKY: ${{ inputs.husky }} # Husky のフックを無効にするための環境変数を設定
name: Quality Check
on:
# プルリクエストが「main」または「develop」ブランチに対して開かれたり、追加でコミットされたときに実行
pull_request:
branches:
- main
- develop
types:
- opened
- synchronize
# 手動でワークフローを実行する場合のトリガー
workflow_dispatch:
env:
# Node.js と pnpm のバージョン設定
NODE_VERSION: 20.17.0
PNPM_VERSION: 9
jobs:
# TypeScript の型チェックを行うジョブ
typecheck:
name: 'TypeScript Type Check'
runs-on: ubuntu-latest
steps:
# ソースコードをチェックアウト(GitHub Actions がリポジトリのコードを取得)
- name: Checkout source code
uses: actions/checkout@v4
# Node.js と依存関係をインストール
- name: Setup Node.js and install dependencies
uses: ./.github/actions/install
with:
pnpm-version: ${{ env.PNPM_VERSION }} # 環境変数で設定した pnpm のバージョンを使用
node-version: ${{ env.NODE_VERSION }} # 環境変数で設定した Node.js のバージョンを使用
# TypeScript の型チェックを実行
- name: Run TypeScript type check
run: pnpm ci:typecheck
# ユニットテストを実行するジョブ
test:
name: 'Run Unit Tests'
runs-on: ubuntu-latest
needs: typecheck # TypeScript の型チェックが成功した後に実行
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Setup Node.js and install dependencies
uses: ./.github/actions/install
with:
pnpm-version: ${{ env.PNPM_VERSION }}
node-version: ${{ env.NODE_VERSION }}
# Vitest を使ってユニットテストを実行
- name: Run Vitest
run: pnpm ci:test
env:
CI: true # CI 環境用に設定
# コードスタイルチェックを行うジョブ
biome:
name: 'Biome Code Style Check'
runs-on: ubuntu-latest
needs: typecheck # 型チェックが成功した後に実行
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Setup Node.js and install dependencies
uses: ./.github/actions/install
with:
pnpm-version: ${{ env.PNPM_VERSION }}
node-version: ${{ env.NODE_VERSION }}
# Biome(コードフォーマット & スタイルチェックツール)を実行
- name: Run Biome check
run: pnpm ci:biome
# Prettier を使ってコードの整形を確認するジョブ
prettier:
name: 'Prettier Formatting Check'
runs-on: ubuntu-latest
needs: typecheck # 型チェックが成功した後に実行
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Setup Node.js and install dependencies
uses: ./.github/actions/install
with:
pnpm-version: ${{ env.PNPM_VERSION }}
node-version: ${{ env.NODE_VERSION }}
# Prettier を使ってコードのフォーマットを確認
- name: Run Prettier check
run: pnpm ci:prettier
# プロジェクトのビルドを行うジョブ
build:
name: 'Build the Project'
runs-on: ubuntu-latest
needs: [typecheck, test, biome, prettier] # 型チェック、テスト、コードスタイル、整形が成功した後に実行
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Setup Node.js and install dependencies
uses: ./.github/actions/install
with:
pnpm-version: ${{ env.PNPM_VERSION }}
node-version: ${{ env.NODE_VERSION }}
# プロジェクトのビルドを実行
- name: Run Build
run: pnpm build
以上で品質管理用のワークフローを作成することができました。
ところどころで、needs
というキーワードを使っています。
needs
にジョブ名を指定することで、そのジョブが成功した後に実行されるようになります。
needs
を使うことで、ジョブ間の依存関係を定義でき、指定したジョブが成功した場合にのみ次のジョブが実行されます。
もし依存するジョブが失敗した場合、その後のジョブはスキップされます。これにより無駄な実行を防ぎ、効率的にワークフローを進めることができます。
例えば、型チェックが失敗しているときにテストなどをしても失敗する可能性は高いですし、テストが失敗しているときにビルドをしても成功とする可能性は低いです。
まとめ
今回は GitHub Actions を使って CI/CD を行うためのワークフローを一緒に見てきました。
GitHub Actions を使えば、手動で行っていた面倒な作業を自動化し、開発者が本来集中すべき「コードを書く」という本業に専念できるようになります。
それだけではありません。
自動化されたテストやビルドにより、コードの品質を保ち、チームの誰かがうっかりミスをしても事前に発見できるのです。
つまり、GitHub Actions は、あなたのプロジェクトにとっての「見えない仲間」です。
カッコつけて「CI/CD」と言いたいだけでなく、実際にその力を活用してみましょう!
Discussion