Skip to content
README.md 3.19 KiB
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")
# 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.

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