Github Actionsでjobを分割したら「.firebase.json file not found.」エラー

## はじめに

こんにちは！[@nyakako13](https://qiita.com/nyakako13 "Qiita ページ") です。

Github Actionsを使い、firebaseに自動デプロイするworkflowで、jobを分けようとしたら困ったので対処法をまとめます。

## 開発環境
frontend: React(Javascript)←今回デプロイするアプリ
backend: supabase
hosting: firebase
CI/CD：Github Actions

## そもそもなんでjobを分けるの？
- 現時点ではbuild→deployのみですが、今後workflowにtestを導入します。
- build、test、deployという単位でjobを分けると例えばネットワーク不調などで**途中でエラーになった場合に、エラーが発生したjobから再実行できます。**（現状、step毎の再実行はできません。）
- jobを分けることでどこでエラーが出たのか、GithubのUI上でもわかりやすくなります。

https://docs.github.com/ja/actions/managing-workflow-runs/re-running-workflows-and-jobs

## jobを分ける前の.ymlファイル
ほぼfirebase initで自動作成してくれたものです。
supabase用の環境変数のみ、github secretsで設定した値を読み込むようにしていました。



```yaml:.github/workflows/firebase-hosting-merge.yml

# This file was auto-generated by the Firebase CLI
# https://github.com/firebase/firebase-tools

name: Deploy to Firebase Hosting on merge
on:
  push:
    branches:
      - main
jobs:
  build_and_deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm run build
        env:
          VITE_SUPABASE_URL: ${{secrets.SUPABASE_URL}}
          VITE_SUPABASE_ANON_KEY: ${{secrets.SUPABASE_ANON_KEY}}
      - uses: FirebaseExtended/action-hosting-deploy@v0
        with:
          repoToken: ${{ secrets.GITHUB_TOKEN }}
          firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_REACT_JS_STUDY_RECORD }}
          channelId: live
          projectId: react-js-study-record
        env:
          FIREBASE_CLI_EXPERIMENTS: webframeworks
```

ちゃんとデプロイできてます。

![スクリーンショット 2024-04-24 8.35.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2539365/aa22277e-64aa-1323-4693-a24d6f7d5a09.png)


## 問題
JOBを分割して再度workflowを動かしたところ、Deployのjobでエラー「.firebase.json file not found.」になりました

![スクリーンショット 2024-04-24 8.42.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2539365/2110b62e-b6b0-9702-f9ed-3dd1fc2f1c6b.png)

jobを分けると、どこでエラーが出たのかわかりやすいですね。

<br>

### 間違えていたymlファイル
```yaml:.github/workflows/firebase-hosting-merge.yml

# This file was auto-generated by the Firebase CLI
# https://github.com/firebase/firebase-tools


name: Deploy to Firebase Hosting on merge
on:
  push:
    branches:
      - main
jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Build
        run: npm ci && npm run build
        env:
          VITE_SUPABASE_URL: ${{secrets.SUPABASE_URL}}
          VITE_SUPABASE_ANON_KEY: ${{secrets.SUPABASE_ANON_KEY}}

  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Deploy to Firebase Hosting
        uses: FirebaseExtended/action-hosting-deploy@v0
        with:
          repoToken: ${{ secrets.GITHUB_TOKEN }}
          firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_REACT_JS_STUDY_RECORD }}
          channelId: live
          projectId: react-js-study-record
        env:
          FIREBASE_CLI_EXPERIMENTS: webframeworks
```




## 解決方法
deploy のjobで再度checkoutとbuildをし直すことで、解決しました。

### 成功したymlファイル
```yaml:.github/workflows/firebase-hosting-merge.yml
name: Deploy to Firebase Hosting on merge
on:
  push:
    branches:
      - main
jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Build
        run: npm ci && npm run build
        env:
          VITE_SUPABASE_URL: ${{secrets.SUPABASE_URL}}
          VITE_SUPABASE_ANON_KEY: ${{secrets.SUPABASE_ANON_KEY}}

  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Build
        run: npm ci && npm run build
        env:
          VITE_SUPABASE_URL: ${{secrets.SUPABASE_URL}}
          VITE_SUPABASE_ANON_KEY: ${{secrets.SUPABASE_ANON_KEY}}
      - name: Deploy to Firebase Hosting
        uses: FirebaseExtended/action-hosting-deploy@v0
        with:
          repoToken: ${{ secrets.GITHUB_TOKEN }}
          firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_REACT_JS_STUDY_RECORD }}
          channelId: live
          projectId: react-js-study-record
        env:
          FIREBASE_CLI_EXPERIMENTS: webframeworks
```

ちゃんと成功しています。

![スクリーンショット 2024-04-24 10.22.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2539365/44081175-0c42-70dd-dc5b-3bac8fb6e111.png)




## 原因
GitHub Actionsでは、**各job毎に専用の仮想マシン ランナー、またはコンテナー内で実行**されるようです。

https://docs.github.com/ja/actions/learn-github-actions/understanding-github-actions#github-actions-%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88

そのため、jobが変わると同じマシン環境を引き継げず、
job毎にgithubリポジトリのファイル（checkout）とbuildしたファイルが必要になります。


## アーティファクトを使う方法
なんか同じこと２回やるのは非効率な気がする・・・

どうにか2回checkoutとbuildをしなくて済む方法はないかな？と思い調べてみましたが、よくわかりませんでした。

GPT先生に聞いてみたらアーティファクトを使う方法を提案してくれました。


<details>
    <summary>ChatGPTの回答</summary>
    
`checkout`と`build`を2回行わずに済むようにするには、`build`ジョブでビルドされたアーティファクトを`deploy`ジョブに渡す方法があります。そのためには、GitHub Actionsのアーティファクトを使用してビルドされたファイルを保存し、`deploy`ジョブでそれらのファイルを取得する必要があります。

以下に、その方法を示します：

```yaml
name: Deploy to Firebase Hosting on merge
on:
  push:
    branches:
      - main
jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Build
        run: npm ci && npm run build
        env:
          VITE_SUPABASE_URL: ${{secrets.SUPABASE_URL}}
          VITE_SUPABASE_ANON_KEY: ${{secrets.SUPABASE_ANON_KEY}}
      - name: Archive build
        uses: actions/upload-artifact@v2
        with:
          name: build
          path: dist # ビルドされたファイルのディレクトリを指定

  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Download build artifact
        uses: actions/download-artifact@v2
        with:
          name: build
          path: dist # ビルドされたファイルのディレクトリを指定
      - name: Deploy to Firebase Hosting
        uses: FirebaseExtended/action-hosting-deploy@v0
        with:
          repoToken: ${{ secrets.GITHUB_TOKEN }}
          firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_REACT_JS_STUDY_RECORD }}
          channelId: live
          projectId: react-js-study-record
        env:
          FIREBASE_CLI_EXPERIMENTS: webframeworks
```

この方法では、`build`ジョブでビルドされたファイルをGitHub Actionsのアーティファクトとしてアーカイブし、`deploy`ジョブでそのアーティファクトをダウンロードして使用します。このようにすることで、`checkout`と`build`を2回行う必要がなくなります。
    
</details>

<br>

:::note 
GitHub Actionsのアーティファクトは、ジョブの実行結果や生成されたファイルを一時的に保存するための仕組みです。アーティファクトは、ビルドされたバイナリファイル、ログ、テスト結果、またはその他の生成物など、ジョブで生成された重要なファイルを保存し、後で参照できるようにします。
:::

公式ドキュメントのartifactの訳は"成果物"なんか。

https://docs.github.com/ja/actions/using-workflows/storing-workflow-data-as-artifacts

<br>

で、試してみたら逆に遅くなりましたw　（57s→1m2s）
![スクリーンショット 2024-04-24 10.21.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2539365/2345b698-d5bd-7be4-05ad-0e34a7ac1253.png)



<details>
    <summary>artifactを使ったymlファイル</summary>
    
```yaml:.github/workflows/firebase-hosting-merge.yml

name: Deploy to Firebase Hosting on merge
on:
  push:
    branches:
      - main
jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "18"
      - name: Build
        run: npm ci && npm run build
        env:
          VITE_SUPABASE_URL: ${{secrets.SUPABASE_URL}}
          VITE_SUPABASE_ANON_KEY: ${{secrets.SUPABASE_ANON_KEY}}
      - name: Archive build
        uses: actions/upload-artifact@v4
        with:
          name: build
          path: dist # ビルドされたファイルのディレクトリを指定

  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Download build artifact
        uses: actions/download-artifact@v4
        with:
          name: build
          path: dist # ビルドされたファイルのディレクトリを指定
      - name: Deploy to Firebase Hosting
        uses: FirebaseExtended/action-hosting-deploy@v0
        with:
          repoToken: ${{ secrets.GITHUB_TOKEN }}
          firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_REACT_JS_STUDY_RECORD }}
          channelId: live
          projectId: react-js-study-record
        env:
          FIREBASE_CLI_EXPERIMENTS: webframeworks
    
```
    
</details>

改めて考えると
1. checkout×２＋ci&build×2
2. checkout+ci&build+upload（artifact）+download（artifact）

の違いなので、ciとbuildでかなり時間がかからない限りは1の方が早いですね。



依存関係や、buildするリポジトリ内のファイルが増えると結果が変わるかもしれませんが、今回はアーティファクトを使わずに普通にjob毎にcheckoutとbuildをしようと思います！





## おわりに
よかったら[X(@nyakako13)](https://twitter.com/nyakako13 "Xプロフィール")もフォローしてもらえると嬉しいです。

[Qiita100投稿](https://qiita.com/nyakako13/items/03ad61cfb82a1582b5d1)まで残り94！

未経験や浅経験、厳しいと言われている年代でエンジニアへの転職活動されている方、負けずにがんばりましょう！！

## 参考
https://docs.github.com/ja/actions/learn-github-actions/understanding-github-actions#github-actions-%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88

https://docs.github.com/ja/actions/using-worAkflows/storing-workflow-data-as-artifacts

https://zenn.dev/hsaki/articles/github-actions-component