Commit Message / Pull Request Titleを美しく保つ方法

初投稿なので変な点があったら気軽にご指摘ください。

# TL;DR

[commitlint](https://commitlint.js.org)と[Commitizen](https://github.com/commitizen/cz-cli)、[Semantic Pull Request](https://github.com/zeke/semantic-pull-requests)を用いて[Convential](https://www.conventionalcommits.org/ja/v1.0.0/)なメッセージを書こう。

# はじめに

皆さんはコミットメッセージを普段どのように書いているでしょうか？人には人それぞれのコミットメッセージの書き方があると思います。しかしコミットメッセージの書き方が人によってバラバラだと非常に見にくいものとなってしまいます。

そのための規約が[Conventional Commits](https://www.conventionalcommits.org/ja/v1.0.0/)です。

> Conventional Commitsの仕様は、コミットメッセージのための軽量の規約です。 明示的なコミット履歴を作成するための簡単なルールを提供します、この規則に従うことで自動化ツールの導入を簡単にします。 この規約はSemVerと組み合わせることで、コミットメッセージへ機能、修正、破壊的変更を入れることで、さらに詳細な説明を可能にします。

このようにConventional Commitsではコミットメッセージにいくつかの規約を設けます。これによってコミットメッセージが統一されるだけでなくいくつかの自動化ツールによってChangelogの記述やSemantic Versioningの運用を楽にすることができます。
Conventional Commitsの規約については今回は触れませんがそこまで難しく無い規約なのでぜひ[公式サイト](https://www.conventionalcommits.org/ja/v1.0.0/)を読んでください(日本語化されています)。

今回はそんなConventionalなコミットメッセージやプルリクエストにするためのいくつかのツールを紹介します。

# commitlint

[commitlint](https://commitlint.js.org)はコミットメッセージがConventional Commitsの規約に沿っているかを判断してくれるコミットメッセージLinterです。これを用いることによって規約に沿ったコミットメッセージを書き続けることができます。

## 導入方法

npmプロジェクトなら比較的簡単に導入することができます。
はじめにnpmプロジェクトの初期化とcommitlintパッケージのインストールを行います。

```shell:commitlintのインストール
# npmを用いますがyarnでも構いません
# また、すでにpackage.jsonがある場合はこの操作は不要です
npm init

# commitlintのCLIツールと設定ファイルをインストールします
npm install --save-dev @commitlint/cli @commitlint/config-conventional
```

次にcommitlintの設定ファイルである`commitlint.config.js`を作成します。

```javascript:commitlint.config.js
module.exports = {
  extends: ["@commitlint/config-conventional"],
};
```

これでCommitlint自体のインストールと設定は完了です。しかし、これだけではコミット時に自動的にLinterが動作しません。そのためGit hooksを簡単に設定できる[husky](https://www.npmjs.com/package/husky)をインストールします。

```shell:huskyのインストール
# huskyをインストールします
# 先にgit initをしておかないとhooksが作られないので注意が必要です
npm install --save-dev husky
```

`package.json`にhuskyの設定を記述します。

```json:package.json
{
  "husky": {
    "hooks": {
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
    }
  }
}
```

これでcommitlintの導入は完了です。コミットしようとすると自動的にcommitlintが走り、規約に反している場合はコミットが失敗します。

# GitHub ActionsによるCI

huskyによるcommitlintは`git commit --no-verify`で実は回避することができます。またlintがうまく動作しないこともありますのでGithub Actionsを用いてCI上でもcommitlintをしましょう。

まずはリポジトリルート下に`.github/workflows`をというディレクトリを作ります

```shell
mkdir -p .github/workflows
```

次に`lint.yml`を`.github/workflows`に作成し、設定を記述します。

```yaml:lint.yml
name: lint
on: [push, pull_request]

jobs:
  commitlint:
    runs-on: ubuntu-latest
    steps:
      # リポジトリをチェックアウトします
      - name: Checkout
        uses: actions/checkout@v2
      # Node.jsのセットアップを行います
      - name: Setup Node.js
        uses: actions/setup-node@v1
      # CI高速化のためにキャッシュを使用します
      - name: Fetch cache
        uses: actions/cache@v1
        with:
          path: ~/.cache/yarn
          key: ${{ runner.os }}-${{ github.ref }}-${{ hashFiles('**/yarn.lock') }}
          restore-keys: |
            ${{ runner.os }}-${{ github.ref }}-
            ${{ runner.os }}-
      # 依存関係をインストールします
      - name: Install dependencies
        run: npm ci
      # commitlintを行います
      - name: Commitlint
        run: npm run commitlint
```

`package.json`にnpm scriptを記述します。

```json:package.json
{
  "scripts": {
    "commitlint": "commitlint -f HEAD"
  }
}
```

これでGitHub Actionsの設定は完了です。pushすると自動的にcommitlintが走ります。

# Commitizen

[Commitizen](https://github.com/commitizen/cz-cli)はコミット時に専用のプロンプトが出現しそれによって規約に沿ったコミットメッセージを簡単に作成することができます。

## 導入方法

```shell
# Commitizenをインストールします
npm install --save-dev commitizen

# cz-conventional-changelogをインストールします
npm install --save-dev cz-conventional-changelog
```

`package.json`にcommitizenの設定とnpm scriptsの設定を記述します。

```json:package.json
{
  "scripts": {
    "cz": "git-cz"
  },
  "config": {
    "commitizen": {
      "path": "cz-conventional-changelog"
    }
  }
}
```

次にhuskyにCommitizenの設定を記述します。
**注意: これらの設定はMac/Linuxのみの設定です。Windowsでは機能しませんのでご注意ください。**

```json:package.json
{
  "husky": {
    "hooks": {
      "prepare-commit-msg": "exec < /dev/tty && git cz --hook || true"
    }
  }
}
```

これでCommitizenの導入は完了です。`npm run cz`で専用のプロンプトが立ち上がり、コミットすることができます。また、Mac/Linuxの場合は`git commit`でも専用のプロンプトが立ち上がります。

# Semantic Pull Requests

コミットメッセージだけでなくPull RequestのタイトルもConventionalにしましょう。
[Semantic Pull Requests](https://github.com/zeke/semantic-pull-requests)を用いるとPull RequestのタイトルにLintを書けることができます。

## 導入方法

[こちら](https://github.com/apps/semantic-pull-requests)からGitHub Appをインストールできます。

また、`.github/semantic.yml`で設定をすることができます。
詳しい設定は[公式README](https://github.com/zeke/semantic-pull-requests/blob/master/README.md)をご覧ください。