CHANGELOGをCIで自動化をする

CHANGELOG.mdの自動化するには、standard-versionが指定する特定のprefixがついたcommitコメントでpushし、CI上でstandard-versionがprefixを収集して、CHANGELOG.md変更・package.jsonのversion更新・git-tagを作成し、それらをまとめてpushします。
特定のprefixを準拠するためにcommitLintが便利で、lintをgitコマンド時に実行するにはhuskyのhookが必要です。
細かいcommitを無視するのであれば、commitLintは使わずにレビュー後のmerge Commentで特定のprefixをつけるようにすると良い???

サンプルチェンジログ
https://github.com/shiba328/npm-study-hello-world/blob/master/CHANGELOG.md


# 基本情報
**プログラム**

- [standard-version](https://github.com/conventional-changelog/standard-version) CHANGELOG.md変更・package.jsonのversion更新・git-tagを作成
- [commitlint](https://github.com/conventional-changelog/commitlint) 特定のprefixに準拠させる
- [husky](https://www.npmjs.com/package/husky) gitコマンドのhook
 
**情報**

- [セマンティック バージョニング 2.0.0](https://semver.org/lang/ja/)
- [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/)

**参照**

- [standard-version と commitlint で npm パッケージのリリース管理を省力化する](https://numb86-tech.hatenablog.com/entry/2019/07/12/212053)

**prefix**

v1.0.3 (MAJOR.MINOR.PATCH)

|バージョン | prefix |
|:-- |:-- |
|PATCH | fix:|
|MINOR | feat: |
| | BREAKING CHANGE: |
| | build:, chore:, ci:, docs:, style:, refactor:, perf:, test: |


## 導入
git repositoryを作成

```
git init
touch README.md     
git add README.md 
git commit -m "docs: readme.md"
git status
```

`npm inti`で新しいパッケージのを作成

```
npm inti
# package name: (deploy-to-auto-changelog) 
# version: (1.0.0) 
# description: 
# entry point: (index.js) 
# test command: jest
# git repository: 
# keywords: 
# author: 
# license: (ISC) 
```

### standard-versionの導入

```
$ npm add -D standard-version
```
``` js:package.json
{
 // :
  "scripts": {
    "release": "standard-version"
  },
// :
}
```
さっそく試してみるとpackage.jsonのversionがupし、up内容がtag付きでcommitされました。

```
npm run release
# package.json
# version: 1.0.0 → 1.0.1

git log --oneline
# (tag: v1.0.1) chore(release): 1.0.1
```

一旦commitを戻す

```
git reset --soft HEAD^
```


### commitlint とhuskyの導入
commitコメントを厳格にするため、commitlintとhuskyを追加します。

```
$ npm add -D @commitlint/{cli,config-conventional}
$ touch commitlint.config.js
```

``` js:commitlint.config.js
module.exports = {
  extends: ['@commitlint/config-conventional']
}
```

husyはgit commitにhookできる便利な子

v9 
```
npm add -D husky
npx husky init
```
v8→v9でコマンドが変わりました。

v8
```
npm add -D husky
npx husky install
npx husky add .husky/commit-msg "npx --no-install commitlint --edit $1"
```



`.husky`に`commit-msg`をつくりcommit messageにhookします。
ついでにtestを走らせる場合は

```
npx husky add .husky/pre-commit "npm run test"
```


```bash
# 失敗
git commit --allow-empty -m "update"
# 成功
git commit --allow-empty -m "fix: update"
```

**lintがきつい**
commitlint.config.jsにrulesの追加
https://commitlint.js.org/#/reference-rules?id=rules



# github action

masterReleaseのときだけ実行するように

```
name: Release

on:
  push:
    branches: [ master ]
  workflow_dispatch:
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Cache node modules
        uses: actions/cache@v1
        env:
          cache-name: cache-node-modules
        with:
          path: ~/.npm
          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-build-${{ env.cache-name }}-
            ${{ runner.os }}-build-
            ${{ runner.os }}-
      - name: Run a multi-line script
        run: |
          npm install
          npm run generator
          git config user.name github-actions
          git config user.email github-actions@github.com
          yarn release "-m \"changelog [skip ci]\""
          git push --follow-tags origin master
```

# CircleCI

```
$ mkdir .circleci
$ cd .circleci
$ touch config.yml
```

```yaml:.circleci/config.yml
  steps:
      # :
      - run: git config --global user.email "$GIT_AUTHOR_EMAIL"
      - run: git config --global user.name "$GIT_AUTHOR_NAME"
      - run: yarn release "-m \"changelog [skip ci]\"" # ciのスキップ
      - run: git push --follow-tags origin master # git-tagをpush
```

**CI上のstandard-versionがgit pushで切るよにCIをread/writeに切り替え**

- circle CIで自動作成された`ssh-key`は`read-only`なので、新しく`wirte/read`の`ssh-key`を追加する。
- 元keyはgithub branchとcircleCI両方から削除する

**参考**
[Circle CI で Github に write access 可能な Deploy key を設定する](https://qiita.com/boushi-bird@github/items/6b6eb1d1ed6f6d3341e4z)

**CIをskipする**
master branchを監視しているので`yarn release`でchangelogがmasterにpushされたときにCIが周り永久loopしちゃうので、`yarn release`は`[skip ci]`でCIを止める
https://circleci.com/docs/2.0/skip-build/

**git-tagをpushする**
standard-versionがpackage.jsonのVersion書き換えと一緒に、git-tagも追加してるので、それもpushする

## standard-versionの勘所
### conventionalcommitsに準拠
- fix: patchアップ `1.0.X`
- feat: minorアップ `1.X.0`

### [疑問]MajorUPはどうするの？
subjectのlintで弾かれるのでbody内で`BREAKING CHANGE:`や`feat!:`など破壊的な更新用のsnippetを利用する。
https://www.conventionalcommits.org/en/v1.0.0/#commit-message-with-description-and-breaking-change-footer