GitHub Actions学習のまとめとして、Create React AppのプロジェクトのCI/CDパイプラインを構築してみました。
使用したnpmパッケージについては以下の記事でまとめています。
#プロジェクトの作成
npx create-react-app react-app --use-npm
でプロジェクトを作成します。
#ワークフローの構成
Git-flowでの運用を想定して、以下のタイミングで実行するワークフローを作成します。
- featureからdevelop向けのプルリクを作成したとき
- プルリクが承認されてfeatureがdevelopへマージされたとき
- developからmaster向けのプルリクを作成したとき
- プルリクが承認されてdevelopがmasterへマージされたとき
加えて、リリースされたらSlackに通知するワークフローも作成します。
#ワークフローの作成
前項の図でワークフローが4つありましたが、これらを1つのymlファイルに記述します。
##ワークフロー①の作成(一部分)
まずは①(featureからdevelop向けのプルリクを作成したとき)のワークフローの内容を記述します。
name: CI
on:
pull_request:
branches: [develop] #develop向けのプルリクが作成されたときにジョブを実行
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2 #チェックアウトするアクション
- name: Use NodeJS
uses: actions/setup-node@v1 #特定バージョンのnodeを設定するアクション
with:
node-version: "12.x"
- run: npm ci #dependencyのインストール
- run: npm run format:check #コードフォーマットチェック
- run: npm test -- --coverage #テスト実行
env:
CI: true #現在の環境がCI環境であることを仮定
ここではdependencyのインストール、コードフォーマットチェック、テスト実行を記述しています。
CIにおいては、npm install
ではなくnpm ci
でdependencyのインストールを行います。
npm ci
では、依存関係の更新をせずに整合性チェックと依存パッケージのダウンロードのみを行うため、npm install
より高速に動作し、CIで必要なことだけを行うことができます。
CI: true
ではテストがCI環境で実行されることを仮定しています。
##ワークフロー②の作成
developからworkflowというfeatureブランチをきって、git push
してdevelop向けのプルリクをつくるとワークフローが実行されます。
ワークフロー②(プルリクが承認されてfeatureがdevelopへマージされたとき)の内容のステップを追記します。
name: CI
on:
pull_request:
branches: [develop]
push:
branches: [develop] #developにマージされたときに実行
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use NodeJS
uses: actions/setup-node@v1
with:
node-version: "12.x"
- run: npm ci
- run: npm run format:check
- run: npm test -- --coverage
env:
CI: true
- name: Build Project #ステージング用のビルドを行うステップ
if: github.event_name == 'push' #pushイベントのときだけ実行
run: npm run build #ビルド実行
- run: npm install -g surge #surgeのインストール
- name: Deploy to Staging #ステージングデプロイを行うステップ
if: github.event_name == 'push' #pushイベントのときだけ実行
run: npx surge --project ./build --domain awesome-quiet.surge.sh #デプロイ
env: #surgeの認証
SURGE_LOGIN: ${{ secrets.SURGE_LOGIN }} #surge whoamiで取得
SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }} #surge tokenで取得
developへのマージをトリガにするために、develop向けのpushイベントを追加します。
また、ワークフローは①と②で共有されているので、ビルドやデプロイがpull_requestイベントで実行されないように、if: github.event_name == 'push'
という実行条件を追加します。
今回、デプロイにはsurgeというnpmパッケージを使用しています。ログイン名とパスワード(token)を予め作成して、GitHubリポジトリのsecretsに環境変数として登録しておきます。
ワークフローの実行内容を確認すると、developへのプルリク時点ではbuild, deployステップを飛ばしています。
developへマージ(push)するとbuild, deployが実行されています。
##dependencyのキャッシュ
ワークフローごとにnpm ci
行うのは無駄なので、dependenciesのキャッシュ用のアクションをステップに追加します。
steps:
- uses: actions/checkout@v2
- name: Cache node_modules
uses: actions/cache@v1
with:
path: ~/.npm #キャッシュしたファイルとキーを格納する場所(OSによって異なる)
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} #キャッシュのリストアや保存をするためのキー
restore-keys: | #キャッシュをリストアするためのキーのリスト
${{ runner.os }}-node-
hashFiles
を使用することで、depencencyに変更があったときに新しいキャッシュをつくることができます。
最初のワークフローを実行すると、以下のようにキーが生成されます。
##Artifact(テストカバレッジ、ビルドファイル)のアップロード
テストとビルドの後にGitHubのActionsタブからArtifactをダウンロードできるようにするため、これらをアップロードするアクションをステップを追加します。
- run: npm test -- --coverage
env:
CI: true
- name: Upload Test Coverage
uses: actions/upload-artifact@v1 #artifactをアップロードするアクション
with:
name: code-coverage #ダウンロード時の表示名
path: coverage #アップロードするフォルダのパス
- name: Build Project
if: github.event_name == 'push'
run: npm run build
- name: Upload Build Coverage
if: github.event_name == 'push'
uses: actions/upload-artifact@v1
with:
name: build
path: build
ワークフローを実行すると以下のようにArtifactがアップロードされます。
##masterにマージされたときだけ実行するステップ
ワークフロー④(プルリクが承認されてdevelopがmasterへマージされたとき)のときだけ実行されるステップを作成します。
###リリースの作成
masterにマージされたときにリリースを作成するステップを追加します。
リリースの作成にはsemantic-releaseを使います。
- name: Create a Release
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
run: npx semanic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
また、リリースの画面からbuild.zip, coverage.zipをダウンロードできるようにします。
- name: ZIP Assets
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
run: |
zip -r build.zip ./build
zip -r coverage.zip ./coverage
リリースの設定は以下のようになります。
module.exports = {
branches: "master",
repositoryUrl: "https://github.com/suzuki0430/react-app",
plugins: [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
[
"@semantic-release/github",
{
assets: [
{path: "build.zip", label: "Build"},
{path: "coverage.zip", label: "Coverage"},
],
},
],
],
};
###codecovへのテストカバレッジのアップロード
codecovはコードのカバレッジを計測し、可視化したりslackに通知したりできる外部サービスです。
envでcodecovで作成したTOKENを指定するだけで、カバレッジレポートをアップロードすることができます。
- name: Upload Coverage Reports
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
run: npx code-coverage
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
##Slack通知用のワークフローの作成
リリースが作成されたときにSlack通知を行うワークフローを作成します。
ci.yml
のCreate releaseステップをトリガにするため、CUSTOM_TOKENを新しくつくります。
リリースの作成(published)をトリガにしたワークフローを以下のように作成します。
name: Notify on Release
on:
release:
types: [published]
jobs:
slack-message:
runs-on: ubuntu-latest
steps:
- name: Slack Message
run: |
curl -X POST -H 'Content-type: application/json' --data '{"text":"New release ${{ github.event.release.tag_name }} is out, <${{ github.event.release.html_url }}|check it out now.>"}' ${{ secrets.SLACK_WEBHOOK }}
#おわりに
GitHub Actionsの使い方が大体わかったので、今度は社内業務で役に立つようなワークフローを作成してみたいと思います。
#参考資料