はじめに
この記事はGitHubActionsについて、名前は知っているけどその実態は何も知らない成人男性がGitHubActionsでコードをテスト~デプロイを行うワークフローを作ってみた話です。
GitHubActionsってなんだ
GitHubActionsはGitHubの提供するCI/CDプラットフォームです。
プルリクエストが作成されたタイミングでテストコードを実行したり、mainブランチへマージされたタイミングでビルドやデプロイを行うワークフローを実行できるほか、イシューを作成したタイミングでラベルを付けるといったこともできるそうです。
GitHub Actions は、DevOps であるだけでなく、リポジトリで他のイベントが発生したときにワークフローを実行できます。 たとえば、リポジトリで新しい issue が作成されるたびに、適切なラベルを自動的に追加するワークフローを実行できます。
GitHubActions Words
出てくるワードが分からんのでまとめてみました。
ワークフロー
1つ以上のジョブを実行する自動化プロセス。
.github/workflows/配下のYAMLファイルで定義する。
ジョブ
ワークフローを構成する各スクリプトやアクション。
イベント
プッシュやフォーク、イシューの作成といったGitHub上のアクションのことで、イベントをトリガーにワークフローが実行される。
使ってみよう
なんとな~く概要を知ったつもりになったところで今回は以下の2つのワークフローを作ってみます。
- プルリクエストが作成されたらテストコードを実行する
- mainブランチへマージされたらビルドしてGitHubPagesに静的サイトをデプロイする
プロジェクトの準備
viteでReactプロジェクトを作成して必要なパッケージをインストールします。
npm create vite@latest
npm install -D vitest @vitest/coverage-v8
適当にvitestの設定をします。
const defaultExclude = ["coverage/**",
"dist/**",
"**\/[.]**",
"packages/*\/test?(s)/**",
"**\/*.d.ts",
"**\/virtual:*",
"**\/__x00__*",
"**\/\x00*",
"cypress/**",
"test?(s)/**",
"test?(-*).?(c|m)[jt]s?(x)",
"**\/*{.,-}{test,spec}?(-d).?(c|m)[jt]s?(x)",
"**\/__tests__/**",
"**\/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build}.config.*",
"**\/vitest.{workspace,projects}.[jt]s?(on)",
"**\/.{eslint,mocha,prettier}rc.{?(c|m)js,yml}"
];
export default defineConfig({
plugins: [react()],
test: {
globals: true,
environment: "jsdom",
include: ["test/**/*.test.{js,ts,jsx,tsx}"],
coverage: {
provider: "v8",
exclude: [...defaultExclude, "src/main.tsx"],
thresholds: {
statements: 100,
branches: 100,
functions: 100,
lines: 100
}
},
alias: { "@": path.resolve(__dirname, "./test"), }
}
});
適当にテストコードを書きます。
import { describe, test, expect } from "vitest";
import React from "react";
import { render, screen } from "@testing-library/react";
import App from "../src/App";
describe("App Test", () => {
test("render check", () => {
render(<App />);
expect(screen.getByText("Vite + React")).toBeTruthy();
});
});
プルリクエストの作成時にテストコードを実行するワークフロー
.github/workflows/配下にワークフローの設定ファイルを作成します。
name: Run Vitest And Check Coverage
run-name: test coverage
# プルリクエストの作成時に実行する
on: [pull_request]
# ワークフローで実行するジョブ定義
jobs:
test:
# ジョブを実行するOS
runs-on: ubuntu-latest
steps:
# リポジトリをチェックアウトする
- name: Checkout repository
uses: actions/checkout@v4
# Node.jsを使用する
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
# 依存関係をインストール
- name: Install dependencies
run: npm install
# Vitestを実行
- name: Run vitest
run: npm run test
on
ワークフローを実行するイベントを記述します。
プルリクエストの作成時(pull_request)やプッシュ時(push)のほかにも指定できるイベントはかなり多いです。
以下の形式で特定のブランチのみワークフローを実行することも可能です。
# mainブランチへプッシュされたときにワークフローを実行する
on:
push:
branches:
- "main"
jobs
ワークフローで実施するジョブを記述します。
ジョブ自体は並列で実行されますが、needs
を指定することで特定のジョブが完了してから実行する、といった制御も可能です。
runs-on
ジョブを実行するOS(ランナー)を設定します。
GitHubホステッドランナー(Ubuntu、Windows、macOS)のほか、独自で設定するセルフホステッドランナーを設定できます。
uses
GitHubやユーザの作成したアクションをワークフロー内から実行することが出来ます。
上記コードで使用しているactions/checkout@v4
やactions/setup-node@v4
はGitHubが作成して公開しているアクションです。
テストコードの自動実行
ワークフローの設定ができたところで、適当にブランチを切ってmainブランチへのプルリクエストを作成します。
その際、vitestのコードカバレッジが100%にならないように変更を加えておきます。
プルリクエストを作ったらGithubActionsが実行されています。
このまま実行が完了するまで待ってみましょう。
カバレッジが100%未満なのでエラーが出ていますが、
このままでもマージはできてしまうので、リポジトリの設定を弄ってテストでエラーが出た場合はマージできないようにしてみましょう。
リポジトリのルールセットから、mainブランチに対するルール設定を追加します。
今回はRequire status checks to pass before merging
を有効化することでマージ前のステータスチェック通過を必須条件とし、必要なステータスチェックとしてGitHubActionsのtestワークフローを追加しています。
これでテストコードのカバレッジを100%にしないとマージできないようになりました。
コードのカバレッジが100%になるよう修正してプッシュしてみると
ステータスチェックが正常に完了し、マージできるようになりました。
mainブランチへマージされたらGitHubPagesにデプロイするワークフロー
.github/workflows/配下にtestとは別のワークフローファイルを作成します。
name: Build Application
run-name: build and deploy
on:
push:
branches:
- "main"
jobs:
build:
runs-on: ubuntu-latest
steps:
# リポジトリをチェックアウトする
- name: Checkout repository
uses: actions/checkout@v4
# Node.jsを使用する
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
# 依存関係をインストール
- name: Install dependencies
run: npm install
# ビルドを実行
- name: Run build
run: npm run build
# ビルドしたアーティファクトをアップロード
- name: Upload artifact files
uses: actions/upload-pages-artifact@v2
with:
path: ./dist
deploy:
runs-on: ubuntu-latest
# GitHub Pagesのデプロイ権限を設定
permissions:
contents: read
pages: write
id-token: write
# buildが完了してから実行する
needs: build
steps:
# GitHub Pagesにデプロイ
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v3
ワークフローを作成したところで適当なブランチへプッシュしてmainブランチへマージします。
マージのタイミングでデプロイ用ワークフローが動いていることが確認できます。
ワークフローがちゃんと完了し、GitHubPagesに静的サイトがデプロイされていました。
おわりに
GithubActionsを使って簡単な仕様のCI/CDを試してみましたが、かなり簡単に実装できるものでしたね。
GitHubは個人で適当に遊ぶ用のリポジトリを用意する程度にしか使ってきませんでしたが、もう少しGitHubの可能性に目を向けるべきだったのかもしれません。
気が向いたらもう少し凝ったワークフローを作って記事を書いてみたいですね。
参考記事