はじめに
先日の記事で、ansible-lint コマンドの即時性を高めるには別途仕組みが必要な旨を書きました。今回は、自動化の仕組みとして pre-commit を使って仕込んでみます。
だいぶシンプルな設定に抑えています。
導入
venv への pre-commit のインストール
今回は素の vnev を利用します。ansible-lint はインストールされていない状態ではじめます。
$ pip list Package Version ---------- ------- pip 23.1 setuptools 53.0.0
venv に pre-commit をインストールします。
$ pip install pre-commit
この時点での pip list は以下のとおりです。
Package Version ------------ ------- cfgv 3.3.1 distlib 0.3.6 filelock 3.11.0 identify 2.5.22 nodeenv 1.7.0 pip 23.1 platformdirs 3.2.0 pre-commit 3.2.2 PyYAML 6.0 setuptools 53.0.0 virtualenv 20.21.0
リポジトリへの pre-commit のインストール
使いたいリポジトリで pre-commit install します。
$ pre-commit install pre-commit installed at .git/hooks/pre-commit
.git/hooks/pre-commit に処理が入ったのを確認します(おまけ)。venv 名が含まれています。
$ cat .git/hooks/pre-commit
#!/usr/bin/env bash
# File generated by pre-commit: https://pre-commit.com
# ID: 138fd403232d2ddd5efb44317e38bf03
# start templated
INSTALL_PYTHON=/home/sakana/ansible/venvlint/bin/python3
ARGS=(hook-impl --config=.pre-commit-config.yaml --hook-type=pre-commit)
# end templated
HERE="$(cd "$(dirname "$0")" && pwd)"
ARGS+=(--hook-dir "$HERE" -- "$@")
if [ -x "$INSTALL_PYTHON" ]; then
exec "$INSTALL_PYTHON" -mpre_commit "${ARGS[@]}"
elif command -v pre-commit > /dev/null; then
exec pre-commit "${ARGS[@]}"
else
echo '`pre-commit` not found. Did you forget to activate your virtualenv?' 1>&2
exit 1
fi
設定ファイルの作成
リポジトリトップに、以下の内容で .pre-commit-config.yaml を作成します。
--- repos: - repo: https://github.com/ansible-community/ansible-lint.git rev: v6.14.6 hooks: - id: ansible-lint files: \.(yaml|yml)$
rev は、ansible/ansible-lint リポジトリのタグ一覧から選択します。
例えば v6.14.6 であれば、こちらの .pre-commit-hooks.yaml が対応します。
単体で実行(動作確認)
とりあえず、commit 操作との連動(hook)の前に、pre-commit 単体の動作を確認します。エラーになるような Playbook を予め commit 済みです。
$ pre-commit run
[INFO] Initializing environment for https://github.com/ansible-community/ansible-lint.git.
[INFO] Initializing environment for https://github.com/ansible-community/ansible-lint.git:.,ansible-core>=2.13.3.
[INFO] Installing environment for https://github.com/ansible-community/ansible-lint.git.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
Ansible-lint.............................................................Failed
- hook id: ansible-lint
- exit code: 2
...(略)...
yaml[truthy]: Truthy value should be one of [false, true]
roles/called_include_role/vars/not_called_vars.yml:2
name[missing]: All tasks should be named.
roles/not_called_role/tasks/main.yml:2 Task/Handler: debug msg=Hello!
yaml[truthy]: Truthy value should be one of [false, true]
roles/not_called_role/vars/main.yml:2
Read documentation for instructions on how to ignore specific rule violations.
Rule Violation Summary
count tag profile rule associated tags
6 name[missing] basic idiom
6 yaml[truthy] basic formatting, yaml
Failed after min profile: 12 failure(s), 0 warning(s) on 19 files.
pre-commit 単体で、ansible-lint が実行できたことを確認できました。
ところで、作業用の venv には ansible-lint はインストールしていませんでしたが実行できました。ログの冒頭に Initializing environment あるように、もろもろインストールされたようです。ただし、作業用 venv の pip list は以下のままで、ansible-lint は含まれていません。なので別の場所で管理されているようですが、pre-commit 触り始めのためこのあたりの仕組みはまだよくわかっていないです・・。
$ pip list Package Version ------------ ------- cfgv 3.3.1 distlib 0.3.6 filelock 3.11.0 identify 2.5.22 nodeenv 1.7.0 pip 23.1 platformdirs 3.2.0 pre-commit 3.2.2 PyYAML 6.0 setuptools 53.0.0
なお、再度 pre-commit run を実行すると Initializing environment は表示されませんでした。
git commit で実行(本番)
本当にやりたいのはこちらです。git commit 実行時に ansible-lint を hoook する動作を確認します。
エラーありの状態で commit
せっかくなので一つ ansible-lint でエラーになる箇所を追加します。
タスク名に name 内がないというエラーが1箇所ある roles/not_called_role/tasks/main.yml というファイルの
--- - ansible.builtin.debug: msg: Hello!
に、FQCN じゃないというエラーを追加します。
--- - debug: msg: Hello!
いよいよ commit です。
$ git commit -am "not fqcn"s
Ansible-lint.............................................................Failed
- hook id: ansible-lint
- exit code: 2
...(略)...
fqcn[action-core]: Use FQCN for builtin module actions (debug).
roles/not_called_role/tasks/main.yml:2 Use `ansible.builtin.debug` or `ansible.legacy.debug` instead.
name[missing]: All tasks should be named.
roles/not_called_role/tasks/main.yml:2 Task/Handler: debug msg=Hello!
yaml[truthy]: Truthy value should be one of [false, true]
roles/not_called_role/vars/main.yml:2
Read documentation for instructions on how to ignore specific rule violations.
Rule Violation Summary
count tag profile rule associated tags
6 name[missing] basic idiom
6 yaml[truthy] basic formatting, yaml
1 fqcn[action-core] production formatting
Failed after min profile: 13 failure(s), 0 warning(s) on 18 files.
pre-commit run の実行のときには検出されなかった、roles/not_called_role/tasks/main.yml に対する fqcn[action-core] のエラーも検出されました。commit は完了していません。
commit しようとしたのファイル以外も検出される所もポイントでしょうか。
エラーなしの状態で commit
検出されていたファイルたちを修正して、commit します。
$ git commit -am fix
Ansible-lint.............................................................Passed
...(略)...
$ git log -1
commit 6fb43c55e85920f66b6cd668611ffa8565684269 (HEAD -> main)
Author: Your Name <you@example.com>
Date: Tue Apr 18 13:17:12 2023 +0000
fix
ansible-lint が pass し、無事に commit されました。
おわりに
開発者全員に ansible-lint を強制するには、リモートリポジトリ側の CI に組み込む方法がいいと思います。ただ、それだけだと CI の結果を待ってから「あ、しまった。lint で引っかかった」と気づいて fix linting のような commit をして再度 push することになります。できればこの手のものは、今回のような仕組みを利用するなどして、commit 前に解消するのもアリかなと思いました。
なお、今回ちょっとやりきれなかったこととしては、EE 内の ansible-lint を動かすことと、VS Code の git クライアント機能でコミットしたときの表示を見やすくすること、です。
参考記事
ありがとうございます!