Newer
Older
# `pre-commit`
> A module to integrate between Bazel and the `pre-commit` framework
[pre-commit] is great, it can manage `git` hooks with a lovely interface.
It maintains a cache of various language toolchains.
Bazel also manages a cache of various language toolchains.
This project provides Bazel rules to leverage the Bazel caching mechanism with `pre-commit`.
Hooks can be easily shared between Bazel projects.
Caching of the hooks can be shared with a Bazel remote cache.
Hooks use `language: system` to call into Bazel when a hook is executed.
The project uses a `@pre-commit` binary that includes a hermetic `git` and `bazel`.
## Getting Started
Add the following to `MODULE.bazel`:
```py
bazel_dep("pre-commit", version = "<version>")
```
Create a `hooks` directory to create the `pre-commit` setup:
load("@pre-commit//pre-commit:defs.bzl", "pre_commit")
load("@pre-commit//pre-commit/hook:defs.bzl", "pre_commit_hook")
pre_commit_hook(
name = "commitlint",
stages = ["@pre-commit//pre-commit/stage:commit-msg"],
summary = "Validate commit message",
description = "Runs `commitlint` against each commit message to validate it conforms.",
pre_commit(
name = "hooks",
# Use externally defined collection of hooks that provides `pre_commit_hooks` rule
srcs = [":commitlint", "@pre-commit-hooks"],
Generate the `hooks/.pre-commit-config.yaml` file with `bazel run hooks:config`.
Add a `pre-commit` configuration in `.bazelrc`:
```
# Disable Bazel output for `pre-commit` hooks
common:pre-commit --ui_event_filters=-info,-stdout,-stderr
common:pre-commit --noshow_progress
This project uses the `pre_commit` macro, see the [hooks](hooks/BUILD.bazel) for example usage.
## Creating hooks
Hooks can be created with the `pre_commit_hook` macro.
By default, the hook defaults to the `run` Bazel command.
An executable target must be provided via the `src` attribute.
The executable target _must_ accept multiple file paths as each hook runs serially to avoid locking contention on the Bazel server.
If an upstream tool does not support multiple file paths, create a Bazel executable wrapper that does and provide that to the `src` attribute.
See [//pre-commit/hook/check-newline-at-end-of-file](pre-commit/hook/check-newline-at-end-of-file/BUILD.bazel) for an example of a single hook.
## Sharing hooks
Multiple hooks can be bundled together with `pre_commit_hooks`.
Setting the visibility of that target to `//visibility:public` will allow downstream users to include the target in `pre_commit_config#srcs`.
See [//pre-commit/hook/buildifier](pre-commit/hook/buildifier/BUILD.bazel) for an example of bundled hooks, albeit without public visibility.
Install the hooks with `bazel run hooks:install`.
Run the hooks with `bazel run hooks:run`.
## Hermeticity
The project uses `rules_python` which is hermetic when `--@rules_python//python/config_settings:bootstrap_impl` is set to `script`.
Otherwise, the operation of `pre-commit` is hermetic using a hermetic `git` and `bazelisk` implementation to run the hooks.
The hermeticity of each individual hook is not controlled by this project.
[pre-commit]: https://pre-commit.com