CIでLerna publishするまで

絶対に忘れる自信があるので今のうちにメモっておく。

## Lerna is 何
- [Lerna]() はmonorepoを管理するためのツール
- Babelのように、単一レポジトリで複数のnpmパッケージを管理できる
- レポジトリ内パッケージ間の依存関係をsimlinkにより解決してくれる（勝手に `npm link` してくれるイメージ）

## やりたいこと

1. 開発者がmasterへコード修正commit(PRのmergeなど)
1. CIでテスト実行
1. 開発者がリリース意思表示
1. CIでリリース実行
  - `lerna publish` が実行されて、npmへpublish完了!

今回はCIサービスにはCircleCI(2.x)を選択。
特にCircleCIにこだわっているわけでもなく、workflow的な仕組みが備わっているCI Serviceであれば問題ないはず。WerckerCIとか。

## 準備

`lerna publish` は下記を逐次的に実行していく。

1. リリースバージョンの決定（デフォルトでは、質問に答えることでインタラクティブに決定される）
1. publishが必要なパッケージの選定
1. lerna.json, publish対象パッケージのpackage.jsonのversion番号を書き換えて `git commit`
1. 決定したバージョンで `git tag` 実行
1. 対象パッケージを `npm publish` 実行
1. `git push origin master --tags` 実行

lernaは、各個のコマンド呼び出しには`child_process.execSync` を叩いているだけなので、CIでも上記の個別コマンドが動くようになっていれば問題ない。

### GitHub deploy key
CircleCIからGitHubへ`git push`できるようにする必要がある。ここでは、Deploy key(SSH公開鍵認証)を使う。

下記コマンドで、パスフレーズ空の鍵ペアを生成。

```sh
ssh-keygen -t rsa -b 4096 -P "" -C "<GitHubのメアド>" -f ${HOME}/.ssh/gh_dep_rsa
```

秘密鍵(`~/.ssh/gh_dep_rsa`)をコピって、CircleCI設定画面の、Permissions -> SSH Permissions -> Add SSH keyから登録。


<img width="380" alt="Project_settings_-_Quramy_reg-suit_-_CircleCI.png" src="https://qiita-image-store.s3.amazonaws.com/0/8808/252c2075-dcb4-1b2c-c55a-4f580dd9e5a3.png">


公開鍵(`~/.ssh/gh_dep_rsa.pub`)をコピって、GitHubレポジトリの Setting -> Deploy keys -> Add deploy key に登録。"Allow write access" を忘れずに。


<img width="380" alt="Deploy_keys.png" src="https://qiita-image-store.s3.amazonaws.com/0/8808/48c8f899-20ea-a7ae-6569-f3e9d49d3e96.png">

<img width="380" alt="Deploy_keys_2.png" src="https://qiita-image-store.s3.amazonaws.com/0/8808/08def7e0-46ff-646e-6d53-650fa6eb7aa6.png">


fingerprintをコピっておいて、CircleCIの設定ファイルに追記.

```.circleci/config.yml
    steps:
      - add-ssh-keys:
          fingerprints:
            # 上記でコピったfingerprintをここに貼り付け 
            - "a1:a2:a3:a4:a5:a6:a7:a8:a1:a2:a3:a4:a5:a6:a7:a8"
```

### Git user config
地味に忘れがちなのがこれ。 package.jsonやらをcommitする際に必要になるので。


```.circleci/config.yml
    steps:
      - run:
          name: Setup git user
          command: |
            git config --global user.email "<メアド>"
            git config --global user.name "<ユーザー名>"
```

### NPM token
npmにpublishするために必要。

ローカルで、`npm adduser`を実行してnpmにログインしておいてから、

```txt:~/.npmrc
//registry.npmjs.org/:_authToken=xxxxxx-yyyyyy-wwwwww-zzzzzz
```

`_authToken=...` の値をコピー。

Build settings -> Environment Variables -> Add variableを選択して、コピーした値を `NPM_AUTH_TOKEN` という名前で保存しておく。
これで、環境変数としてnpmの認証トークンを取り出せるようになったので、この値を使ってCI側でログインするようにしておく。

```.circleci/config.yml
      - run:
          name: Login npm
          command: |
            echo "//registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN}" > ~/.npmrc
            npm whoami
```

なお、 `npm whoami` はログインの確認用。

## 実行

これで準備が整った。最後は`lerna publish`をstepに加えるだけだ。

```.circleci/config.yml
      - run:
          name: Publish
          command: |
            ./node_modules/.bin/lerna --cd-version="patch" --yes --registry="https://registry.npmjs.org/" publish
```

`--cd-version="patch"` と `--yes` でリリースバージョンが自動的に決定されるようにしておく。
`--registry` は [https://github.com/lerna/lerna/issues/896](https://github.com/lerna/lerna/issues/896) のworkaround。多分そのうち不要になるだろうけど、最初はコイツを忘れたお陰で、`npm whoami`が正常終了なのに、lernaから実行される `npm publish` でauth errorとなって悲しい思いをした。 


# 追記 (2019.03.21)

久々にドキュメント読み返していたら、 `--cd-version` の記載が消えていた。

```
lerna publish patch --yes
```

のように書くか、または、手元で `lerna version patch` などを実行後に、CI側で

```
lerna publish from-package --yes
```

を叩くと良さそう（CIまでは未検証）