React × Supabase × Vercel で TODO アプリを作ってみた ③ ～ GitHub Actions で CI/CD 編～ 🤖

## React × Supabase × Vercel シリーズ

ある程度、独立した内容になっていますが、ご興味あればどうぞ 💁‍♂️

- [① 作ってデプロイ編](https://qiita.com/kamata-bug-factory/items/363a4291fd31a8d34ead)
- [② Vitest で単体テスト編](https://qiita.com/kamata-bug-factory/items/e095d38e445e76210e8d)
- ③ GitHub Actions で CI/CD 編 ← 本記事

## はじめに

昨今のソフトウェア開発には、開発からデプロイまでのプロセスを自動化する **CI/CD (継続的インテグレーション / 継続的デリバリー)** が取り入れられていることが多いです。

よしやってみようということで、以下の React アプリを **Vitest でテストし、テストがパスしたら Vercel に自動デプロイする CI/CD パイプライン** を **GitHub Actions** で構築しました ✊

https://github.com/kamata-bug-factory/typescript-todo

:::note warn
GitHub Actions の利用は、
public リポジトリ：無料
private リポジトリ：プランに応じた無料枠 + 従量課金
となっています。

詳しくは以下を確認してください 🙇‍♂️
https://docs.github.com/ja/billing/managing-billing-for-your-products/managing-billing-for-github-actions/about-billing-for-github-actions
:::

## CI/CD とは

### CI (継続的インテグレーション)

リポジトリにコミットがあるたび、自動でビルドやテストが実行される仕組み

### CD (継続的デリバリー)

ビルドとテストが通ったら、自動でデプロイする仕組み

## 手順 🧑‍🏫

### 前提

- Vercel にデプロイされていること
- テストコードが書いてあること

### 1. Vercel と GitHub の連携を切る ✂️

デプロイは GitHub Actions に任せるので、Vercel と GitHub の連携を切ります。

このボタンをポチッと押すと

![github-disconnect.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/31e917d3-e3e1-485a-b5e7-021c3578db5a.png)

連携が切れます。

![スクリーンショット 2025-04-13 23.11.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/7f4e6187-997d-4028-8db4-c7313dd22341.png)

### 2. GitHub の Secrets に必要な環境変数を登録する 🤫

リポジトリの Settings タブの Secrets and Variables から `VERCEL_TOKEN`, `VERCEL_ORG_ID`, `VERCEL_PROJECT_ID` を登録します。

![env.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/83c60b87-476b-4094-8b07-4501952bf8b0.png)

#### `VERCEL_TOKEN`

Vercel の Account Settings に行って

![account-settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/be49360e-9271-4e2f-8582-eeb07a85105d.png)

Tokens から作成します。

![tokens.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/bfea067e-50d7-4dd2-9e7d-79778374a005.png)

↓ これが `VERCEL_TOKEN` です。

![vercel-token.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/e11b34f7-456f-475b-be36-937fb29ac4a9.png)

#### `VERCEL_ORG_ID`

Settings に行って

![project-settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/a20c1f60-7120-4bd2-b08b-d2bb95ee817c.png)

シュルシュルッと下に行くと Team ID という子がいます。これです。

![team-id.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/083eaea3-9d23-429a-93f4-1147348f382f.png)

#### `VERCEL_PROJECT_ID`

プロジェクトの

![project.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/729bf272-cce4-4ec1-aefd-3cb9ceeb2944.png)

Settings に行くと

![project-settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/bcfdb172-5019-448f-a565-b49afccbc3ce.png)

Project ID という子がいます。これです。

![project-id.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/a7f65743-577e-469d-ad3b-275872d72b60.png)

### 3. GitHub Actions の設定 🤖

ワークフローファイルを書きます。

今回は `main` ブランチに push されたらワークフローを実行しようと思います。

ルートに `.github/workflows` というディレクトリを作ると、その中の YAML ファイルがワークフローファイルと認識されます。

```yaml:.github/workflows/deploy.yml
name: Vitest and Deploy to Vercel

on:
  push:
    branches:
      - main

jobs:
  test-and-deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repo
        uses: actions/checkout@v3

      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: 22

      - name: Install dependencies
        run: |
          cd todo-app
          npm ci

      - name: Run Vitest
        run: npx vitest run

      - name: Deploy to Vercel
        if: success()
        run: |
          npx vercel --prod --token=$VERCEL_TOKEN
        env:
          VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
          VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
          VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
```

`VERCEL_ORG_ID`, `VERCEL_PROJECT_ID` は、コマンドで指定するのではなく、`vercel` コマンドを叩くときに勝手に参照されるっぽい？🤔
[公式の例](https://vercel.com/guides/how-can-i-use-github-actions-with-vercel) でも `env` にセットしてるだけ。

`vercel` コマンドの使い方はこの辺を見ました。

- https://vercel.com/docs/cli/deploy#prod
- https://vercel.com/docs/cli/global-options#token

## 動作確認

### 成功バージョン 😊

今、タイトル部分が赤字になっているので黒字に戻してみます。

![スクリーンショット 2025-04-14 0.46.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/3804bdc1-e930-451a-8811-ffa52f2096d7.png)

```html:src/pages/TodoHome/TodoHome.tsx
<h1>Todo</h1>
```

```diff_css:src/index.css
h1 {
  font-size: 2em;
- color: red;
}
```

リポジトリの Actions タブからワークフローを確認できます。

実行中のワークフローをポチッと押して詳細を見にいくと

![workflows.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/e80868aa-c756-4f64-9b3a-79609556cf35.png)

こんな感じで実行されています。

![スクリーンショット 2025-04-14 0.48.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/3dfdac4b-f5b1-464f-a80e-e1627a174cb6.png)

成功 🌟

![スクリーンショット 2025-04-14 0.48.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/ee2a1944-ba68-4077-b723-f4d6cbccd0cf.png)

黒字になりました ✌️

![スクリーンショット 2025-04-14 0.50.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/3d1fa82d-6a76-499c-a27c-ec3baaa650b8.png)

### 失敗バージョン 😢

`TodoUtil` をぶっこわーす 💥

```diff_typescript:todo-app/src/utils/TodoUtil.ts
export class TodoUtil {
  static filterTodoItems = (
    items: Todo[],
    keyword: string,
    showingDone: boolean
  ) => {
    return items?.filter((item) => {
      if (!showingDone && item.done) {
        return false;
      }
-     return item.text.includes(keyword);
+     return item.text;
    });
  };
}
```

ちゃんとテストでこけました。

![スクリーンショット 2025-04-14 1.01.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/4e0be7ce-3d01-4ee7-980b-1a099ae8e27f.png)

Vercel のデプロイ履歴を見るとデプロイされていないことがわかります 👌

↓ 最新のデプロイが 1 個前のコミット

![deploy-log.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/ea0e9b2b-78eb-45e5-81e1-0ccb7a35d480.png)

## おわりに

CI/CD 実装できました 🎊

実用的には lint やステージング環境へのデプロイなど組み込むべきものが色々とありますが、ひとまず目標達成！