はじめに
先日の記事で、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 クライアント機能でコミットしたときの表示を見やすくすること、です。
参考記事
ありがとうございます!