Skip to main content

Centralized pre-commit configuration

PyPI version Code style: black PRs Welcome

Easily install and update centralized pre-commit hooks and their configuration files in decentralized repositories.

To be able to validate and automatically fix commits we're using git hooks.

We're also heavily relying on pre-commit, which is a framework for managing and maintaining multi-language pre-commit hooks. Please refer to the pre-commit documentation here.

Philosophy

In order to be able to install all the tools and linters in a single command with up to date centralized configurations, we're copying the configurations files of your tools (.pre-commit-config.yaml, isort.cfg, .flake8, .clang-format, ...) from an URL to your local git directory and we then install pre-commit.

Why not use only pre-commit by @asotile? Well, in his words:

pre-commit will not directly support mutability in configuration (this includes referencing a centralized repository). This causes lots of issues with repeatability and maintenance in general. This was an early design decision after seeing the pain caused at scale when a linter changes behaviour and suddenly every repository's master branch is broken.

So if you disagree and want decentralized repository with centralized lint configuration, you need a tool on top of pre-commit to shoot yourself in the foot anyway. Or more realistically to update your configuration files from a central repository from time to time.

More seriously, the alternative is to use all-repos to mass update a bunch of decentralized repositories with a decentralized configuration.

Installation

pip3 install centralized-pre-commit-conf

Usage

See pre-commit-conf --help for options.

Installing hooks

For example with this config.yaml in one of the appropriate search paths:

configuration_files:
  - ".pylintrc"
  - ".pre-commit-config.yaml"
repository: https://mycompany.net/lint-conf/
branch: master
update_gitignore: True
path: "pre-commit/static/"
gitignore_info_text:
  "# Configuration file added automatically by 'centralized-pre-commit-conf'"

pre-commit-conf would recover the defined configuration files from https://mycompany.net/lint-conf/master/pre-commit/static/ and update the .gitignore:

You can set the option system wide in /home/pierre/.config/pre-commit-conf/config.yaml.
✨ Successfully retrieved .pre-commit-config.yaml ✨
✨ Successfully retrieved .pylintrc               ✨
✨ Updated .gitignore successfully with {'.pre-commit-config.yaml', '.pylintrc'}. ✨
 🎉 2 configuration files recovered and pre-commit installed correctly. 🎉

Here would the content of the .gitignore:

# Configuration file added automatically by 'centralized-pre-commit-conf'
.pre-commit-config.yaml
.pylintrc

Ignoring tool cache files

Some tools write a cache to the work directory (mypy creates .mypy_cache/, pytest creates .pytest_cache/, ruff creates .ruff_cache/, ...). These caches can be added to the .gitignore automatically. cache_files maps a tool's configuration file to the cache entries it generates; when that configuration file is installed and update_gitignore is on, its cache entries are added to the .gitignore alongside the configuration file:

configuration_files:
  - "mypy.ini"
  - ".pre-commit-config.yaml"
update_gitignore: True
cache_files:
  "mypy.ini": [".mypy_cache/"]

resulting in:

# Configuration file added automatically by 'centralized-pre-commit-conf'
.mypy_cache/
.pre-commit-config.yaml
mypy.ini

The default configuration already maps mypy, pytest and ruff. Add your own tools by extending cache_files.

Then with the same configuration, using pre-commit-conf --branch hardcore-pylint-conf would try to recover the configuration files from https://mycompany.net/lint-conf/hardcore-pylint-conf/pre-commit/static/ instead.

You can set the option system wide in /home/pierre/.config/pre-commit-conf/config.yaml.
Found existing .pre-commit-config.yaml ⁉️  Use '-f' or '--replace-existing' to force erase.
Found existing .pylintrc               ⁉️  Use '-f' or '--replace-existing' to force erase.
All configuration files already existed.

Next commit supposing the .pre-commit-config.yaml is done correctly your modified files we be linted with the centralized configuration.

Private repositories (authentication)

If your configuration lives in a private repository, an unauthenticated request is redirected to a login page and the HTML of that page would be downloaded instead of your configuration file. pre-commit-conf detects that redirection and reports a failed download asking you to provide a token.

To authenticate, provide a token. The token is sent as the PRIVATE-TOKEN header on every request.

You do not need a broad token: pre-commit-conf only reads from the single repository that holds your centralized configuration, so grant the least privilege that works. On GitLab, prefer a Project Access Token created on that one configuration repository, with only the read_repository scope. A Group Access Token (if the configuration repository may move within a group) or a Personal Access Token also work, but a Personal Access Token can read every repository your account can access — if it leaks, everything leaks — so avoid it unless necessary.

On GitLab, set provider: gitlab. The read_repository scope authenticates against the Repository Files API, not the /-/raw/ web endpoint (which only accepts a browser session), so pre-commit-conf fetches each file through the API. Point repository at the project's web URL — the host and project path are enough, the API URL is built for you:

configuration_files:
  - ".pylintrc"
  - ".pre-commit-config.yaml"
repository: https://gitlab.mycompany.net/admin-sys/internal-pre-commit-conf
provider: gitlab
branch: master
path: ""

Then supply the token using one of the following (precedence: CLI > config > env var — a token set in a config file shadows the environment variable):

  1. Environment variable (recommended) — set it once, used on every run, never stored in a committed file:

    export PRE_COMMIT_CONF_TOKEN="glpat-xxxxxxxxxxxxxxxxxxxx"
    pre-commit-conf
    
  2. Config file — convenient but keep the file out of version control, it contains a secret:

    token: "glpat-xxxxxxxxxxxxxxxxxxxx"
    
  3. Command line — avoid for real tokens, it leaks into your shell history and the process list:

    pre-commit-conf --token "glpat-xxxxxxxxxxxxxxxxxxxx"
    

In CI, store the token as a masked/protected variable named PRE_COMMIT_CONF_TOKEN.

Setup is a one-time thing: configure the repository once and keep the token available (in your shell profile or CI secrets) so every run authenticates automatically. The only recurring task is renewing the token when it expires.

Development / contribution

pip3 install -e ".[test]"
pre-commit-conf
python3 -m pytest --cov centralized_pre_commit_conf

Pull requests are welcome :)

Metadata

Release files for centralized-pre-commit-conf 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for centralized-pre-commit-conf 0.7.0
File Size Uploaded Provenance
centralized_pre_commit_conf-0.7.0.tar.gz 16.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for centralized-pre-commit-conf 0.7.0
File Interpreter ABI Platform
centralized_pre_commit_conf-0.7.0-py3-none-any.whl Python 3 none any Details

Total release size: 35.1 kB

Release files / centralized_pre_commit_conf-0.7.0.tar.gz

Download URL centralized_pre_commit_conf-0.7.0.tar.gz
Size 16.6 kB
Tags Source
SHA-256 checksum
How to use checksums
1b3a331a50ef685e1525bd8d6ac61b24d872f750df5031d35c6a81c21138d2f3
BLAKE2b-256 checksum
How to use checksums
686d350ccd5e154d2fd9d649da3b880c9ce767b07ccd67a641abd8e486ec93b7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.15

Release files / centralized_pre_commit_conf-0.7.0-py3-none-any.whl

Download URL centralized_pre_commit_conf-0.7.0-py3-none-any.whl
Size 18.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f40ea7d9f66628426e0d34b6bb774f663ffbe5e0256f2688f2657af4ea17f4b7
BLAKE2b-256 checksum
How to use checksums
769541fc0d35b5489528dd4129d0d635b840624156625e96bec57f1a8c0de55c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.15

Security for centralized-pre-commit-conf 0.7.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page