はじめに
こんにちは、H×Hのセンリツ大好きエンジニアです。
自分で新規プロダクトを開発してみよう!となった際に、「CIを最初に作っておくと便利だから作ってみるか〜」という軽い気持ちで手を出してみました。
(思ったより苦戦しました。。。)
なので、同じ思いを抱いている方に少しでも楽をして欲しいので、記事に書きました!
フロントエンド(TypeScript)とバックエンド(Golang)のCIを作成したのですが、今回はフロントエンドについてです。バックエンドも記事を書いたら載せます。
GitHub Actionsとは?
こちらの記事が非常に分かりやすいので、詳しく知りたい方は参考にしてみて下さい!(他力本願寺)
【初心者向け】【入門】GitHub Actionsの書き方についてデバッグ設定、runs-onやcheckoutなどの仕組みや構造も含めて徹底解説
簡単に言うと、GitHub上でCI/CDが構築できるよ!と言うものです。
(今までは、CircleCIなどの外部サービスと連携させる必要がありましたが、必要なくなります。一つのサービスで完結できるのって素晴らしいですね!)
CIの内容
TypeScriptのCIでは、主に2点を行います。
- ESLintを用いた静的解析
- Dockleを用いた脆弱性検査
フロントエンドは、テストはしなくても良いかな(というか分からない。。。)ので今回は省きました。
実装
Github Actionsはリポジトリ直下の.github/workflows
にあるymlファイルに記述されたワークフローを元に実行されます。
公式リファレンス: GitHub Actions
なので、まずはリポジトリ直下に.github/workflows
ディレクトリを作成し、その中に今回使用するymlファイルを作成します。(名前はなんでも良いので、frontend_ci.yml
とかにしておきます。)
構成図は以下になります。
.
├── .github
│ └── workflows
│ └── frontend_ci.yml <- コレ!
└── frontend <- 中身はnpx create-next-appで生成される者たち
├── .eslintrc.json
├── .gitignore
├── .next
├── Dockerfile
├── README.md
├── next-env.d.ts
├── next.config.js
├── node_modules
├── package-lock.json
├── package.json
├── public
├── src
└── tsconfig.json
.
.
.
「自分はこのリポジトリではフロントエンドだけ開発するからリポジトリ直下に置くよ!」という方はこの後のymlファイルの作業ディレクトリを.
に変更して下さい。
そして、気になるymlファイルの中身ですが、以下のようにしました。
# ワークフローの名前
name: frontend_ci
# トリガーになる Github イベント
on:
pull_request:
branches:
- develop
# ルート直下の場合は不要
paths:
- "frontend/**"
# 無くても良い(手動実行したい人だけ残す)
workflow_dispatch:
# 環境変数を設定
env:
DOCKER_IMAGE_TAG: "frontend"
# デフォルトの作業ディレクトリ変更
# ルート直下の場合は不要
defaults:
run:
working-directory: frontend
# ジョブ定義
jobs:
# ジョブ名
frontend_lint_check:
runs-on: ubuntu-latest
strategy:
matrix:
# 使用するNode.jsのバージョンを定義
node-version: [20.10.0]
# GitHub Actionsの権限設定
permissions:
contents: read
pull-requests: write
steps:
# リポジトリからソースコードの取得
- name: Checkout Repository
uses: actions/checkout@v4
# Node.jsのセットアップ
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
# 利用したいNode.jsバージョンを指定
node-version: ${{ matrix.node-version }}
# npmのキャッシュを使用する設定
cache: "npm"
# ルート直下の場合は「./package-lock.json」に変更
cache-dependency-path: ./frontend/package-lock.json
# プロジェクトの依存関係をインストール
- name: Install Dependencies
run: npm ci
# ReviewdogをESLintで実行
- name: Run ESLint Reviewdog
uses: reviewdog/action-eslint@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
reporter: github-pr-review
eslint_flags: "src/**/*.{ts,tsx}"
# ルート直下の場合は不要
workdir: frontend/
frontend_build_check:
runs-on: ubuntu-latest
steps:
# リポジトリからソースコードの取得
- name: Checkout Repository
uses: actions/checkout@v4
# Dockerのコンテナイメージをビルド
- name: Docker Image Build
run: |
docker build -f Dockerfile -t ${{ env.DOCKER_IMAGE_TAG }} .
# Dockleで脆弱性検査を行う
- name: Run Dockle
uses: erzz/dockle-action@v1
with:
image: ${{ env.DOCKER_IMAGE_TAG }}
exit-code: 1
failure-threshold: fatal
ほとんどコメントアウトで記述しているので、割愛しながら説明していきます。
# トリガーになる Github イベント
on:
pull_request:
branches:
- develop
# ルート直下の場合は不要
paths:
- "frontend/**"
# 無くても良い(手動実行したい人だけ残す)
workflow_dispatch:
ここでは、GitHub Actionsを呼び出すトリガーを設定します。
今回は、以下のように設定しました。
- developブランチにPull Requestが作成された時に発火
- pathsでfrontendディレクトリの中身が編集されていれば実行するように変更
- 手動実行もしたいので
workflow_dispatch
をトリガーに追加
# 環境変数を設定
env:
DOCKER_IMAGE_TAG: "frontend"
今回は、Dockerを用いてフロントエンドとバックエンドを管理しており、脆弱性検査の時にDockerfileのイメージを指定するので、ここで環境変数に設定しています。
静的解析
# ジョブ定義
jobs:
# ジョブ名
frontend_lint_check:
runs-on: ubuntu-latest
strategy:
matrix:
# 使用するNode.jsのバージョンを定義
node-version: [20.10.0]
# GitHub Actionsの権限設定
permissions:
contents: read
pull-requests: write
jobs
では、実行するジョブを定義します。
そして、実行する内容を記述する前に必要な設定を記述します。
- ジョブの実行を行うOSの指定
- Node.jsバージョンの指定(変数に入れることで管理しやすくする)
- GitHub Actionsの権限設定
最後の権限設定に関してですが、これはESLintで指摘項目があった際にPull Requestのコメントに内容を送信してもらうためです。(直す箇所が特定できるのでめためた便利です)
steps:
# リポジトリからソースコードの取得
- name: Checkout Repository
uses: actions/checkout@v4
# Node.jsのセットアップ
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
# 利用したいNode.jsバージョンを指定
node-version: ${{ matrix.node-version }}
# npmのキャッシュを使用する設定
cache: "npm"
# ルート直下の場合は「./package-lock.json」に変更
cache-dependency-path: ./frontend/package-lock.json
ここでジョブの内容を記述します。
まずはソースコードを取得し、Node.jsのセットアップを行います。
今回はセットアップ時にnpmのキャッシュを使いたいので、package-lock.json
の場所を明記してあげます。
yarn
やpnpm
を使用している方はwithの中身を変更して下さい。
# ReviewdogをESLintで実行
- name: Run ESLint Reviewdog
uses: reviewdog/action-eslint@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
reporter: github-pr-review
eslint_flags: "src/**/*.{ts,tsx}"
# ルート直下の場合は不要
workdir: frontend/
reviewdogという便利ツールを使います。
このツールは、各種linterの検出結果をレビューコメントとして自動的に投稿してくれるツールです。
公式リファレンス:reviewdog/reviewdog
今回はこのreviewdogのESLintバージョンで実行します。
オプションでは、以下のことを行なっています。
-
github_token
でreviewdogに権限を付与 -
reporter
で投稿方法を設定- Pull Requestのレビューコメントに設定
-
eslint_flags
で静的解析するファイルを選択- srcフォルダ内にある全てのTypeSctiptファイルを対象
-
workdir
で作業ディレクトリ変更
このジョブを作成後、規則違反したソースコードをPull Requestにあげるとどうなるのか見てみましょう。
ちゃんと怒ってくれますね!(社会人になると怒ってくれる人が少なくなるのでbotに怒ってもらいましょう!)
脆弱性検査
次に、脆弱性検査のジョブです。
frontend_build_check:
runs-on: ubuntu-latest
steps:
# リポジトリからソースコードの取得
- name: Checkout Repository
uses: actions/checkout@v4
# Dockerのコンテナイメージをビルド
- name: Docker Image Build
run: |
docker build -f Dockerfile -t ${{ env.DOCKER_IMAGE_TAG }} .
# Dockleで脆弱性検査を行う
- name: Run Dockle
uses: erzz/dockle-action@v1
with:
image: ${{ env.DOCKER_IMAGE_TAG }}
exit-code: 1
failure-threshold: fatal
先ほど同様リポジトリからソースコードを取得した後、Dockerイメージをビルドしていきます。
自分はDockerを使っているのですが、Dockerを使っていない場合は分かりません。。。
最後に、脆弱性検査ツールのDockleを実行します。
今回は、指摘される警告レベルをfatalに設定しました。
実際に動かしてみましょう。
出力結果はbackendのものですが、実装は同じなので見てみます!
こちらも、きちんと怒ってくれました。(感動)
さいごに
CIをGitHub Actionsで構築してみました!(完全に理解した)
ただ、自分より完全理解した方がいらっしゃれば「もっとこうするといいよ!」などのアドバイスを頂けると幸いです。
ここまでご覧いただきありがとうございました!