pre-commit
is intentionally designed against centralized management because it makes it impossible to upgrade the centralized configuration without breaking lots of repositories. For example, we managed hundreds of repositories at yelp and when the systems team would upgrade flake8 a good percentages of them them would break!. At the core, pre-commit is designed for repeatability and per-repository customization. It provides a mechanism to make this way easier: pre-commit autoupdate
. You can also use a distributed refactoring tool such as all-repos (which has direct pre-commit
support) to make sweeping changes to the configuration (and have each individual repository tested in a repository).
That said, the design gives you quite a few escape hatches to allow unsupported pathways which could accomplish what you're looking for. The issue you linked in fact contains many of these solutions (it's where I've been trying to accumulate them!) -- I'll reiterate them here though.
using "pre-commit in pre-commit"
at the end of the day, pre-commit
is just a tool which calls executables, why can't that executable be pre-commit
? (it can)
layout
$ tree -I .git -a ../testrepo/
../testrepo/
├── .pre-commit-hooks.yaml
├── orghooks.yaml
└── run-org-hooks
0 directories, 3 files
.pre-commit-hooks.yaml
- id: org-hook
name: org-wide hooks
language: script
entry: ./run-org-hooks
verbose: true
verbose: true
forces the output to always appear whether or not things pass
./run-org-hooks
(mode: 0755
)
#!/usr/bin/env python
import os
import sys
HERE = os.path.dirname(os.path.realpath(__file__))
def main():
cfg = os.path.join(HERE, 'orghooks.yaml')
cmd = ['pre-commit', 'run', '--config', cfg, '--files'] + sys.argv[1:]
os.execvp(cmd[0], cmd)
if __name__ == '__main__':
exit(main())
Note here that we're using pre-commit's --config
option as a sort of "include". --files
is important here such that top-level pre-commit run --files ...
is honored.
orghooks.yaml
(basically any old .pre-commit-config.yaml
!)
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- repo: https://github.com/asottile/add-trailing-comma
rev: v1.5.0
hooks:
- id: add-trailing-comma
consuming repository
.pre-commit-config.yaml
(note, I'm using local paths and a sha here because I wanted to test the idea, in reality you'd put this in a clonable repository and use tags)
repos:
- repo: /tmp/wat/testrepo
rev: 2d76bfbfddde6129c4ec5db31ac08abfbe362114
hooks:
- id: org-hook
running
$ pre-commit run --all-files
org-wide hooks...........................................................Passed
hookid: org-hook
Trim Trailing Whitespace.................................................Passed
Fix End of Files.........................................................Passed
Add trailing commas......................................................Passed
$ pre-commit run --files README.md
org-wide hooks...........................................................Passed
hookid: org-hook
Trim Trailing Whitespace.................................................Passed
Fix End of Files.........................................................Passed
Add trailing commas..................................(no files to check)Skipped
$ SKIP=trailing-whitespace pre-commit run --files setup.py
org-wide hooks...........................................................Passed
hookid: org-hook
Trim Trailing Whitespace................................................Skipped
Fix End of Files.........................................................Passed
Add trailing commas......................................................Passed
symlinks
nothing currently requires that .pre-commit-config.yaml
is a regular file. You could make it be a symlink
Some ideas on how a symlink might accomplish this:
- conventionally cloned repository adjacent to working repositories (
.pre-commit-config -> ../convention/pre-commit-config.yaml
)
- configuration management managed file (
.pre-commit-config.yaml -> /etc/pre-commit/pre-commit-config.yaml
)
- submodule (
.pre-commit-config.yaml -> submodule/pre-commit-config.yaml
)
Don't use pre-commit install
and use your own shell script for .git/hooks/pre-commit
/ etc.
pre-commit install
is a convenience, but not necessary to work. it's ~essentially a wrapper around pre-commit run
, you could easily substitute that script for a shell script which calls pre-commit run --config /etc/pre-commit/pre-commit-config.yaml
.
disclaimers:
- I am the author of
pre-commit
- I am the author of
all-repos
require_serial: true
to the.pre-commit-hooks.yaml
otherwise the process would run multiple times in a row – Sr