結局のところGitフックは
- どうやってチームメンバーと共有するの
- 誰がメンテすんの
あたりが最終的な課題になってくると思うのですが、
Python製のツールpre-commitでGitのpre-commit hookを楽々管理!!
こちらの記事で紹介されているpre-commitを弊チームでも導入したので補足記事を書きたいと思います。
なおあくまでも補足なのでまずは上記記事を一読されることをおすすめします。
環境
windows 10
python 3.7.2
pre-commit 1.16.1
ざっくり仕組み紹介
- リポジトリのルートで
pre-commit install
すると.git/hooksにpythonで書かれたpre-commitが生まれる - このpre-commitは同じくルートにある.pre-commit-config.yamlを参照し、記載されたプログラムを上から順に実行する
- 全てのプログラムが0を返せばコミットが実行される
というのが基本です。
その他おさえておきたい特徴はこのあたり。
-
pre-commit install
にオプションをつけることによってpre-commitのほか以下のフックを作成できる(公式ドキュメント)- pre-push
- prepare-commit-msg
- commit-msg
- ローカルに用意したプログラムだけでなくGitHubなどの公開リポジトリを利用できる
- 使用できる言語は以下の通り(公式ドキュメント)
- docker
- docker_image
- fail
- golang
- node
- python
- python_venv
- ruby
- rust
- swift
- pcre
- pygrep
- script
- system
プロジェクトと同じ言語で書けたら楽ですよね。
実演
さて、実際にpre-commitを使用してGitHubに置いた自作のPythonスクリプトをcommit-msgで動かしてみます。
公開リポジトリの準備
Pythonの場合ディレクトリ構成はこうなります。
パッケージングして.pre-commit-hooks.yamlを置けってことですね。
.
├── commit_msg(任意)
│ ├── __init__.py
│ └── issue_num.py(任意)
├── .pre-commit-hooks.yaml
├── setup.cfg
└── setup.py
まずはフックスクリプトの用意です。
今回はブランチ名からイシュー番号を拾ってコミットメッセージに付与するだけの簡単なものを作ります。
import sys
import io
import pathlib
import re
def main():
"""
return
1 ... Failed
0 ... Succeed
"""
isError = False
encoding = 'utf-8'
git_dir = commit_msg_file = pathlib.Path('./.git/')
# イシュー番号取得
head = pathlib.Path(git_dir/'HEAD').read_text(encoding)
issue_num_match = re.search(r'#\d{1,}', head)
# コミットメッセージ書き換え
if issue_num_match:
commit_msg_file = pathlib.Path(git_dir/'COMMIT_EDITMSG')
commit_msg = commit_msg_file.read_text(encoding)
commit_msg_file.write_text(f'{issue_num_match.group()} {commit_msg}', encoding)
else:
# これがないと出力が文字化けします
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding)
print('ブランチ名にイシュー番号が存在しません')
isError = True
return isError
if __name__ == '__main__':
sys.exit(main())
次にsetupを書きます。
from setuptools import setup
setup()
[metadata]
name = my_hooks
version = 1.0.0
description = hooks for Python tool "pre-commit".
[options]
packages = commit_msg
[options.entry_points]
console_scripts =
issue_num = commit_msg.issue_num:main
必要最低限なので好きに追加してください。
最後に.pre-commit-hooks.yamlです。
- id: issue_num
name: issue_num
description: Get issue number from branch name and add to commit message.
entry: issue_num
language: python
stages: [commit-msg]
id及びnameは自由ですが、entryには必ずsetupで書いたentry_pointsのそれを書いてください。
stagesはpre-commitとか他のフックが存在する際にどのフックで起動するかを指定できます。
詳しくはこちら。
ここまで出来たら最終コミットのハッシュ値をメモっておいてください。
GitHubで言うとここのやつ↓
タグでも結構です。
これで準備が整いました。
フックを適用したいリポジトリの設定
.
├── .git
│ ├── hooks
│ ┊ └── hoges
│ └── hoge
├── .pre-commit-config.yaml
├── hoge
┊
└── hoge
まずルートでターミナルを立ち上げて
pre-commit install -t commit-msg
します。
.git/hooks内にcommit-msgが作成されたことを確認してください。
あとは.pre-commit-config.yamlを書いたら完了です。
repos:
- repo: リポジトリのURL
rev: メモったハッシュ値 or タグ
hooks:
- id: issue_num(.pre-commit-hooks.yamlに登録したid)
成功例
この状態でコミットしてみましょう。
初回はインストールなりなんなり(ユーザー/.cache/pre-commit内にリポジトリごとの環境を構築するので)
で時間がかかりますが、2回目以降は大丈夫です。
自作のissue_num.pyをPassしたことが出力されています。
終わりに
参照しているのはGitHubなので直接共有する必要がなく、またプロジェクトと同じ言語で書いているので誰もがメンテナンス可能です(ここは賛否あると思いますが…)。
また公式が用意しているスクリプトも有用なものが多いので、併せて使えばよりレビューが楽になるでしょう。
良いフックスクリプトのご公開をお待ちしています。かしこ