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 CHANGELOG.md変更・package.jsonのversion更新・git-tagを作成
  • commitlint 特定のprefixに準拠させる
  • husky gitコマンドのhook

情報

参照

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
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
commitlint.config.js
module.exports = {
  extends: ['@commitlint/config-conventional']
}

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

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

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

npx husky add .husky/pre-commit "npm run test"
# 失敗
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 [email protected]
          yarn release "-m \"changelog [skip ci]\""
          git push --follow-tags origin master

CircleCI

$ mkdir .circleci
$ cd .circleci
$ touch config.yml
.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-keyread-onlyなので、新しくwirte/readssh-keyを追加する。
  • 元keyはgithub branchとcircleCI両方から削除する

参考
Circle CI で Github に write access 可能な Deploy key を設定する

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