EAS Buildを実行していて、Distribution Certificate is not validated for non-interactive builds.が発生した時の解決までの道のり

# はじめに

GitHub ActionsでEAS Buildを実行するために、次のコマンドを実行した。

```shell
eas build --non-interactive --no-wait --platform=ios --profile=production-internal
```

そして次のエラーが発生した。

```shell
Run eas build --non-interactive --no-wait --platform=ios --profile=production-internal
★ eas-cli@3.4.1 is now available, please upgrade.
Proceeding with outdated version

- Linking to project @takagimeow/my-application
✔ Linked to project @takagimeow/my-application (​https://expo.dev/accounts/takagimeow/projects/my-application​)
✔ Using remote iOS credentials (Expo server)

Distribution Certificate is not validated for non-interactive builds.
Provisioning Profile has expired.
Failed to set up credentials.
    Error: Provisioning profile is not configured correctly. Please run this 
    command again in interactive mode.
Error: Process completed with exit code 1.
```

# eas-cliのバージョンを上げる

調べたところ、`eas-cli`のバージョンが古いことが原因とのコメントを見つけた。

https://forums.expo.dev/t/eas-failed-to-setup-credentials/58958

ワークフローファイルを確認すると、`eas-cli`のバージョンが`0.41.x`で固定になっていたので、最新の`3.4.x`に修正した。

```yaml
...
- name: 🚀 Setup EAS
    uses: expo/expo-github-action@v6
    with:
      eas-version: 3.4.x
      eas-cache: true
      token: ${{ secrets.EAS_TOKEN }}
    env:
      NODE_OPTIONS: --max-old-space-size=4096
...
```

# extra.eas.projectIdを設定

更新後、再度実行してみたところ、今度は別のエラーが発生した。

```shell
EAS project not configured.
    Error: Must configure EAS project by running 'eas init' before this 
    command can be run in non-interactive mode.
Error: Process completed with exit code 1.
```

同じようなエラーに遭遇している方が多く、次の投稿を見つけた。

>Hey Guys,
>I found a fix for this issue
>
>Just make sure you add this in your app.config.js
>
>extra: {
>eas: {
>projectId: <INSERT_YOUR_PROJECT_ID>
>},
>},
>
>This should resolve the issue. Not sure what caused this to be honest.
>
>Let me know should you need any more information.
>

https://github.com/expo/eas-cli/issues/1426#issuecomment-1274302840

まず`projectId`を取得するために、`eas init`をExpoプロジェクトのディレクトリ内で実行する。

```shell
% eas init
★ eas-cli@3.4.1 is now available.
To upgrade, run npm install -g eas-cli.
Proceeding with outdated version.

✔ Existing project found: @takagimeow/my-application (ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx). Link this project? … yes

Warning: Your project uses dynamic app configuration, and the EAS project ID can't automatically be added to it.
https://docs.expo.dev/workflow/configuration/#dynamic-configuration-with-appconfigjs

To complete the setup process, set "extra.eas.projectId" in your app.config.js or app.json:

{
  "expo": {
    "extra": {
      "eas": {
        "projectId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
      }
    }
  }
}

Error: Cannot automatically write to dynamic config at: app.config.js
```

そして、表示された内容をもとに、**app.config.js**にて`extra.eas.projectId`を追加した。

```js
export default ({ config }) => {
    return {
        // ...
        extra: {
            eas: {
                projectId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
            }
        }
    }
}
```

# Error: [ios.infoPlist]: withIosInfoPlistBaseMod: ENOENT: no such file or directoryが発生

すると、今度は次のエラーが発生した。

```shell
Update this package.json to use a subpath pattern like "./*".
    Error: [ios.infoPlist]: withIosInfoPlistBaseMod: ENOENT: no such file or 
    directory, open '/home/runner/work/monorepo/app
    s/my-application/secrets/production/GoogleService-Info.plist'
    Code: ENOENT
Error: Process completed with exit code 1.
```

今までは、`eas-build-pre-install`にて、EXPOのSecretsにて保存した内容を元に**GoogleService-Info.plist**を復元するという処理を行なっていたため、このような問題は起きなかった。

しかし、`eas-build-pre-install`が実行される前に、なぜか`app.config.js`の内容がGitHub Actions内で確認されるようになり、**app.config.js**にて設定してある`ios.googleServicesFile`に記述されたパスに該当のファイルが存在しないため、このようなエラーが出ている。(もちろんEAS Buildを使ってビルドを想定しているため、**GoogleService-Info.plist**はワークフロー実行時には存在しない。)

> However, in the iOS eas build, the GoogleService-Info.plist check is performed first, and I get Error: [ios.infoPlist]: withIosInfoPlistBaseMod: ENOENT: no such file or directory.

https://github.com/expo/eas-cli/issues/1317#issuecomment-1242981731

そこで、空の**GoogleService-Info.plist**を作成して認識してもらうようにした。

```yaml
- name: Create Empty Production GoogleService-Info.plist
    run: mkdir -p ./secrets/production && touch ./secrets/production/GoogleService-Info.plist
    working-directory: apps/${{ github.event.inputs.package }}
```

しかし、次のエラーが発生しました。

```shell
AssertionError: [ios.infoPlist]: withIosInfoPlistBaseMod: 
GoogleService-Info.plist is empty
Code: ERR_ASSERTION
```

なので、空のファイルを作成して誤魔化すのは断念した。

調べていくと、同じような問題に直面している人を見つけた。

> Facing this too on v3.3.2 for iOS only and my setup is very similar to OP's:
My pre-install hook creates the GoogleService-Info.plist file from an environment variable. I first came across this when setting up Expo Github Action since the CI environment doesn't have a GoogleService-Info.plist file present like my machine does. Might be worth noting that the file is in my .gitignore and .easignore.
>
> However, when uploading the file as a secret file to EAS , the build starts (and successfully builds my app) just fine, so I'll be using this as my workaround for now.

https://github.com/expo/eas-cli/issues/1317#issuecomment-1386701107

# GoogleService-Info.plistをGitHub Actionsでも復元するように設定

そこで、次のようにし**GoogleService-Info.plist**をシークレットファイルとしてEASにアップロードしてみた。

https://docs.expo.dev/build-reference/variables/#how-to-upload-a-secret-file-and-use-it-in-my-app-config

```shell
eas secret:create --scope project --name GOOGLE_SERVICES_FILE --type file --value ./secrets/production/GoogleService-Info.plist
```

そして、もう一度ワークフローを実行してみた。
しかし、アップロードしただけでは何も変わらず。おそらく`env.GOOGLE_SERVICES_FILE`を`ios.googleServicesFile`に設定すると通るのだろうが、あいにく環境ごとに使用する**GoogleServices-Info.plist**を切り替えているためこのまま設定することができない。

```js
...
return {
    ios: {
        googleServicesFile: process.env.GOOGLE_SERVICES_FILE,
        ...,
    },
}
...
```

これでは埒があかないので、GitHub ActionsのSecretsに対しても、エンコードした**GoogleService-Info.plist**をアップロードした。

```shell
base64 -i ./secrets/production/GoogleService-Info.plist > ./secrets/production/GoogleService-Info.txt
```

そして、ワークフローファイル内で復元するようにした。

```yaml
- name: Decode PRODUCTION_GOOGLE_SERVICE_INFO_PLIST
    run: mkdir -p ./secrets/production && echo ${{ secrets.PRODUCTION_GOOGLE_SERVICE_INFO_PLIST }} | base64 -d > ./secrets/production/GoogleService-Info.plist
    working-directory: apps/${{ github.event.inputs.package }}
```

上記の内容でワークフローを実行した結果、無事問題は解決した。

# おまけ

途中諦めかけて、ローカルで次のコマンドを実行した。

```shell
eas build --platform=ios --profile=production-internal
```

ローカルでは、もちろん**GoogleService-Info.plist**が存在するのでコマンドの実行に成功した。