GitHub Actionsでprivateリポジトリのライブラリをflutter pub getする方法

# 導入

iPresenceでは社内で作ったFlutterのライブラリをGitHubのPrivateリポジトリで管理しています。  
プロジェクトで使う分には pubspec.yaml内でGitHubのリポジトリを指定して上げれば問題なく開発はできます。  

テスト駆動で開発を進めていく内にGitHub Actionsを導入してテスト周りの効率化を図りたくなってきました、  
ただ普通にGitHub Actions内で`flutter pub get` を実行しただけではprivateリポジトリのライブラリを取得しようとした際に  
Permissionエラーになってしまいテストを実行する前にActionが失敗してしまい、GitHub Actionsの導入を諦めるめかけていましたが、  
SSH keyを適切に設定しActions内で読み込ませることでprivateリポジトリのライブラリも問題なく取得できるようになりました。  

# SSH Keyの作成

まずはプロジェクトのリポジトリからライブラリのリポジトリへアクセスできるようにするためにSSH keyを作成します。  
SSH Keyの作成はいつもどおりの `ssh-keygen` コマンドでやっていきます

```bash
cd ~/.ssh
ssh-keygen -t rsa -b 4096 -C "{EMAIL}" -f FILENAME
```

`EMAIL`にはGitHubに登録しているメールアドレス(privateリポジトリにアクセス権限のあるもの)を   
`FILENAME`には作成するSSH Keyのファイル名を指定します。  

コマンドを実行すると `FILENAME` と `FILENAME.pub` というファイルができているはずです。  
`FILENAME`が秘密鍵、`FILENAME.pub`が公開鍵になっています。  

# GitHubへ鍵の設定  

作成したSSH KeyをそれぞれGitHubへ登録していきます。  

## 秘密鍵  

まず秘密鍵の登録です。  
秘密鍵はGitHub Actionsを実行するリポジトリに登録します。  

リポジトリの Setting → Security → Actions に移動します。
https://github.com/ユーザ名/リポジトリ/settings/secrets/actions  

![秘密鍵1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2846848/2cbdb48d-d653-8095-b81c-d19fba586225.png)



`New repository secret`のボタンをクリックすると秘密鍵の登録画面になります。  

![秘密鍵2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2846848/f745be31-3547-6951-b5d0-1355882c00c7.png)


NAME: 鍵の名前 兼 Actions内の変数名
Secret: 事前に用意した秘密鍵

をそれぞれ入力して `Add secret` をクリックすると秘密鍵の登録は完了です。

## 公開鍵

次に公開鍵の登録です。 
公開鍵はアカウントの設定から登録していきます。  

アカウントの settings → SSH and GPG keys → New SSH Key でSSH Keyの登録画面まで移動します。
https://github.com/settings/ssh/new

![公開鍵.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2846848/333aa6f7-cd02-d153-fc79-284549dc87ad.png)


Title: 鍵のタイトルです、プロジェクト名などわかりやすものがおすすめです。
Key Type: Authentication Key を指定します。
Key: 事前に作成した公開鍵の内容

をそれぞれ入力して `Add SSH key` をクリックして公開鍵の登録をします。  

# GitHub Actionsの設定

プロジェクトのディレクトリ内に `.github/workflows/test.yaml` というテストを実行するActionsのファイルを用意します。  
ファイルの中身は以下のようになります。

```yaml
name: test
on:
  - pull_request
permissions:
  contents: read
  id-token: write
jobs:
  test: 
    name: flutter test
    runs-on: ubuntu-latest
    steps:
      - name: set up repository
        uses: actions/checkout@v2
      - name: Install Chrome
        run: |
          sudo wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
          sudo apt update
          sudo apt-get install google-chrome-stable
      - name: set up java
        uses: actions/setup-java@v1
        with:
          java-version: "12.x"
      - uses: subosito/flutter-action@v1
        with:
          flutter-version: "3.3.2"
      - name: flutter doctor
        run: flutter doctor -v
      - name: flutter pub get
        env: 
          ENV_SECRET_KEY: ${{ secrets.SECRET_KEY }}
        run:
          mkdir -p ~/.ssh;
          echo "$ENV_SECRET_KEY" | tr -d '\r' > ~/.ssh/secret_key;
          chmod 700 ~/.ssh/secret_key;
          eval $(ssh-agent -s);
          ssh-add ~/.ssh/secret_key;
          ssh-keyscan -H github.com >> ~/.ssh/known_hosts;
          export GIT_SSH_COMMAND="ssh -i $HOME/.ssh/secret_key";
          flutter pub get;
      - name: flutter unit test
        run: flutter test  
```

この中で今回重要になるのが`flutter pub get` をしている以下の箇所です

```yaml
      - name: flutter pub get
        env: 
          ENV_SECRET_KEY: ${{ secrets.SECRET_KEY }}
        run:
          mkdir -p ~/.ssh;
          echo "$ENV_SECRET_KEY" | tr -d '\r' > ~/.ssh/secret_key;
          chmod 700 ~/.ssh/secret_key;
          eval $(ssh-agent -s);
          ssh-add ~/.ssh/secret_key;
          ssh-keyscan -H github.com >> ~/.ssh/known_hosts;
          export GIT_SSH_COMMAND="ssh -i $HOME/.ssh/secret_key";
          flutter pub get;
```

まず `env` の項目でリポジトリに指定した秘密鍵を環境変数として読み込めるようにします。  
`ENV_SECRET_KEY`がActions内で使用できるようになる環境変数  
 `secrets.SECRET_KEY` の `SECRET_KEY` 部分が秘密鍵を登録した際に入力したNAMEになります。  

```yaml
        env: 
          ENV_SECRET_KEY: ${{ secrets.SECRET_KEY }}
```

環境変数として使えるようにできれば後は｀run` 内でbash上でSSH Keyを使用するときと同じようにssh-agentに登録していくだけです。  

```yaml
        run:
          mkdir -p ~/.ssh; # 鍵を置くディレクトリの作成
          echo "$ENV_SECRET_KEY" | tr -d '\r' > ~/.ssh/secret_key; # 用意したディレクトリに秘密鍵のファイルを作成
          chmod 700 ~/.ssh/secret_key; # 秘密鍵の権限を変更
          eval $(ssh-agent -s); # ssh-agentの起動
          ssh-add ~/.ssh/secret_key; # ssh-agentへ秘密鍵を追加 
          ssh-keyscan -H github.com >> ~/.ssh/known_hosts; # ホスト鍵登録のknown_hostsファイルを作成
          export GIT_SSH_COMMAND="ssh -i $HOME/.ssh/secret_key"; # gitコマンド実行時に使用する鍵を秘密鍵に指定
          flutter pub get; # Flutterのライブラリ取得です。
```

# pubspec.ymlの編集

ライブラリの取得先をhttpsを使っている場合は取得先をsshを使いようにします。  

```yaml: pubspec.yml
~ 前略 ~
dependencies:
  flutter:
    sdk: flutter
  private_repo_lib:
    git:
      # url: https://github.com/hogefuga/private_repo_lib.git
      url: git@github.com:hogefuga/private_repo_lib.git
      ref: 1.0.0
```


# 最後に
以上のようにしてGitHub Actions内からでもprivateリポジトリのライブラリを取得できるようになりました。  
実際この問題にハマってネット上にも知見が転がってなかったので数ヶ月Actionsの導入を諦めていましたが、ようやく使えるようになりました。  
同じようにGitHubActionsで`flutter pub get`ができずに諦めている人の解決に繋がれば幸いです。