# `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 = "") ``` Create a `hooks` directory to create the `pre-commit` setup: ```py load("@pre-commit//pre-commit:defs.bzl", "pre_commit") load("@pre-commit//pre-commit/hook:defs.bzl", "pre_commit_hook") # Locally defined hook pre_commit_hook( name = "commitlint", stages = ["@pre-commit//pre-commit/stage:commit-msg"], src = "@commitlint", 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. ## Usage 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