diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 9408e44d..00000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,2 +0,0 @@ -github: asottile -open_collective: pre-commit diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 91ed3615..47422e09 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,18 +1,21 @@ -name: deploy on: pull_request: push: - branches: [master] + branches: [main] schedule: - cron: '30 8 * * *' +permissions: + contents: write + jobs: - build: - name: pr + pr: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - uses: actions/setup-python@v1 + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: 3.x - run: pip install virtualenv - run: make - run: make push diff --git a/.gitignore b/.gitignore index 2deee430..8658b840 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,4 @@ *.html *.pyc -*.swp -/.mypy_cache -/all-hooks.json /build /node_modules -/venv diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fa39c888..1f2f8c10 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,59 +1,42 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.0.1 + rev: v6.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - id: debug-statements -- repo: https://github.com/PyCQA/flake8 - rev: 3.9.2 - hooks: - - id: flake8 -- repo: https://github.com/pre-commit/mirrors-autopep8 - rev: v1.5.7 - hooks: - - id: autopep8 -- repo: https://github.com/asottile/reorder_python_imports - rev: v2.5.0 + - id: double-quote-string-fixer + - id: name-tests-test + - id: requirements-txt-fixer +- repo: https://github.com/asottile/reorder-python-imports + rev: v3.16.0 hooks: - id: reorder-python-imports - args: [--py36-plus] - exclude: ^install-local.py$ + args: [--py310-plus, --add-import, 'from __future__ import annotations'] - id: reorder-python-imports - files: install-local.py +- repo: https://github.com/asottile/add-trailing-comma + rev: v4.0.0 + hooks: + - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade - rev: v2.19.4 + rev: v3.21.2 hooks: - id: pyupgrade - args: [--py36-plus] - exclude: ^install-local.py$ - - id: pyupgrade - files: install-local.py -- repo: https://github.com/asottile/add-trailing-comma - rev: v2.1.0 + args: [--py310-plus] +- repo: https://github.com/hhatto/autopep8 + rev: v2.3.2 hooks: - - id: add-trailing-comma + - id: autopep8 +- repo: https://github.com/PyCQA/flake8 + rev: 7.3.0 + hooks: + - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.902 + rev: v2.1.0 hooks: - id: mypy - additional_dependencies: [types-all] -- repo: https://github.com/pre-commit/mirrors-eslint - rev: v7.28.0 - hooks: - - id: eslint - args: [--fix] -- repo: local - hooks: - - id: scss-lint - name: scss-lint - entry: scss-lint - types: [scss] - language: ruby - additional_dependencies: ['scss_lint:0.57.0'] - - id: no-github-dot-git - name: No need for .git for github/gitlab urls - entry: '(github|gitlab).*\.git' - files: all-repos.yaml - language: pygrep +- repo: https://github.com/biomejs/pre-commit + rev: v2.5.0 + hooks: + - id: biome-check diff --git a/Makefile b/Makefile index 13d63c35..81533eda 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -all: install-hooks build/main_bs5.css all-hooks.json index.html hooks.html +all: install-hooks build/main_bs5.css index.html hooks.html .PHONY: install-hooks install-hooks: venv @@ -7,10 +7,7 @@ install-hooks: venv build/main_bs5.css: node_modules build scss/main_bs5.scss scss/_variables.scss node_modules/.bin/sass --style=compressed --load-path=. scss/main_bs5.scss build/main_bs5.css -all-hooks.json: venv make_all_hooks.py all-repos.yaml - venv/bin/python make_all_hooks.py - -index.html hooks.html: venv all-hooks.json base.mako index.mako hooks.mako make_templates.py template_lib.py sections/*.md +index.html hooks.html: venv base.mako index.mako hooks.mako make_templates.py template_lib.py sections/*.md venv/bin/python make_templates.py venv: requirements-dev.txt Makefile @@ -28,11 +25,10 @@ node_modules: package.json push: venv venv/bin/markdown-to-presentation push \ .nojekyll README.md CNAME \ - build assets node_modules *.html *.png *.svg favicon.ico \ - all-hooks.json install-local.py + build assets *.html *.png *.svg favicon.ico clean: - rm -rf venv build node_modules *.html all-hooks.json + rm -rf venv build node_modules *.html build: mkdir -p build diff --git a/README.md b/README.md index 4942a13b..c311257b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ pre-commit.com ============== -[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/pre-commit/pre-commit.com/master.svg)](https://results.pre-commit.ci/latest/github/pre-commit/pre-commit.com/master) -[![Build Status](https://github.com/pre-commit/pre-commit.com/workflows/deploy/badge.svg)](https://github.com/pre-commit/pre-commit.com/actions) +[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/pre-commit/pre-commit.com/main.svg)](https://results.pre-commit.ci/latest/github/pre-commit/pre-commit.com/main) +[![Build Status](https://github.com/pre-commit/pre-commit.com/actions/workflows/deploy.yml/badge.svg)](https://github.com/pre-commit/pre-commit.com/actions) This powers https://pre-commit.com diff --git a/all-repos.yaml b/all-repos.yaml deleted file mode 100644 index be58a7f4..00000000 --- a/all-repos.yaml +++ /dev/null @@ -1,194 +0,0 @@ -# This file is used to generate all-hooks.json -- https://github.com/pre-commit/pre-commit-hooks -- https://github.com/pre-commit/mirrors-autopep8 -- https://github.com/pre-commit/mirrors-coffeelint -- https://github.com/pre-commit/mirrors-csslint -- https://github.com/pre-commit/mirrors-eslint -- https://github.com/pre-commit/mirrors-fixmyjs -- https://github.com/pre-commit/mirrors-jshint -- https://github.com/pre-commit/mirrors-mypy -- https://github.com/pre-commit/mirrors-prettier -- https://github.com/pre-commit/mirrors-puppet-lint -- https://github.com/pre-commit/mirrors-ruby-lint -- https://github.com/pre-commit/mirrors-scss-lint -- https://github.com/pre-commit/mirrors-yapf -- https://github.com/pre-commit/pygrep-hooks -- https://github.com/FalconSocial/pre-commit-mirrors-pep257 -- https://github.com/FalconSocial/pre-commit-python-sorter -- https://github.com/guykisel/pre-commit-robotframework-tidy -- https://github.com/guykisel/prospector-mirror -- https://github.com/asottile/add-trailing-comma -- https://github.com/asottile/pyupgrade -- https://github.com/asottile/reorder_python_imports -- https://github.com/asottile/yesqa -- https://github.com/asottile/blacken-docs -- https://github.com/asottile/dead -- https://github.com/asottile/setup-cfg-fmt -- https://github.com/asottile/cheetah_lint -- https://github.com/digitalpulp/pre-commit-php -- https://github.com/elidupuis/mirrors-jscs -- https://github.com/elidupuis/mirrors-sass-lint -- https://github.com/jumanjihouse/pre-commit-hooks -- https://github.com/jumanjihouse/pre-commit-hook-yamlfmt -- https://github.com/Lucas-C/pre-commit-hooks -- https://github.com/Lucas-C/pre-commit-hooks-go -- https://github.com/Lucas-C/pre-commit-hooks-java -- https://github.com/Lucas-C/pre-commit-hooks-lxml -- https://github.com/Lucas-C/pre-commit-hooks-markup -- https://github.com/Lucas-C/pre-commit-hooks-nodejs -- https://github.com/Lucas-C/pre-commit-hooks-safety -- https://github.com/chriskuehl/puppet-pre-commit-hooks -- https://github.com/golangci/golangci-lint -- https://github.com/Bahjat/pre-commit-golang -- https://github.com/dnephin/pre-commit-golang -- https://github.com/troian/pre-commit-golang -- https://github.com/jstewmon/check-swagger -- https://github.com/detailyang/pre-commit-shell -- https://github.com/lovesegfault/beautysh -- https://github.com/antonbabenko/pre-commit-terraform -- https://github.com/ansible-community/ansible-lint -- https://github.com/doublify/pre-commit-clang-format -- https://github.com/doublify/pre-commit-go -- https://github.com/doublify/pre-commit-hindent -- https://github.com/doublify/pre-commit-rust -- https://github.com/kintoandar/pre-commit -- https://github.com/awebdeveloper/pre-commit-stylelint -- https://github.com/awebdeveloper/pre-commit-tslint -- https://github.com/adrienverge/yamllint -- https://github.com/thlorenz/doctoc -- https://github.com/noahsark769/xcodeproj-sort-pre-commit-hook -- https://github.com/jorisroovers/gitlint -- https://github.com/psf/black -- https://github.com/IamTheFij/ansible-pre-commit -- https://github.com/IamTheFij/docker-pre-commit -- https://github.com/mattlqx/pre-commit-ruby -- https://github.com/mattlqx/pre-commit-sign -- https://github.com/mattlqx/pre-commit-search-and-replace -# - https://github.com/openstack-dev/bashate -- https://github.com/pryorda/dockerfilelint-precommit-hooks -- https://github.com/alessandrojcm/commitlint-pre-commit-hook -- https://github.com/henryykt/pre-commit-perl -- https://github.com/juancarlospaco/pre-commit-nim -- https://github.com/aws-cloudformation/cfn-python-lint -- https://github.com/thoughtworks/talisman -- https://github.com/PyCQA/flake8 -- https://github.com/PyCQA/bandit -- https://github.com/PyCQA/pydocstyle -- https://github.com/PyCQA/pylint -- https://github.com/PyCQA/doc8 -- https://github.com/PyCQA/prospector -- https://github.com/PyCQA/isort -- https://github.com/miki725/importanize -- https://github.com/motet-a/jinjalint -- https://github.com/milin/giticket -- https://github.com/milin/gitown -- https://github.com/sqlalchemyorg/zimports -- https://github.com/peterdemin/pip-compile-multi -- https://github.com/homebysix/pre-commit-macadmin -- https://github.com/fortman/pre-commit-prometheus -- https://github.com/syntaqx/git-hooks -- https://github.com/Calinou/pre-commit-luacheck -- https://github.com/belminf/pre-commit-chef -- https://github.com/pocc/pre-commit-hooks -- https://github.com/dwightgunning/pre-commit-nglint -- https://github.com/codespell-project/codespell -- https://gitlab.com/smop/pre-commit-hooks -- https://github.com/seddonym/import-linter -- https://github.com/marco-c/taskcluster_yml_validator -- https://github.com/myint/docformatter -- https://github.com/myint/rstcheck -- https://github.com/myint/autoflake -- https://github.com/lorenzwalthert/precommit -- https://github.com/FelixSeptem/pre-commit-golang -- https://gitlab.com/daverona/pre-commit/cpp -- https://github.com/codingjoe/relint -- https://github.com/nix-community/nixpkgs-fmt -- https://github.com/d6e/beancount-check -# - https://github.com/thg-consulting/inspectortiger -- https://gitlab.com/iamlikeme/nbhooks -- https://github.com/Vimjas/vint -- https://github.com/eschulte/lisp-format -- https://github.com/shellcheck-py/shellcheck-py -- https://github.com/APIDevTools/swagger-cli -- https://github.com/kynan/nbstripout -- https://gitlab.com/devopshq/gitlab-ci-linter -- https://github.com/bmorcos/pre-commit-hooks-cpp -- https://github.com/igorshubovych/markdownlint-cli -- https://github.com/TekWizely/pre-commit-golang -- https://github.com/markdownlint/markdownlint -- https://github.com/jguttman94/pre-commit-gradle -- https://github.com/Yelp/detect-secrets -- https://github.com/dmitri-lerko/pre-commit-docker-kustomize -- https://github.com/perltidy/perltidy -- https://github.com/talos-systems/conform -- https://github.com/twu/skjold -- https://github.com/commitizen-tools/commitizen -- https://github.com/gherynos/pre-commit-java -# - https://github.com/JamesWoolfenden/pre-commit -- https://github.com/lietu/go-pre-commit -- https://github.com/macisamuele/language-formatters-pre-commit-hooks -- https://github.com/jlebar/pre-commit-hooks -- https://github.com/jazzband/pip-tools -- https://github.com/pappasam/toml-sort -- https://github.com/arenadotio/pre-commit-ocamlformat -- https://github.com/hcodes/yaspeller -- https://github.com/maltzj/google-style-precommit-hook -- https://github.com/jvstein/pre-commit-dotnet-format -# - https://github.com/hakancelik96/unimport -- https://github.com/PeterMosmans/jenkinslint -- https://github.com/nicklockwood/SwiftFormat -- https://github.com/executablebooks/mdformat -- https://gitlab.com/daverona/pre-commit/php -- https://github.com/anderseknert/pre-commit-opa -- https://github.com/radix-ai/auto-smart-commit -- https://github.com/thibaudcolas/curlylint -- https://github.com/cheshirekow/cmake-format-precommit -- https://github.com/aorumbayev/pydantic-to-schema -- https://github.com/hadialqattan/pycln -- https://github.com/nbQA-dev/nbQA -- https://github.com/Scony/godot-gdscript-toolkit -- https://github.com/avilaton/add-msg-issue-prefix-hook -- https://github.com/dustinsand/pre-commit-jvm -- https://github.com/alan-turing-institute/CleverCSV-pre-commit -- https://gitlab.com/jvenom/elixir-pre-commit-hooks -- https://github.com/Cretezy/flutter-format-pre-commit -- https://github.com/dluksza/flutter-analyze-pre-commit -- https://github.com/fluttercommunity/import_sorter -- https://github.com/editorconfig-checker/editorconfig-checker.python -- https://gitlab.com/pablodiehl/pre-commit-lua-formatter -- https://github.com/frnmst/md-toc -- https://github.com/mgedmin/check-manifest -- https://github.com/ecugol/pre-commit-hooks-django -- https://github.com/PrincetonUniversity/blocklint -- https://github.com/sirosen/check-jsonschema -- https://github.com/sirosen/fix-smartquotes -- https://github.com/snok/pep585-upgrade -- https://github.com/jendrikseipp/vulture -- https://github.com/mwouts/jupytext -- https://github.com/ejba/pre-commit-maven -- https://github.com/terraform-linters/tflint -- https://github.com/tfsec/tfsec -- https://github.com/yoheimuta/protolint -- https://github.com/hadolint/hadolint -- https://github.com/google/go-jsonnet -- https://github.com/guid-empty/flutter-dependency-validation-pre-commit -- https://github.com/cpplint/cpplint -- https://github.com/MarcoGorelli/absolufy-imports -- https://github.com/domdfcoding/flake2lint -- https://github.com/dotnet/format -- https://github.com/ashwin153/pre-commit-vagrant -- https://github.com/AleksaC/hadolint-py -- https://github.com/AleksaC/circleci-cli-py -- https://github.com/AleksaC/mirrors-cfn-nag -- https://github.com/cmake-lint/cmake-lint -- https://github.com/priv-kweihmann/oelint-adv -- https://github.com/jggomez/pre-commit-android-kotlin -- https://github.com/Carreau/velin -- https://github.com/chrismgrayftsinc/jsonnetfmt -- https://github.com/zricethezav/gitleaks -- https://github.com/hugoh/pre-commit-fish -- https://github.com/redwarp/optimize-png-hooks -- https://github.com/nbyl/pre-commit-license-checks -- https://github.com/jonasbb/pre-commit-latex-hooks -- https://github.com/dfm/black_nbconvert -- https://github.com/crate-ci/typos diff --git a/assets/copyable.js b/assets/copyable.js index 8aba102f..7d18e25b 100644 --- a/assets/copyable.js +++ b/assets/copyable.js @@ -1,6 +1,8 @@ -(function () { +'use strict'; + +(() => { function copyTextToClipboard(text) { - var textArea = document.createElement('textarea'); + const textArea = document.createElement('textarea'); textArea.value = text; textArea.style.position = 'fixed'; textArea.style.left = '-1'; @@ -11,17 +13,15 @@ document.execCommand('copy'); document.body.removeChild(textArea); } - var codeBlockElements = document.getElementsByClassName('copyable'); - for (var i = 0; i < codeBlockElements.length; i++) { - var block = codeBlockElements[i]; - var copyIcon = new Image(16, 16); + for (const block of document.getElementsByClassName('copyable')) { + const copyIcon = new Image(16, 16); copyIcon.setAttribute('src', './assets/copy-icon.svg'); copyIcon.setAttribute('alt', 'copy'); copyIcon.setAttribute('title', 'copy to clipboard'); block.insertBefore(copyIcon, block.children[0]); - copyIcon.addEventListener('click', function(block) { - var text = block.getElementsByTagName('pre')[0].innerText; + copyIcon.addEventListener('click', () => { + const text = block.getElementsByTagName('pre')[0].innerText; copyTextToClipboard(text); - }.bind(null, block)); + }); } })(); diff --git a/assets/filter_repos.js b/assets/filter_repos.js deleted file mode 100644 index 718cb73d..00000000 --- a/assets/filter_repos.js +++ /dev/null @@ -1,41 +0,0 @@ -'use strict'; - -(() => { - const searchInput = document.getElementById('search-hook-id'); - const selectInput = document.getElementById('select-hook-type'); - - const hooks = document.getElementById('hooks'); - const repos = hooks.getElementsByTagName('ul'); - - const filterHooks = () => { - const id = searchInput.value.toLowerCase(); - const type = selectInput.value; - - for (let i = 0; i < repos.length; i += 1) { - const repo = repos[i]; - let hasVisibleHooks = false; - const repoHooks = repo.getElementsByTagName('li'); - - if (repoHooks) { - for (let j = 0; j < repoHooks.length; j += 1) { - const repoHook = repoHooks[j]; - const hookId = repoHook.dataset.id.toLowerCase(); - const hookTypes = repoHook.dataset.types.split(', '); - - if (hookId.includes(id) && (type === '' || hookTypes.includes(type))) { - repoHook.hidden = false; - hasVisibleHooks = true; - } else { - repoHook.hidden = true; - } - } - } - - repo.hidden = !hasVisibleHooks; - hooks.querySelector(`h3[data-repo="${repo.dataset.repo}"]`).hidden = !hasVisibleHooks; - } - }; - - searchInput.addEventListener('input', filterHooks); - selectInput.addEventListener('change', filterHooks); -})(); diff --git a/base.mako b/base.mako index 6ac25cb9..77ba61f4 100644 --- a/base.mako +++ b/base.mako @@ -54,27 +54,20 @@ A framework for managing and maintaining multi-language pre-commit hooks.

- - Build Status + + build status - - Azure DevOps Coverage - - - pre-commit.ci status + + pre-commit.ci status
## https://buttons.github.io/ Star - - ## https://developer.twitter.com/en/docs/twitter-for-websites/tweet-button/overview - Tweet -
- pre-commit logo + pre-commit logo @@ -88,7 +81,7 @@
 
- + +${body} diff --git a/install-local.py b/install-local.py deleted file mode 100644 index 925cf4bf..00000000 --- a/install-local.py +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env python -from __future__ import absolute_import -from __future__ import print_function -from __future__ import unicode_literals - -import contextlib -import distutils.spawn -import hashlib -import io -import os.path -import shutil -import subprocess -import sys -import tarfile - - -if str is bytes: - from urllib import urlopen # type: ignore -else: - from urllib.request import urlopen - -if False: - from typing import Generator - - -TGZ = ( - 'https://files.pythonhosted.org/packages/a4/e3/' - '1f067de470e3a86875ed915438dc3bd781fb0346254f541190a09472b677/' - 'virtualenv-16.7.10.tar.gz' -) -CHECKSUM = 'e88fdcb08b0ecb11da97868f463dd06275923f50d87f4b9c8b2fc0994eec40f4' -PKG_PATH = '/tmp/.virtualenv-pkg' - - -def clean(dirname): - # type: (str) -> None - if os.path.exists(dirname): - shutil.rmtree(dirname) - - -@contextlib.contextmanager -def clean_path(): - # type: (...) -> Generator[None, None, None] - try: - yield - finally: - clean(PKG_PATH) - - -def virtualenv(path): - # type: (str) -> int - clean(PKG_PATH) - clean(path) - - print('Downloading ' + TGZ) - tar_bytes = urlopen(TGZ).read() - checksum = hashlib.sha256(tar_bytes).hexdigest() - if checksum != CHECKSUM: - print( - 'Checksums did not match. ' - 'Got {}, expected {}.'.format(checksum, CHECKSUM), - file=sys.stderr, - ) - return 1 - - tar_stream = io.BytesIO(tar_bytes) - with contextlib.closing(tarfile.open(fileobj=tar_stream)) as tarfile_obj: - # Chop off the first path segment to avoid having the version in - # the path - for member in tarfile_obj.getmembers(): - _, _, member.name = member.name.partition('/') - if member.name: - tarfile_obj.extract(member, PKG_PATH) - print('Done.') - - with clean_path(): - return subprocess.call(( - sys.executable, os.path.join(PKG_PATH, 'virtualenv.py'), path, - )) - - -def main(): - # type: (...) -> int - venv_path = os.path.join(os.environ['HOME'], '.pre-commit-venv') - bin_dir = os.path.join(os.environ['HOME'], 'bin') - script_src = os.path.join(venv_path, 'bin', 'pre-commit') - script_dest = os.path.join(bin_dir, 'pre-commit') - - if sys.argv[1:] == ['uninstall']: - clean(PKG_PATH) - clean(venv_path) - if os.path.lexists(script_dest): - os.remove(script_dest) - print('Cleaned ~/.pre-commit-venv ~/bin/pre-commit') - return 0 - - if virtualenv(venv_path): - return 1 - - subprocess.check_call(( - os.path.join(venv_path, 'bin', 'pip'), 'install', 'pre-commit', - )) - - print('*' * 79) - print('Installing pre-commit to {}'.format(script_dest)) - print('*' * 79) - - if not os.path.exists(bin_dir): - os.mkdir(bin_dir) - - # os.symlink is not idempotent - if os.path.exists(script_dest): - os.remove(script_dest) - - os.symlink(script_src, script_dest) - - if not distutils.spawn.find_executable('pre-commit'): - print('It looks like {} is not on your path'.format(bin_dir)) - print('You may want to add it.') - print('Often this does the trick: source ~/.profile') - - return 0 - - -if __name__ == '__main__': - exit(main()) diff --git a/make_all_hooks.py b/make_all_hooks.py deleted file mode 100644 index 63106c20..00000000 --- a/make_all_hooks.py +++ /dev/null @@ -1,55 +0,0 @@ -import functools -import json -import multiprocessing -import os.path -import subprocess -import tempfile -from typing import Any -from typing import Dict -from typing import List -from typing import Tuple - -import yaml -from pre_commit.clientlib import load_manifest - -Loader = getattr(yaml, 'CSafeLoader', yaml.SafeLoader) -fast_load = functools.partial(yaml.load, Loader=Loader) - - -def get_manifest(repo_path: str) -> Tuple[bool, str, List[Dict[str, Any]]]: - print(f'*** {repo_path}') - with tempfile.TemporaryDirectory() as directory: - repo_dir = os.path.join(directory, 'repo') - cmd = ('git', 'clone', '--depth', '1', '-q', repo_path, repo_dir) - subprocess.check_call(cmd) - manifest_path = os.path.join(repo_dir, '.pre-commit-hooks.yaml') - # Validate the manifest just to make sure it's ok. - manifest = load_manifest(manifest_path) - # hooks should not set debugging `verbose: true` flag - for hook in manifest: - if hook['verbose']: - print(f'{repo_path} ({hook["id"]}) sets `verbose: true`') - return False, repo_path, [] - - with open(manifest_path) as f: - return True, repo_path, fast_load(f) - - -def main() -> int: - with open('all-repos.yaml') as f: - repos = fast_load(f) - - hooks_json = {} - with multiprocessing.Pool(4) as pool: - for ok, path, manifest in pool.map(get_manifest, repos): - if not ok: - return 1 - hooks_json[path] = manifest - - with open('all-hooks.json', 'w') as hooks_json_file: - json.dump(hooks_json, hooks_json_file, indent=4) - return 0 - - -if __name__ == '__main__': - exit(main()) diff --git a/make_templates.py b/make_templates.py index 8b592b1d..aca62aed 100644 --- a/make_templates.py +++ b/make_templates.py @@ -1,8 +1,6 @@ -import collections -import json +from __future__ import annotations + import os.path -from typing import Any -from typing import Dict import mako.lookup import markupsafe @@ -28,13 +26,7 @@ ) -ALL_TEMPLATES = [ - filename for filename in os.listdir('.') - if filename.endswith('.mako') and filename != 'base.mako' -] - - -def get_env() -> Dict[str, Any]: +def index_body() -> markupsafe.Markup: body_parts = [] for title, filename in SECTIONS: div_id, _ = os.path.splitext(os.path.basename(filename)) @@ -49,32 +41,24 @@ def get_env() -> Dict[str, Any]: f'\n', ), ) - body = markupsafe.Markup().join(body_parts) + return markupsafe.Markup().join(body_parts) - all_hooks = json.loads( - open('all-hooks.json').read(), - object_pairs_hook=collections.OrderedDict, - ) - all_types = { - hook_type - for properties in all_hooks.values() - for hook_type in ( - properties[0].get("types", []) + properties[0].get("types_or", []) - ) - } - return {'all_hooks': all_hooks, 'all_types': all_types, 'body': body} + +def hooks_body() -> markupsafe.Markup: + with open('sections/hooks.md') as f: + return md(f.read()) def main() -> int: - env = get_env() - for template in ALL_TEMPLATES: - template_name, _ = os.path.splitext(template) - env['template_name'] = template_name - with open(f'{template_name}.html', 'w') as html_file: - template_obj = template_lookup.get_template(template) - html_file.write(template_obj.render(**env)) + with open('index.html', 'w') as f: + tmpl = template_lookup.get_template('index.mako') + f.write(tmpl.render(body=index_body(), template_name='index')) + + with open('hooks.html', 'w') as f: + tmpl = template_lookup.get_template('hooks.mako') + f.write(tmpl.render(body=hooks_body(), template_name='hooks')) return 0 if __name__ == '__main__': - exit(main()) + raise SystemExit(main()) diff --git a/package.json b/package.json index a4bd6cb4..8a5f9f53 100644 --- a/package.json +++ b/package.json @@ -2,30 +2,7 @@ "repository": "github.com/pre-commit/pre-commit.com", "license": "MIT", "dependencies": { - "bootstrap": "^5.0.0", + "bootstrap": "5.0.2", "sass": "^1.32.13" - }, - "eslintConfig": { - "extends": "eslint:recommended", - "rules": { - "indent": [ - "error", - 4 - ], - "quotes": [ - "error", - "single" - ], - "semi": [ - "error", - "always" - ] - }, - "parserOptions": { - "ecmaVersion": 6 - }, - "env": { - "browser": true - } } } diff --git a/scss/_variables.scss b/scss/_variables.scss index f231a640..c4339549 100644 --- a/scss/_variables.scss +++ b/scss/_variables.scss @@ -23,3 +23,5 @@ $code-color: #e83e8c !default; $lead-font-size: 1.75rem !default; $lead-font-weight: 400 !default; + +$enable-smooth-scroll: false; diff --git a/sections/advanced.md b/sections/advanced.md index d2d8d804..646f2ac1 100644 --- a/sections/advanced.md +++ b/sections/advanced.md @@ -18,199 +18,205 @@ entire commit. $ SKIP=flake8 git commit -m "foo" ``` -## pre-commit during commits +## Confining hooks to run at certain stages + +pre-commit supports many different types of `git` hooks (not just +`pre-commit`!). + +Providers of hooks can select which git hooks they run on by setting the +[`stages`](#hooks-stages) property in `.pre-commit-hooks.yaml` -- this can +also be overridden by setting [`stages`](#config-stages) in +`.pre-commit-config.yaml`. If `stages` is not set in either of those places +the default value will be pulled from the top-level +[`default_stages`](#top_level-default_stages) option (which defaults to _all_ +stages). By default, tools are enabled for [every hook type](#supported-git-hooks) +that pre-commit supports. + +_new in 3.2.0_: The values of `stages` match the hook names. Previously, +`commit`, `push`, and `merge-commit` matched `pre-commit`, `pre-push`, and +`pre-merge-commit` respectively. -Running hooks on unstaged changes can lead to both false-positives and -false-negatives during committing. pre-commit only runs on the staged -contents of files by temporarily saving the contents of your files at commit -time and stashing the unstaged changes while running hooks. +The `manual` stage (via `stages: [manual]`) is a special stage which will not +be automatically triggered by any `git` hook -- this is useful if you want to +add a tool which is not automatically run, but is run on demand using +`pre-commit run --hook-stage manual [hookid]`. -_new in 2.4.0_: pre-commit can be used to manage [post-commit] hooks. +If you are authoring a tool, it is usually a good idea to provide an appropriate +`stages` property. For example a reasonable setting for a linter or code +formatter would be `stages: [pre-commit, pre-merge-commit, pre-push, manual]`. -To use `post-commit` hooks with pre-commit, run: +To install `pre-commit` for particular git hooks, pass `--hook-type` to +`pre-commit install`. This can be specified multiple times such as: ```console -$ pre-commit install --hook-type post-commit -pre-commit installed at .git/hooks/post-commit +$ pre-commit install --hook-type pre-commit --hook-type pre-push +pre-commit installed at .git/hooks/pre-commit +pre-commit installed at .git/hooks/pre-push ``` -`post-commit` hooks fire after the commit succeeds and cannot be used to -prevent the commit from happening (use `pre-commit` instead). Since -`post-commit` does not operate on files, any hooks must set `always_run`: +Additionally, one can specify a default set of git hook types to be installed +for by setting the top-level [`default_install_hook_types`](#top_level-default_install_hook_types). + +For example: ```yaml -- repo: local - hooks: - - id: post-commit-local - name: post commit - always_run: true - stages: [post-commit] - # ... +default_install_hook_types: [pre-commit, pre-push, commit-msg] ``` -[post-commit]: https://git-scm.com/docs/githooks#_post_commit +```console +$ pre-commit install +pre-commit installed at .git/hooks/pre-commit +pre-commit installed at .git/hooks/pre-push +pre-commit installed at .git/hooks/commit-msg +``` -## pre-commit during merges +[anchor](__#pre-commit-during-commits) +[anchor](__#pre-commit-during-merges) +[anchor](__#pre-commit-during-clean-merges) +[anchor](__#pre-commit-during-push) +[anchor](__#pre-commit-for-commit-messages) +[anchor](__#pre-commit-for-switching-branches) +[anchor](__#pre-commit-for-rewriting) -The biggest gripe we’ve had in the past with pre-commit hooks was during merge -conflict resolution. When working on very large projects a merge often -results in hundreds of committed files. I shouldn’t need to run hooks on all -of these files that I didn’t even touch! This often led to running commit -with `--no-verify` and allowed introduction of real bugs that hooks could have -caught. +## Supported git hooks -pre-commit solves this by only running hooks on files that conflict or were -manually edited during conflict resolution. This also includes files which -were automatically merged by git. Git isn't perfect and this can often catch -implicit conflicts (such as with removed python imports). +- [commit-msg](#commit-msg) +- [post-checkout](#post-checkout) +- [post-commit](#post-commit) +- [post-merge](#post-merge) +- [post-rewrite](#post-rewrite) +- [pre-commit](#pre-commit) +- [pre-merge-commit](#pre-merge-commit) +- [pre-push](#pre-push) +- [pre-rebase](#pre-rebase) +- [prepare-commit-msg](#prepare-commit-msg) -_new in 2.11.0_ pre-commit can be used to manage [post-merge] hooks. +### commit-msg -To use `post-merge` hooks with pre-commit, run: +[git commit-msg docs](https://git-scm.com/docs/githooks#_commit_msg) -```console -$ pre-commit install --hook-type post-merge -pre-commit installed at .git/hooks/post-merge -``` +`commit-msg` hooks will be passed a single filename -- this file contains the +current contents of the commit message to be validated. The commit will be +aborted if there is a nonzero exit code. -The hook fires after a successful `git merge`. +### post-checkout -[post-merge]: https://git-scm.com/docs/githooks#_post_merge +[git post-checkout docs](https://git-scm.com/docs/githooks#_post_checkout) -## pre-commit during clean merges +post-checkout hooks run *after* a `checkout` has occurred and can be used to +set up or manage state in the repository. -_new in 1.21.0_ pre-commit can be used to manage [pre-merge-commit] hooks. +`post-checkout` hooks do not operate on files so they must be set as +`always_run: true` or they will always be skipped. -To use `pre-merge-commit` hooks with pre-commit, run: +environment variables: +- `PRE_COMMIT_FROM_REF`: the first argument to the `post-checkout` git hook +- `PRE_COMMIT_TO_REF`: the second argument to the `post-checkout` git hook +- `PRE_COMMIT_CHECKOUT_TYPE`: the third argument to the `post-checkout` git hook -```console -$ pre-commit install --hook-type pre-merge-commit -pre-commit installed at .git/hooks/pre-merge-commit -``` +### post-commit -The hook fires after a merge succeeds but before the merge commit is created. +[git post-commit docs](https://git-scm.com/docs/githooks#_post_commit) -Note that you need to be using at least git 2.24 which added support for the -pre-merge-commit hook. +`post-commit` runs after the commit has already succeeded so it cannot be used +to prevent the commit from happening. -[pre-merge-commit]: https://git-scm.com/docs/githooks#_pre_merge_commit +`post-commit` hooks do not operate on files so they must be set as +`always_run: true` or they will always be skipped. -## pre-commit during push +### post-merge -To use `pre-push` hooks with pre-commit, run: +[git post-merge docs](https://git-scm.com/docs/githooks#_post_merge) -```console -$ pre-commit install --hook-type pre-push -pre-commit installed at .git/hooks/pre-push -``` +`post-merge` runs after a successful `git merge`. -During a push, pre-commit will export the following environment variables: -- `PRE_COMMIT_FROM_REF`: the remote revision that is being pushed to. - - _new in 2.2.0_ prior to 2.2.0 the variable was `PRE_COMMIT_SOURCE`. -- `PRE_COMMIT_TO_REF`: the local revision that is being pushed to the remote. - - _new in 2.2.0_ prior to 2.2.0 the variable was `PRE_COMMIT_ORIGIN`. -- `PRE_COMMIT_REMOTE_NAME`: _new in 2.0.0_ which remote is being pushed to - (for example `origin`) -- `PRE_COMMIT_REMOTE_URL`: _new in 2.0.0_ the url of the remote that is being - pushed to (for example `git@github.com:pre-commit/pre-commit`. +`post-merge` hooks do not operate on files so they must be set as +`always_run: true` or they will always be skipped. -[pre-push]: https://git-scm.com/docs/githooks#_pre_push +environment variables: +- `PRE_COMMIT_IS_SQUASH_MERGE`: the first argument to the `post-merge` git hook. -## pre-commit for commit messages +### post-rewrite -pre-commit can be used to manage [commit-msg] hooks. +[git post-rewrite docs](https://git-scm.com/docs/githooks#_post_rewrite) -To use `commit-msg` hooks with pre-commit, run: +`post-rewrite` runs after a git command which modifies history such as +`git commit --amend` or `git rebase`. -```console -$ pre-commit install --hook-type commit-msg -pre-commit installed at .git/hooks/commit-msg -``` +`post-rewrite` hooks do not operate on files so they must be set as +`always_run: true` or they will always be skipped. -`commit-msg` hooks can be configured by setting `stages: [commit-msg]`. -`commit-msg` hooks will be passed a single filename -- this file contains the -current contents of the commit message which can be validated. If a hook -exits nonzero, the commit will be aborted. +environment variables: +- `PRE_COMMIT_REWRITE_COMMAND`: the first argument to the `post-rewrite` git hook. -_new in 1.16.0_: pre-commit can be used to manage [prepare-commit-msg] hooks. +### pre-commit -To use `prepare-commit-msg` hooks with pre-commit, run: +[git pre-commit docs](https://git-scm.com/docs/githooks#_pre_commit) -```console -$ pre-commit install --hook-type prepare-commit-msg -pre-commit installed at .git/hooks/prepare-commit-msg -``` +`pre-commit` is triggered before the commit is finalized to allow checks on the +code being committed. Running hooks on unstaged changes can lead to both +false-positives and false-negatives during committing. pre-commit only runs +on the staged contents of files by temporarily stashing the unstaged changes +while running hooks. -`prepare-commit-msg` hooks can be used to create dynamic templates for commit -messages. `prepare-commit-msg` hooks can be configured by setting -`stages: [prepare-commit-msg]`. `prepare-commit-msg` hooks will be passed a -single filename -- this file contains any initial commit message (e.g. from -`git commit -m "..."` or a template) and can be modified by the hook before -the editor is shown. A hook may want to check for `GIT_EDITOR=:` as this -indicates that no editor will be launched. If a hook exits nonzero, -the commit will be aborted. +### pre-merge-commit -[commit-msg]: https://git-scm.com/docs/githooks#_commit_msg -[prepare-commit-msg]: https://git-scm.com/docs/githooks#_prepare_commit_msg +[git pre-merge-commit docs](https://git-scm.com/docs/githooks#_pre_merge_commit) +`pre-merge-commit` fires after a merge succeeds but before the merge commit is +created. This hook runs on all staged files from the merge. -## pre-commit for switching branches -_new in 2.2.0_: pre-commit can be used to manage [post-checkout] hooks. +Note that you need to be using at least git 2.24 for this hook. -To use `post-checkout` hooks with pre-commit, run: +### pre-push -```console -$ pre-commit install --hook-type post-checkout -pre-commit installed at .git/hooks/post-checkout -``` +[git pre-push docs](https://git-scm.com/docs/githooks#_pre_push) -`post-checkout` hooks can be used to perform repository validity checks, -auto-display differences from the previous HEAD if different, -or set working dir metadata properties. Since `post-checkout` doesn't operate -on files, any hooks must set `always_run`: +`pre-push` is triggered on `git push`. -```yaml -- repo: local - hooks: - - id: post-checkout-local - name: Post checkout - always_run: true - stages: [post-checkout] - # ... -``` +environment variables: +- `PRE_COMMIT_FROM_REF`: the revision that is being pushed to. +- `PRE_COMMIT_TO_REF`: the local revision that is being pushed to the remote. +- `PRE_COMMIT_REMOTE_NAME`: which remote is being pushed to (for example `origin`) +- `PRE_COMMIT_REMOTE_URL`: the url of the remote that is being pushed to (for + example `git@github.com:pre-commit/pre-commit`) +- `PRE_COMMIT_REMOTE_BRANCH`: the name of the remote branch to which we are + pushing (for example `refs/heads/target-branch`) +- `PRE_COMMIT_LOCAL_BRANCH`: the name of the local branch that is being pushed + to the remote (for example `HEAD`) -`post-checkout` hooks have three environment variables they can check to -do their work: `$PRE_COMMIT_FROM_REF`, `$PRE_COMMIT_TO_REF`, -and `$PRE_COMMIT_CHECKOUT_TYPE`. These correspond to the first, second, -and third arguments (respectively) that are normally passed to a regular -post-checkout hook from Git. +### pre-rebase -[post-checkout]: https://git-scm.com/docs/githooks#_post_checkout +_new in 3.2.0_ -## Confining hooks to run at certain stages +[git pre-rebase docs](https://git-scm.com/docs/githooks#_pre_rebase) + +`pre-rebase` is triggered before a rebase occurs. A hook failure can cancel a +rebase from occurring. + +`pre-rebase` hooks do not operate on files so they must be set as +`always_run: true` or they will always be skipped. + +environment variables: +- `PRE_COMMIT_PRE_REBASE_UPSTREAM`: the first argument to the `pre-rebase` git hook +- `PRE_COMMIT_PRE_REBASE_BRANCH`: the second argument to the `pre-rebase` git hook. + +### prepare-commit-msg -Since the [`default_stages`](#top_level-default_stages) top level configuration property of the -`.pre-commit-config.yaml` file is set to all stages by default, when installing -hooks using the `-t`/`--hook-type` option (see [pre-commit -install [options]](#pre-commit-install)), all hooks will be installed by default -to run at the stage defined through that option. For instance, -`pre-commit install --hook-type pre-push` will install by default all hooks -to run at the `push` stage. - -Hooks can however be confined to a stage by setting the [`stages`](#config-stages) -property in your `.pre-commit-config.yaml`. The [`stages`](#config-stages) property -is an array and can contain any of `commit`, `merge-commit`, `push`, `prepare-commit-msg`, -`commit-msg`, `post-checkout`, `post-commit`, `post-merge`, and `manual`. - -If you do not want to have hooks installed by default on the stage passed -during a `pre-commit install --hook-type ...`, please set the [`default_stages`](#top_level-default_stages) -top level configuration property to the desired stages, also as an array. - -_new in 1.8.0_: An additional `manual` stage is available for one off execution -that won't run in any hook context. This special stage is useful for taking -advantage of `pre-commit`'s cross-platform / cross-language package management -without running it on every commit. Hooks confined to `stages: [manual]` can -be executed by running `pre-commit run --hook-stage manual [hookid]`. +[git prepare-commit-msg docs](https://git-scm.com/docs/githooks#_prepare_commit_msg) + +`prepare-commit-msg` hooks will be passed a single filename -- this file may +be empty or it could contain the commit message from `-m` or from other +templates. `prepare-commit-msg` hooks can modify the contents of this file to +change what will be committed. A hook may want to check for `GIT_EDITOR=:` as +this indicates that no editor will be launched. If a hook exits nonzero, the +commit will be aborted. + +environment variables: +- `PRE_COMMIT_COMMIT_MSG_SOURCE`: the second argument to the + `prepare-commit-msg` git hook +- `PRE_COMMIT_COMMIT_OBJECT_NAME`: the third argument to the + `prepare-commit-msg` git hook ## Passing arguments to hooks @@ -219,8 +225,8 @@ arguments by specifying the [`args`](#config-args) property in your `.pre-commit as follows: ```yaml -- repo: https://gitlab.com/PyCQA/flake8 - rev: 3.8.3 +- repo: https://github.com/PyCQA/flake8 + rev: 4.0.1 hooks: - id: flake8 args: [--max-line-length=131] @@ -266,9 +272,9 @@ For example: hooks: - id: check-requirements name: check requirements files - language: system + language: unsupported entry: python -m scripts.check_requirements --compare - files: ^requirements.*.txt$ + files: ^requirements.*\.txt$ ``` ## Repository local hooks @@ -285,7 +291,7 @@ You can configure repository-local hooks by specifying the [`repo`](#repos-repo) sentinel `local`. local hooks can use any language which supports [`additional_dependencies`](#config-additional_dependencies) -or `docker_image` / `fail` / `pygrep` / `script` / `system`. +or [`docker_image`](#docker_image) / [`fail`](#fail) / [`pygrep`](#pygrep) / [`unsupported`](#unsupported) / [`unsupported_script`](#unsupported_script). This enables you to install things which previously would require a trivial mirror repository. @@ -301,12 +307,13 @@ Here's an example configuration with a few `local` hooks: - id: pylint name: pylint entry: pylint - language: system + language: unsupported types: [python] + require_serial: true - id: check-x name: Check X entry: ./bin/check-x.sh - language: script + language: unsupported_script files: \.x$ - id: scss-lint name: scss-lint @@ -319,8 +326,6 @@ Here's an example configuration with a few `local` hooks: ## meta hooks -_new in 1.4.0_ - `pre-commit` provides several hooks which are useful for checking the pre-commit configuration itself. These can be enabled using `repo: meta`. @@ -337,22 +342,182 @@ The currently available `meta` hooks: =c= [`check-hooks-apply`](_#meta-check_hooks_apply) =c= ensures that the configured hooks apply to at least one file in the repository. - _new in 1.4.0_. =r= =c= [`check-useless-excludes`](_#meta-check_useless_excludes) =c= ensures that `exclude` directives apply to _any_ file in the repository. - _new in 1.4.0_. =r= =c= [`identity`](_#meta-identity) =c= a simple hook which prints all arguments passed to it, useful for debugging. - _new in 1.14.0_. ``` +## `pre-commit hazmat` + +"hazardous materials" + +pre-commit provides a few `entry` prefix "helpers" for unusual situations. + +in case it's not clear, using these is _usually_ a bad idea. + +_note_: hazmat helpers do not work on languages which adjust `entry` (`docker` +/ `docker_image` / `fail` / `julia` / `pygrep` / `r` / `unsupported_script`). + +### `pre-commit hazmat cd` + +_new in 4.5.0_ + +for "monorepo" usage one can use this to target a subdirectory. + +this entry prefix will cd to the target subdir and adjust filename arguments + +example usage: + +```yaml +# recommended: +# minimum_pre_commit_version: 4.5.0 +repos: +- repo: ... + rev: ... + hooks: + - id: example + alias: example-repo1 + name: example (repo1) + files: ^repo1/ + # important! ends with `--` + # important! copy `args: [...]` to entry and blank out `args: []` + entry: pre-commit hazmat cd repo1 example-bin --arg1 -- + args: [] + + - id: example + alias: example-repo2 + name: example (repo2) + files: ^repo2/ + entry: pre-commit hazmat cd repo2 example-bin --arg1 -- + args: [] + + # ... etc. +``` + +### `pre-commit hazmat ignore-exit-code` + +_new in 4.5.0_ + +it's a bad idea to introduce warning noise but this gives you a way to do it. + +example: + +```yaml +# recommended: +# minimum_pre_commit_version: 4.5.0 +repos: +- repo: ... + rev: ... + hooks: + - id: example + # important! copy `args: [...]` to entry and blank out `args: []` + entry: pre-commit hazmat ignore-exit-code example-bin --arg1 -- + args: [] + # otherwise the output will always be hidden + verbose: true +``` + +### `pre-commit hazmat n1` + +_new in 4.5.0_ + +some hooks only take one filename argument. this runs them one at a time +(which is super slow!) + +example: + +```yaml +# recommended: +# minimum_pre_commit_version: 4.5.0 +repos: +- repo: ... + rev: ... + hooks: + - id: example + # important! ends with `--` + # important! copy `args: [...]` to entry and blank out `args: []` + entry: pre-commit hazmat n1 example-bin --arg1 -- + args: [] +``` + +## usage with git 2.54+ hook configuration + +_new in 4.6.0_: pre-commit improved support for `git config`-based hooks. +a later version will change `pre-commit install` to use this approach. + +[git 2.54] introduced a new way to install git hook tools via `git config`. + +the basic gist is the following enables a hook in a git repo: + +```bash +git config set hook..event pre-push +git config set hook..command 'some command here' +``` + +an example setup with `pre-commit` might look like: + +```bash +# note, the "hook" name here is `pre-commit.pre-commit` +# for the `pre-commit` "tool" and the `pre-commit` "event" +git config set hook.pre-commit.pre-commit.event pre-commit +git config set hook.pre-commit.pre-commit.command 'pre-commit hook-impl --hook-type pre-commit --' + +# please follow that naming scheme for future compatibility with `pre-commit install` + +# an example with pre-push: +# +# git config set hook.pre-commit.pre-push.event pre-push +# git config set hook.pre-commit.pre-push.command 'pre-commit hook-impl --hook-type pre-push --' +``` + +`pre-commit hook-impl` is a "hidden" implementation command with these options: +- `--hook-type ...`: the [hook type](#supported-git-hooks) to use +- `--config ...`: (optional) path to `.pre-commit-config.yaml` +- `--skip-on-missing-config`: silently pass when a config is missing + +some interesting applications of this: + +### "global" installation of pre-commit + +with `git config set --global ...` this can automatically enable pre-commit +for all repositories: + +```bash +git config set --global hook.pre-commit.pre-commit.event pre-commit +git config set --global hook.pre-commit.pre-commit.command 'pre-commit hook-impl --hook-type pre-commit --skip-on-missing-config --' +``` + +- this setup **not recommended** as it can lead to accidentally running hooks + when interacting with an untrusted repository. +- `--skip-on-missing-config` is recommended here as arbitrary git repositories + may not have a `.pre-commit-config.yaml`. + +### always running a hook on all files + +since you can configure pre-commit as many times as you want you *could* invoke +pre-commit to run a particular hook always and on all files + +```bash +git config set hook.pre-commit.pre-commit-always.event pre-commit +git config set hook.pre-commit.pre-commit-always.command 'pre-commit run hookid --hook-stage pre-commit --all-files' +``` + +*note*: this is not recommended as it has the tendancy to be slow and deviates +from the normal expectations of pre-commit. + +[git 2.54]: https://github.blog/open-source/git/highlights-from-git-2-54/#h-config-based-hooks + ## automatically enabling pre-commit on repositories -_new in 1.18.0_ +*note*: if you are on a new-enough version of `git` you may want to use +[this approach](#global-installation-of-pre-commit) instead. + +___ `pre-commit init-templatedir` can be used to set up a skeleton for `git`'s `init.templateDir` option. This means that any newly cloned repository will @@ -390,7 +555,7 @@ Initialized empty Git repository in /tmp/sample/.git/ $ cd sample $ git commit --allow-empty -m 'Initial commit' `.pre-commit-config.yaml` config file not found. Skipping `pre-commit`. -[master (root-commit) d1b39c1] Initial commit +[main (root-commit) d1b39c1] Initial commit ``` To still require opt-in, but prompt the user to set up pre-commit use a @@ -435,8 +600,8 @@ Some of the common tags you'll find from identify: - `executable` - whether the file has the executable bit set - `text` - whether the file looks like a text file - `binary` - whether the file looks like a binary file -- [tags by extension / naming convention](https://github.com/pre-commit/identify/blob/master/identify/extensions.py) -- [tags by shebang (`#!`)](https://github.com/pre-commit/identify/blob/master/identify/interpreters.py) +- [tags by extension / naming convention](https://github.com/pre-commit/identify/blob/main/identify/extensions.py) +- [tags by shebang (`#!`)](https://github.com/pre-commit/identify/blob/main/identify/interpreters.py) To discover the type of any file on disk, you can use `identify`'s cli: @@ -455,7 +620,7 @@ If a file extension you use is not supported, please `types`, `types_or`, and `files` are evaluated together with `AND` when filtering. Tags within `types` are also evaluated using `AND`. -_new in 2.9.0_: Tags within `types_or` are evaluated using `OR`. +Tags within `types_or` are evaluated using `OR`. For example: @@ -493,9 +658,6 @@ with `#!/usr/bin/env python3` will also be matched. As with `files` and `exclude`, you can also exclude types if necessary using `exclude_types`. -If you'd like to use `types` with compatibility for older versions -[here is a guide to ensuring compatibility](https://github.com/pre-commit/pre-commit/pull/551#issuecomment-312535540). - ## Regular expressions The patterns for `files` and `exclude` are python @@ -543,15 +705,17 @@ This tells pre-commit to use ruby `2.1.5` to run the `scss-lint` hook. Valid values for specific languages are listed below: - python: Whatever system installed python interpreters you have. The value of this argument is passed as the `-p` to `virtualenv`. - - _new in 1.4.3_: on windows the + - on windows the [pep394](https://www.python.org/dev/peps/pep-0394/) name will be translated into a py launcher call for portability. So continue to use names like `python3` (`py -3`) or `python3.6` (`py -3.6`) even on windows. - node: See [nodeenv](https://github.com/ekalinin/nodeenv#advanced). - ruby: See [ruby-build](https://github.com/sstephenson/ruby-build/tree/master/share/ruby-build). +- rust: `language_version` is passed to `rustup` +- _new in 3.0.0_ golang: use the versions on [go.dev/dl](https://go.dev/dl/) such as `1.19.5` -_new in 1.14.0_: you can now set [`default_language_version`](#top_level-default_language_version) +you can set [`default_language_version`](#top_level-default_language_version) at the [top level](#pre-commit-configyaml---top-level) in your configuration to control the default versions across all hooks of a language. @@ -568,24 +732,24 @@ default_language_version: you can add a badge to your repository to show your contributors / users that you use pre-commit! -[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) +[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit) - Markdown: ```md#copyable - [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) + [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit) ``` - HTML: ```html#copyable - pre-commit + pre-commit ``` - reStructuredText: ```rst#copyable - .. image:: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white + .. image:: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit :target: https://github.com/pre-commit/pre-commit :alt: pre-commit ``` @@ -593,7 +757,7 @@ you use pre-commit! - AsciiDoc: ```#copyable - image:https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white[pre-commit, link=https://github.com/pre-commit/pre-commit] + image:https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit[pre-commit, link=https://github.com/pre-commit/pre-commit] ``` ## Usage in continuous integration @@ -625,7 +789,7 @@ pre-commit.ci also has the following benefits: - it will autofix pull requests - it will periodically autoupdate your configuration -[![pre-commit.ci speed comparison](https://raw.githubusercontent.com/pre-commit-ci-demo/demo/master/img/2020-12-15_noop.svg)](https://github.com/pre-commit-ci-demo/demo#results) +[![pre-commit.ci speed comparison](https://raw.githubusercontent.com/pre-commit-ci-demo/demo/main/img/2020-12-15_noop.svg)](https://github.com/pre-commit-ci-demo/demo#results) [pre-commit.ci]: https://pre-commit.ci @@ -642,7 +806,7 @@ note: azure pipelines uses immutable caches so the python version and `.pre-commit-config.yaml` hash must be included in the cache key. for a repository template, see [asottile@job--pre-commit.yml]. -[asottile@job--pre-commit.yml]: https://github.com/asottile/azure-pipeline-templates/blob/master/job--pre-commit.yml +[asottile@job--pre-commit.yml]: https://github.com/asottile/azure-pipeline-templates/blob/main/job--pre-commit.yml ```yaml jobs: @@ -703,7 +867,7 @@ immutable caches: ```yaml - name: set PY run: echo "PY=$(python -VV | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: ~/.cache/pre-commit key: pre-commit|${{ env.PY }}|${{ hashFiles('.pre-commit-config.yaml') }} @@ -722,6 +886,9 @@ my_job: - ${PRE_COMMIT_HOME} ``` +pre-commit's cache requires to be served from a constant location between the different builds. This isn't the default when using k8s runners +on GitLab. In case you face the error `InvalidManifestError`, set `builds_dir` to something static e.g `builds_dir = "/builds"` in your `[[runner]]` config + ### travis-ci example ```yaml diff --git a/sections/cli.md b/sections/cli.md index a22752b1..56b74d76 100644 --- a/sections/cli.md +++ b/sections/cli.md @@ -1,12 +1,12 @@ All pre-commit commands take the following options: - `--color {auto,always,never}`: whether to use color in output. - Defaults to `auto`. _new in 1.18.0_: can be overridden by using + Defaults to `auto`. can be overridden by using `PRE_COMMIT_COLOR={auto,always,never}` or disabled using `TERM=dumb`. - `-c CONFIG`, `--config CONFIG`: path to alternate config file - `-h`, `--help`: show help and available options. -_new in 2.8.0_: `pre-commit` now exits with more specific codes: +`pre-commit` exits with specific codes: - `1`: a detected / expected error - `3`: an unexpected error - `130`: the process was interrupted by `^C` @@ -19,10 +19,10 @@ Options: - `--bleeding-edge`: update to the bleeding edge of the default branch instead of the latest tagged version (the default behaviour). -- `--freeze`: _new in 1.21.0_: Store "frozen" hashes in [`rev`](#repos-rev) - instead of tag names. -- `--repo REPO`: _new in 1.4.1_: Only update this repository. _new in 1.7.0_: - This option may be specified multiple times. +- `--freeze`: Store "frozen" hashes in [`rev`](#repos-rev) instead of tag names. +- `--repo REPO`: Only update this repository. This option may be specified + multiple times. +- `-j` / `--jobs`: _new in 3.3.0_ Number of threads to use (default: 1). Here are some sample invocations using this `.pre-commit-config.yaml`: @@ -68,6 +68,8 @@ $ grep rev: .pre-commit-config.yaml rev: 34a269fd7650d264e4de7603157c10d0a9bb8211 # frozen: v1.25.2 ``` +pre-commit will preferentially pick tags containing a `.` if there are ties. + ## pre-commit clean [options] #pre-commit-clean Clean out cached pre-commit files. @@ -76,8 +78,6 @@ Options: (no additional options) ## pre-commit gc [options] #pre-commit-gc -_new in 1.14.0_ - Clean unused cached repos. `pre-commit` keeps a cache of installed hook repositories which grows over @@ -88,15 +88,12 @@ Options: (no additional options) ## pre-commit init-templatedir DIRECTORY [options] #pre-commit-init-templatedir -_new in 1.18.0_ - Install hook script in a directory intended for use with `git config init.templateDir`. Options: -- `-t {pre-commit,pre-merge-commit,pre-push,prepare-commit-msg,commit-msg,post-checkout,post-commit,post-merge}`, - `--hook-type {pre-commit,pre-merge-commit,pre-push,prepare-commit-msg,commit-msg,post-checkout,post-commit,post-merge}`: +- `-t HOOK_TYPE, --hook-type HOOK_TYPE`: which hook type to install. Some example useful invocations: @@ -132,20 +129,23 @@ Options: - `--install-hooks`: Also install environments for all available hooks now (rather than when they are first executed). See [`pre-commit install-hooks`](#pre-commit-install-hooks). -- `-t {pre-commit,pre-merge-commit,pre-push,prepare-commit-msg,commit-msg,post-checkout,post-commit,post-merge}`, - `--hook-type {pre-commit,pre-merge-commit,pre-push,prepare-commit-msg,commit-msg,post-checkout,post-commit,post-merge}`: +- `-t HOOK_TYPE, --hook-type HOOK_TYPE`: Specify which hook type to install. - `--allow-missing-config`: Hook scripts will permit a missing configuration file. Some example useful invocations: -- `pre-commit install`: Default invocation. Installs the pre-commit script +- `pre-commit install`: Default invocation. Installs the hook scripts alongside any existing git hooks. - `pre-commit install --install-hooks --overwrite`: Idempotently replaces existing git hook scripts with pre-commit, and also installs hook environments. +`pre-commit install` will install hooks from +[`default_install_hook_types`](#top_level-default_install_hook_types) if +`--hook-type` is not specified on the command line. + ## pre-commit install-hooks [options] #pre-commit-install-hooks Install all missing environments for the available hooks. Unless this command or @@ -162,8 +162,6 @@ Options: (no additional options) ## pre-commit migrate-config [options] #pre-commit-migrate-config -_new in 1.0.0_ - Migrate list configuration to the new map configuration format. Options: (no additional options) @@ -179,8 +177,6 @@ Options: - `--files [FILES [FILES ...]]`: specific filenames to run hooks on. - `--from-ref FROM_REF` + `--to-ref TO_REF`: run against the files changed between `FROM_REF...TO_REF` in git. - - _new in 2.2.0_: prior to 2.2.0 the arguments were `--source` and - `--origin`. - `--hook-stage STAGE`: select a [`stage` to run](#confining-hooks-to-run-at-certain-stages). - `--show-diff-on-failure`: when hooks fail, run `git diff` directly afterward. - `-v`, `--verbose`: produce hook output independent of success. Include hook @@ -206,8 +202,6 @@ Options: (no additional options) ## pre-commit try-repo REPO [options] #pre-commit-try-repo -_new in 1.3.0_ - Try the hooks in a repository, useful for developing new hooks. `try-repo` can also be used for testing out a repository before adding it to your configuration. `try-repo` prints a configuration it generates based on @@ -238,6 +232,12 @@ Uninstall the pre-commit script. Options: -- `-t {pre-commit,pre-merge-commit,pre-push,prepare-commit-msg,commit-msg,post-checkout,post-commit,post-merge}`, - `--hook-type {pre-commit,pre-merge-commit,pre-push,prepare-commit-msg,commit-msg,post-checkout,post-commit,post-merge}`: - which hook type to uninstall. +- `-t HOOK_TYPE, --hook-type HOOK_TYPE`: which hook type to uninstall. + +## pre-commit validate-config [options] [filenames ...] #pre-commit-validate-config + +Validate .pre-commit-config.yaml files + +## pre-commit validate-manifest [options] [filenames ...] #pre-commit-validate-manifest + +Validate .pre-commit-hooks.yaml files diff --git a/sections/hooks.md b/sections/hooks.md new file mode 100644 index 00000000..a045f6f6 --- /dev/null +++ b/sections/hooks.md @@ -0,0 +1,167 @@ +## featured hooks + +here are a few hand-picked repositories which provide pre-commit integrations. + +these are fairly popular and are generally known to work well in most setups! + +_this list is not intended to be exhaustive_ + +provided by the pre-commit team: +- [pre-commit/pre-commit-hooks]: a handful of language-agnostic hooks which + are universally useful! +- [pre-commit/pygrep-hooks]: a few quick regex-based hooks for a handful of + quick syntax checks +- [pre-commit/sync-pre-commit-deps]: sync pre-commit hook dependencies based + on other installed hooks +- [pre-commit/mirrors-*]: pre-commit mirrors of a handful of popular tools + +[pre-commit/pre-commit-hooks]: https://github.com/pre-commit/pre-commit-hooks +[pre-commit/pygrep-hooks]: https://github.com/pre-commit/pygrep-hooks +[pre-commit/sync-pre-commit-deps]: https://github.com/pre-commit/sync-pre-commit-deps +[pre-commit/mirrors-*]: https://github.com/orgs/pre-commit/repositories?language=&q=%22mirrors-%22+archived%3AFalse&sort= + +for python projects: +- [asottile/pyupgrade]: automatically upgrade syntax for newer versions of the + language +- [asottile/(others)]: a few other repos by the pre-commit creator +- [psf/black]: The uncompromising Python code formatter +- [hhatto/autopep8]: automatically fixes PEP8 violations +- [astral-sh/ruff-pre-commit]: the ruff linter and formatter for python +- [google/yapf]: a highly configurable python formatter +- [PyCQA/flake8]: a linter framework for python +- [PyCQA/isort]: an import sorter for python +- [PyCQA/(others)]: a few other python code quality tools +- [adamchainz/django-upgrade]: automatically upgrade your Django project code + +[asottile/pyupgrade]: https://github.com/asottile/pyupgrade +[asottile/(others)]: https://sourcegraph.com/search?q=context:global+file:%5E%5C.pre-commit-hooks%5C.yaml%24+repo:%5Egithub.com/asottile/ +[psf/black]: https://github.com/psf/black +[hhatto/autopep8]: https://github.com/hhatto/autopep8 +[astral-sh/ruff-pre-commit]: https://github.com/astral-sh/ruff-pre-commit +[google/yapf]: https://github.com/google/yapf +[PyCQA/flake8]: https://github.com/PyCQA/flake8 +[PyCQA/isort]: https://github.com/PyCQA/isort +[PyCQA/(others)]: https://sourcegraph.com/search?q=context:global+file:%5E%5C.pre-commit-hooks%5C.yaml%24+repo:%5Egithub.com/PyCQA/ +[adamchainz/django-upgrade]: https://github.com/adamchainz/django-upgrade + +for shell scripts: +- [shellcheck-py/shellcheck-py]: runs shellcheck on your scripts +- [openstack/bashate]: code style enforcement for bash programs + +[shellcheck-py/shellcheck-py]: https://github.com/shellcheck-py/shellcheck-py +[openstack/bashate]: https://github.com/openstack/bashate + +for the web: +- [biomejs/pre-commit]: a fast formatter / fixer written in rust +- [standard/standard]: linter / fixer +- [oxipng/oxipng]: optimize png files + +[biomejs/pre-commit]: https://github.com/biomejs/pre-commit +[standard/standard]: https://github.com/standard/standard +[oxipng/oxipng]: https://github.com/oxipng/oxipng + +for configuration files: +- [python-jsonschema/check-jsonschema]: check many common configurations with jsonschema +- [rhysd/actionlint]: lint your GitHub Actions workflow files +- [google/yamlfmt]: a formatter for yaml files +- [adrienverge/yamllint]: a linter for YAML files + +[python-jsonschema/check-jsonschema]: https://github.com/python-jsonschema/check-jsonschema +[rhysd/actionlint]: https://github.com/rhysd/actionlint +[google/yamlfmt]: https://github.com/google/yamlfmt +[adrienverge/yamllint]: https://github.com/adrienverge/yamllint + +for text / docs / prose: +- [crate-ci/typos]: find and fix common typographical errors +- [thlorenz/doctoc]: generate a table-of-contents in markdown files +- [amperser/proselint]: A linter for prose. +- [markdownlint/markdownlint]: a Markdown lint tool in Ruby +- [DavidAnson/markdownlint-cli2]: a Markdown lint tool in Node +- [codespell-project/codespell]: check code for common misspellings + +[crate-ci/typos]: https://github.com/crate-ci/typos +[thlorenz/doctoc]: https://github.com/thlorenz/doctoc +[amperser/proselint]: https://github.com/amperser/proselint +[markdownlint/markdownlint]: https://github.com/markdownlint/markdownlint +[DavidAnson/markdownlint-cli2]: https://github.com/DavidAnson/markdownlint-cli2 +[codespell-project/codespell]: https://github.com/codespell-project/codespell + +for linting commit messages: +- [jorisroovers/gitlint] +- [commitizen-tools/commitizen] + +[jorisroovers/gitlint]: https://github.com/jorisroovers/gitlint +[commitizen-tools/commitizen]: https://github.com/commitizen-tools/commitizen + +for secret scanning / security: +- [gitleaks/gitleaks] +- [trufflesecurity/truffleHog] +- [thoughtworks/talisman] + +[gitleaks/gitleaks]: https://github.com/gitleaks/gitleaks +[trufflesecurity/truffleHog]: https://github.com/trufflesecurity/truffleHog +[thoughtworks/talisman]: https://github.com/thoughtworks/talisman + +for other programming languages: +- [realm/SwiftLint]: enforce Swift style and conventions +- [nicklockwood/SwiftFormat]: a formatter for Swift +- [AleksaC/terraform-py]: format and validate terraform syntax +- [rubocop/rubocop]: static analysis and formatting for Ruby +- [bufbuild/buf]: tooling for Protocol Buffers +- [sqlfluff/sqlfluff]: a modular linter and auto formatter for SQL +- [aws-cloudformation/cfn-lint]: aws CloudFormation linter +- [google/go-jsonnet]: linter / formatter for jsonnet +- [JohnnyMorganz/StyLua]: an opinionated Lua code formatter +- [Koihik/LuaFormatter]: a formatter for Lua code +- [mrtazz/checkmake]: linter for Makefile syntax +- [nbqa-dev/nbqa]: run common linters on Jupyter Notebooks + +[realm/SwiftLint]: https://github.com/realm/SwiftLint +[nicklockwood/SwiftFormat]: https://github.com/nicklockwood/SwiftFormat +[AleksaC/terraform-py]: https://github.com/AleksaC/terraform-py +[rubocop/rubocop]: https://github.com/rubocop/rubocop +[bufbuild/buf]: https://github.com/bufbuild/buf +[sqlfluff/sqlfluff]: https://github.com/sqlfluff/sqlfluff +[aws-cloudformation/cfn-lint]: https://github.com/aws-cloudformation/cfn-lint +[google/go-jsonnet]: https://github.com/google/go-jsonnet +[JohnnyMorganz/StyLua]: https://github.com/JohnnyMorganz/StyLua +[Koihik/LuaFormatter]: https://github.com/Koihik/LuaFormatter +[mrtazz/checkmake]: https://github.com/mrtazz/checkmake +[nbqa-dev/nbqa]: https://github.com/nbQA-dev/nbQA + +## finding hooks + +it's recommended to use your favorite searching tool to find existing hooks to +use in your project. + +for example, here's some searches you may find useful using [sourcegraph]: + +- hooks which run on python files: [`file:^\.pre-commit-hooks\.yaml$ "types: [python]"`](https://sourcegraph.com/search?q=context:global+file:^\.pre-commit-hooks\.yaml%24+%22types:+[python]%22) +- hooks which run on shell files: [`file:^\.pre-commit-hooks\.yaml$ "types: [shell]"`](https://sourcegraph.com/search?q=context:global+file:^\.pre-commit-hooks\.yaml%24+"types:+[shell]") +- pre-commit configurations in popular projects: [`file:^\.pre-commit-config\.yaml$`](https://sourcegraph.com/search?q=context:global+file:^\.pre-commit-hooks\.yaml) + +[sourcegraph]: https://sourcegraph.com/search + +you may also find [github's search] useful as well, though its querying and +sorting capabilities are quite limited plus it requires a login: + +- repositories providing hooks: [`path:.pre-commit-hooks.yaml language:YAML`](https://github.com/search?q=path%3A.pre-commit-hooks.yaml+language%3AYAML&type=code&l=YAML) + +[github's search]: https://github.com/search + + +## adding to this page + +the previous iteration of this page was a laundry list of hooks and maintaining +quality of the listed tools was cumbersome. + +**this page is not intended to be exhaustive** + +you may send [a pull request] to expand this list however there are a few +requirements you *must* follow or your PR will be closed without comment: + +- the tool must already be fairly popular (>500 stars) +- the tool must use a managed language (no `unsupported` / `unsupported_script` / `docker` hooks) +- the tool must operate on files + +[a pull request]: https://github.com/pre-commit/pre-commit.com/blob/main/sections/hooks.md diff --git a/sections/install.md b/sections/install.md index c114c049..3d6d4d85 100644 --- a/sections/install.md +++ b/sections/install.md @@ -7,16 +7,6 @@ Using pip: pip install pre-commit ``` -Non-administrative installation: - -- _to upgrade: run again, to uninstall: pass `uninstall` to python_ -- _does not work on platforms without symlink support (windows)_ - - -```bash -curl https://pre-commit.com/install-local.py | python - -``` - In a python project, add the following to your requirements.txt (or requirements-dev.txt): @@ -32,18 +22,6 @@ As a 0-dependency [zipapp]: [zipapp]: https://docs.python.org/3/library/zipapp.html [github releases]: https://github.com/pre-commit/pre-commit/releases -Using [homebrew](https://brew.sh): - -```bash -brew install pre-commit -``` - -Using [conda](https://conda.io) (via [conda-forge](https://conda-forge.org)): - -```bash -conda install -c conda-forge pre-commit -``` - ## Quick start ### 1. Install pre-commit @@ -74,7 +52,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/psf/black - rev: 19.3b0 + rev: 22.10.0 hooks: - id: black ``` diff --git a/sections/new-hooks.md b/sections/new-hooks.md index 181efcd1..7f21d439 100644 --- a/sections/new-hooks.md +++ b/sections/new-hooks.md @@ -4,9 +4,12 @@ installable package (gem, npm, pypi, etc.) or exposes an executable, it can be used with pre-commit. Each git repo can support as many languages/hooks as you want. +_new in 2.5.0_: `pre-commit` sets the `PRE_COMMIT=1` environment variable +during hook execution. + The hook must exit nonzero on failure or modify files. -A git repo containing pre-commit plugins must contain a .pre-commit-hooks.yaml +A git repo containing pre-commit plugins must contain a `.pre-commit-hooks.yaml` file that tells pre-commit: ```table @@ -37,7 +40,6 @@ file that tells pre-commit: =c= [`types_or`](_#hooks-types_or) =c= (optional: default `[]`) list of file types to run on (OR). See [Filtering files with types](#filtering-files-with-types). - _new in 2.9.0_. =r= =c= [`exclude_types`](_#hooks-exclude_types) =c= (optional: default `[]`) the pattern of files to exclude. @@ -45,10 +47,14 @@ file that tells pre-commit: =c= [`always_run`](_#hooks-always_run) =c= (optional: default `false`) if `true` this hook will run even if there are no matching files. +=r= + =c= [`fail_fast`](_#hooks-fail_fast) + =c= (optional: default `false`) if `true` pre-commit will stop running + hooks if this hook fails. =r= =c= [`verbose`](_#hooks-verbose) - =c= (optional) if `true`, forces the output of the hook to be printed even when - the hook passes. _new in 1.6.0_. + =c= (optional: default `false`) if `true`, forces the output of the hook to be printed even when + the hook passes. =r= =c= [`pass_filenames`](_#hooks-pass_filenames) =c= (optional: default `true`) if `false` no filenames will be passed to @@ -56,7 +62,7 @@ file that tells pre-commit: =r= =c= [`require_serial`](_#hooks-require_serial) =c= (optional: default `false`) if `true` this hook will execute using a - single process instead of in parallel. _new in 1.13.0_. + single process instead of in parallel. =r= =c= [`description`](_#hooks-description) =c= (optional: default `''`) description of the hook. used for metadata @@ -74,10 +80,8 @@ file that tells pre-commit: =c= (optional: default `[]`) list of additional parameters to pass to the hook. =r= =c= [`stages`](_#hooks-stages) - =c= (optional: default (all stages)) confines the hook to the `commit`, `merge-commit`, - `push`, `prepare-commit-msg`, `commit-msg`, `post-checkout`, `post-commit`, - `post-merge`, or `manual` stage. See - [Confining hooks to run at certain stages](#confining-hooks-to-run-at-certain-stages). + =c= (optional: default (all stages)) selects which git hook(s) to run for. + See [Confining hooks to run at certain stages](#confining-hooks-to-run-at-certain-stages). ``` @@ -105,16 +109,14 @@ interactively: _note_: you may need to provide `--commit-msg-filename` when using this command with hook types `prepare-commit-msg` and `commit-msg`. -_new in 1.14.0_: a commit is no longer necessary to `try-repo` on a local +a commit is not necessary to `try-repo` on a local directory. `pre-commit` will clone any tracked uncommitted changes. ```pre-commit -~/work/hook-repo $ git checkout origin/master -b feature +~/work/hook-repo $ git checkout origin/main -b feature # ... make some changes -# new in 1.14.0: a commit is no longer necessary for `try-repo` - # In another terminal or tab ~/work/other-repo $ pre-commit try-repo ../hook-repo foo --verbose --all-files @@ -140,27 +142,28 @@ Hello from foo hook! - [conda](#conda) - [coursier](#coursier) +- [dart](#dart) - [docker](#docker) - [docker_image](#docker_image) - [dotnet](#dotnet) - [fail](#fail) - [golang](#golang) +- [haskell](#haskell) +- [julia](#julia) +- [lua](#lua) - [node](#node) - [perl](#perl) - [python](#python) -- [python_venv](#python_venv) - [r](#r) - [ruby](#ruby) - [rust](#rust) - [swift](#swift) - [pygrep](#pygrep) -- [script](#script) -- [system](#system) +- [unsupported](#unsupported) +- [unsupported_script](#unsupported_script) ### conda -_new in 1.21.0_ - The hook repository must contain an `environment.yml` file which will be used via `conda env create --file environment.yml ...` to create the environment. @@ -168,25 +171,51 @@ The `conda` language also supports [`additional_dependencies`](#config-additiona and will pass any of the values directly into `conda install`. This language can therefore be used with [local](#repository-local-hooks) hooks. +`mamba` or `micromamba` can be used to install instead via the +`PRE_COMMIT_USE_MAMBA=1` or `PRE_COMMIT_USE_MICROMAMBA=1` environment +variables. + __Support:__ `conda` hooks work as long as there is a system-installed `conda` binary (such as [`miniconda`](https://docs.conda.io/en/latest/miniconda.html)). It has been tested on linux, macOS, and windows. ### coursier -_new in 2.8.0_ - -The hook repository must have a `.pre-commit-channel` folder and that folder must contain -the coursier +The hook repository must have a `.pre-commit-channel` folder and that folder +must contain the coursier [application descriptors](https://get-coursier.io/docs/2.0.0-RC6-10/cli-install.html#application-descriptor-reference) for the hook to install. For configuring coursier hooks, your [`entry`](#hooks-entry) should correspond to an executable installed from the repository's `.pre-commit-channel` folder. -__Support:__ `coursier` hooks are known to work on any system which has the `cs` -package manager installed. The specific coursier applications you install may depend -on various versions of the JVM, consult the hooks' documentation for clarification. -It has been tested on linux. +__Support:__ `coursier` hooks are known to work on any system which has the +`cs` or `coursier` package manager installed. The specific coursier +applications you install may depend on various versions of the JVM, consult +the hooks' documentation for clarification. It has been tested on linux. + +pre-commit also supports the `coursier` naming of the package manager +executable. + +_new in 3.0.0_: `language: coursier` hooks now support `repo: local` and +`additional_dependencies`. + +### dart + +The hook repository must have a `pubspec.yaml` -- this must contain an +`executables` section which will list the binaries that will be available +after installation. Match the [`entry`](#hooks-entry) to an executable. + +`pre-commit` will build each executable using `dart compile exe bin/{executable}.dart`. + +`language: dart` also supports [`additional_dependencies`](#config-additional_dependencies). +to specify a version for a dependency, separate the package name by a `:`: + +```yaml + additional_dependencies: ['hello_world_dart:1.0.0'] +``` + +__Support:__ `dart` hooks are known to work on any system which has the `dart` +sdk installed. It has been tested on linux, macOS, and windows. ### docker @@ -243,8 +272,6 @@ For example: ### dotnet -_new in 2.8.0_ - dotnet hooks are installed using the system installation of the dotnet CLI. Hook repositories must contain a dotnet CLI tool which can be `pack`ed and @@ -257,8 +284,6 @@ CLI installed. It has been tested on linux and windows. ### fail -_new in 1.11.0_ - A lightweight [`language`](#hooks-language) to forbid files by filename. The `fail` language is especially useful for [local](#repository-local-hooks) hooks. @@ -281,13 +306,80 @@ being added to the `changelog` directory: ### golang The hook repository must contain go source code. It will be installed via -`go get ./...`. pre-commit will create an isolated `GOPATH` for each hook and -the [`entry`](#hooks-entry) should match an executable which will get installed into the +`go install ./...`. pre-commit will create an isolated `GOPATH` for each hook +and the [`entry`](#hooks-entry) should match an executable which will get installed into the `GOPATH`'s `bin` directory. +This language supports `additional_dependencies` and will pass any of the values directly to `go +install`. It can be used as a `repo: local` hook. + +_changed in 2.17.0_: previously `go get ./...` was used + +_new in 3.0.0_: pre-commit will bootstrap `go` if it is not present. `language: golang` +also now supports `language_version` + __Support:__ golang hooks are known to work on any system which has go installed. It has been tested on linux, macOS, and windows. +### haskell + +_new in 3.4.0_ + +The hook repository must have one or more `*.cabal` files. Once installed +the `executable`s from these packages will be available to use with `entry`. + +This language supports `additional_dependencies` so it can be used as a +`repo: local` hook. + +__Support:__ haskell hooks are known to work on any system which has `cabal` +installed. It has been tested on linux, macOS, and windows. + +### julia + +_new in 4.1.0_ + +For configuring julia hooks, your [`entry`](#hooks-entry) should be a path to a julia source +file relative to the hook repository (optionally with arguments). + +Hooks run in an isolated package environment defined by a `Project.toml` file (optionally +with a `Manifest.toml` file) in the hook repository. If no `Project.toml` file is found the +hook is run in an empty environment. + +Julia hooks support [`additional_dependencies`](#config-additional_dependencies) which can +be used to augment, or override, the existing environment in the hooks repository. This also +means that julia can be used as a `repo: local` hook. `additional_dependencies` are passed +to `pkg> add` and should be specified using +[Pkg REPL mode syntax](https://pkgdocs.julialang.org/v1/repl/#repl-add). + +Examples: + +```yaml +- id: foo-without-args + name: ... + language: julia + entry: bin/foo.jl +- id: bar-with-args + name: ... + language: julia + entry: bin/bar.jl --arg1 --arg2 +- id: baz-with-extra-deps + name: ... + language: julia + entry: bin/baz.jl + additional_dependencies: + - 'ExtraDepA@1' + - 'ExtraDepB@2.4' +``` + +__Support:__ julia hooks are known to work on any system which has `julia` installed. + +### lua + +Lua hooks are installed with the version of Lua that is used by Luarocks. + +__Support:__ Lua hooks are known to work on any system which has Luarocks +installed. It has been tested on linux and macOS and _may_ work on windows. + ### node The hook repository must have a `package.json`. It will be installed via @@ -295,17 +387,12 @@ The hook repository must have a `package.json`. It will be installed via match the [`entry`](#hooks-entry) – usually through `bin` in package.json. __Support:__ node hooks work without any system-level dependencies. It has -been tested on linux and macOS and _may_ work under cygwin. - -_new in 1.5.0_: windows is now supported for node hooks. Currently python3 -only due to [a bug in cpython](https://bugs.python.org/issue32539). +been tested on linux, windows, and macOS and _may_ work under cygwin. ### perl -_new in 2.1.0_ - Perl hooks are installed using the system installation of -[cpan](https://perldoc.perl.org/5.30.0/cpan.html), the CPAN package installer +[cpan](https://perldoc.perl.org/cpan), the CPAN package installer that comes with Perl. Hook repositories must have something that `cpan` supports, typically @@ -315,7 +402,7 @@ via `cpan -T .` (with the installed files stored in your pre-commit cache, not polluting other Perl installations). When specifying [`additional_dependencies`](#config-additional_dependencies) for Perl, you can use any of the -[install argument formats understood by `cpan`](https://perldoc.perl.org/5.30.0/CPAN.html#get%2c-make%2c-test%2c-install%2c-clean-modules-or-distributions). +[install argument formats understood by `cpan`](https://perldoc.perl.org/CPAN#get%2c-make%2c-test%2c-install%2c-clean-modules-or-distributions). __Support:__ Perl hooks currently require a pre-existing Perl installation, including the `cpan` tool in `PATH`. It has been tested on linux, macOS, and @@ -328,29 +415,15 @@ The hook repository must be installable via `pip install .` (usually by either executable that will match the [`entry`](#hooks-entry) – usually through `console_scripts` or `scripts` in setup.py. -__Support:__ python hooks work without any system-level dependencies. It -has been tested on linux, macOS, windows, and cygwin. - -### python_venv - -_new in 1.9.0_ - -_new in 2.4.0_: The `python_venv` language is now an alias to `python` since -`virtualenv>=20` creates equivalently structured environments. Previously, -this [`language`](#hooks-language) created environments using the [venv] module. - -This [`language`](#hooks-language) will be removed eventually so it is suggested to use `python` -instead. - -[venv]: https://docs.python.org/3/library/venv.html +This language also supports `additional_dependencies` +so it can be used with [local](#repository-local-hooks) hooks. +The specified dependencies will be appended to the `pip install` command. __Support:__ python hooks work without any system-level dependencies. It has been tested on linux, macOS, windows, and cygwin. ### r -_new in 2.11.0_ - This hook repository must have a `renv.lock` file that will be restored with [`renv::restore()`](https://rstudio.github.io/renv/reference/restore.html) on hook installation. If the repository is an R package (i.e. has `Type: Package` @@ -379,10 +452,8 @@ been tested on linux and macOS and _may_ work under cygwin. ### rust -_new in 1.10.0_ - -Rust hooks are installed using the system installation of -[Cargo](https://github.com/rust-lang/cargo), Rust's official package manager. +Rust hooks are installed using [Cargo](https://github.com/rust-lang/cargo), +Rust's official package manager. Hook repositories must have a `Cargo.toml` file which produces at least one binary ([example](https://github.com/chriskuehl/example-rust-pre-commit-hook)), @@ -396,8 +467,10 @@ build _your_ hook repo), or the special syntax `cli:{package_name}:{package_version}` for a CLI dependency (built separately, with binaries made available for use by hooks). -__Support:__ Rust hooks currently require a pre-existing Rust installation. It -has been tested on linux, Windows, and macOS. +pre-commit will bootstrap `rust` if it is not present. +`language: rust` also supports `language_version` + +__Support:__ It has been tested on linux, Windows, and macOS. ### swift @@ -410,37 +483,40 @@ installed. It has been tested on linux and macOS. ### pygrep -_new in 1.2.0_ - A cross-platform python implementation of `grep` – pygrep hooks are a quick way to write a simple hook which prevents commits by file matching. Specify the regex as the [`entry`](#hooks-entry). The [`entry`](#hooks-entry) may be any python [regular expression](#regular-expressions). For case insensitive regexes you can apply the `(?i)` flag as the start of your entry, or use `args: [-i]`. -_new in 1.8.0_: For multiline matches, use `args: [--multiline]`. -_new in 2.8.0_: To require all files to match, use `args: [--negate]`. +For multiline matches, use `args: [--multiline]`. + +To require all files to match, use `args: [--negate]`. __Support:__ pygrep hooks are supported on all platforms which pre-commit runs on. -### script +### unsupported -Script hooks provide a way to write simple scripts which validate files. The -[`entry`](#hooks-entry) should be a path relative to the root of the hook repository. +[anchor](__#system) +_new in 4.4.0_: previously `language: system`. the alias will be removed in a +future version + +System hooks provide a way to write hooks for system-level executables which +don't have a supported language above (or have special environment +requirements that don't allow them to run in isolation such as pylint). This hook type will not be given a virtual environment to work with – if it needs additional dependencies the consumer must install them manually. -__Support:__ the support of script hooks depend on the scripts themselves. +### unsupported_script -### system +[anchor](__#script) +_new in 4.4.0_: previously `language: script`. the alias will be removed in a +future version -System hooks provide a way to write hooks for system-level executables which -don't have a supported language above (or have special environment -requirements that don't allow them to run in isolation such as pylint). +Script hooks provide a way to write simple scripts which validate files. The +[`entry`](#hooks-entry) should be a path relative to the root of the hook repository. This hook type will not be given a virtual environment to work with – if it needs additional dependencies the consumer must install them manually. - -__Support:__ the support of system hooks depend on the executables. diff --git a/sections/plugins.md b/sections/plugins.md index 0245648d..96cb213c 100644 --- a/sections/plugins.md +++ b/sections/plugins.md @@ -6,17 +6,15 @@ pre-commit config file describes what repositories and hooks are installed. ## .pre-commit-config.yaml - top level -_new in 1.0.0_: The default configuration file top-level was changed from a -list to a map. If you're using an old version of pre-commit, the top-level -list is the same as the value of [`repos`](#pre-commit-configyaml---repos). -If you'd like to migrate to the new configuration format, run -[`pre-commit migrate-config`](#pre-commit-migrate-config) to automatically -migrate your configuration. - ```table =r= =c= [`repos`](_#top_level-repos) =c= A list of [repository mappings](#pre-commit-configyaml---repos). +=r= + =c= [`default_install_hook_types`](_#top_level-default_install_hook_types) + =c= (optional: default `[pre-commit]`) a list of `--hook-type`s which will + be used by default when running + [`pre-commit install`](#pre-commit-install). =r= =c= [`default_language_version`](_#top_level-default_language_version) =c= (optional: default `{}`) a mapping from language to the default @@ -29,8 +27,6 @@ migrate your configuration. default_language_version: python: python3.7 ``` - - _new in 1.14.0_ =r= =c= [`default_stages`](_#top_level-default_stages) =c= (optional: default (all stages)) a configuration-wide default for @@ -40,24 +36,21 @@ migrate your configuration. For example: ```yaml - default_stages: [commit, push] + default_stages: [pre-commit, pre-push] ``` - - _new in 1.14.0_ =r= =c= [`files`](_#top_level-files) - =c= (optional: default `''`) global file include pattern. _new in 1.21.0_. + =c= (optional: default `''`) global file include pattern. =r= =c= [`exclude`](_#top_level-exclude) - =c= (optional: default `^$`) global file exclude pattern. _new in 1.1.0_. + =c= (optional: default `^$`) global file exclude pattern. =r= =c= [`fail_fast`](_#top_level-fail_fast) =c= (optional: default `false`) set to `true` to have pre-commit stop - running hooks after the first failure. _new in 1.1.0_. + running hooks after the first failure. =r= =c= [`minimum_pre_commit_version`](_#top_level-minimum_pre_commit_version) =c= (optional: default `'0'`) require a minimum version of pre-commit. - _new in 1.15.0_. ``` A sample top-level: @@ -78,9 +71,12 @@ from. =r= =c= [`repo`](_#repos-repo) =c= the repository url to `git clone` from + or one of the special sentinel values: + [`local`](#repository-local-hooks), + [`meta`](#meta-hooks). =r= =c= [`rev`](_#repos-rev) - =c= the revision or tag to clone at. _new in 1.7.0_: previously `sha` + =c= the revision or tag to clone at. =r= =c= [`hooks`](_#repos-hooks) =c= A list of [hook mappings](#pre-commit-configyaml---hooks). @@ -110,7 +106,6 @@ repository's configuration. =c= [`alias`](_#config-alias) =c= (optional) allows the hook to be referenced using an additional id when using `pre-commit run `. - _new in 1.14.0_. =r= =c= [`name`](_#config-name) =c= (optional) override the name of the hook - shown during hook execution. @@ -132,7 +127,6 @@ repository's configuration. =c= [`types_or`](_#config-types_or) =c= (optional) override the default file types to run on (OR). See [Filtering files with types](#filtering-files-with-types). - _new in 2.9.0_. =r= =c= [`exclude_types`](_#config-exclude_types) =c= (optional) file types to exclude. @@ -141,10 +135,8 @@ repository's configuration. =c= (optional) list of additional parameters to pass to the hook. =r= =c= [`stages`](_#config-stages) - =c= (optional) confines the hook to the `commit`, `merge-commit`, `push`, - `prepare-commit-msg`, `commit-msg`, `post-checkout`, `post-commit`, - `post-merge`, or `manual` stage. See - [Confining hooks to run at certain stages](#confining-hooks-to-run-at-certain-stages). + =c= (optional) selects which git hook(s) to run for. + See [Confining hooks to run at certain stages](#confining-hooks-to-run-at-certain-stages). =r= =c= [`additional_dependencies`](_#config-additional_dependencies) =c= (optional) a list of dependencies that will be installed in the @@ -157,7 +149,7 @@ repository's configuration. =r= =c= [`verbose`](_#config-verbose) =c= (optional) if `true`, forces the output of the hook to be printed even when - the hook passes. _new in 1.6.0_. + the hook passes. =r= =c= [`log_file`](_#config-log_file) =c= (optional) if present, the hook output will additionally be written to diff --git a/sections/usage.md b/sections/usage.md index dbba2aab..94addae8 100644 --- a/sections/usage.md +++ b/sections/usage.md @@ -27,6 +27,6 @@ pyupgrade................................................................Passed rst ``code`` is two backticks........................(no files to check)Skipped rst..................................................(no files to check)Skipped changelog filenames..................................(no files to check)Skipped -[master 146c6c2c] Add super awesome feature +[main 146c6c2c] Add super awesome feature 1 file changed, 1 insertion(+) ``` diff --git a/template_lib.py b/template_lib.py index e9e5ef80..72286d70 100644 --- a/template_lib.py +++ b/template_lib.py @@ -1,22 +1,23 @@ +from __future__ import annotations + +import html import os import re import shlex import subprocess import sys -from typing import Optional import markdown_code_blocks import markupsafe ID_RE = re.compile(r' #([a-z0-9-]+)$') -SPECIAL_CHARS_RE = re.compile('[^a-z0-9 _-]') +SPECIAL_CHARS_RE = re.compile('(&[a-z]+;|[^a-z0-9 _-])') ROW = '=r=' COL = ' =c= ' INDENT = ' ' * 8 -SELF_LINK_PREFIX = '_#' def _render_table(code: str) -> str: @@ -64,13 +65,13 @@ def _maybe_end_row() -> None: output.append('') elif line.startswith(COL): _maybe_end_col() - col_buffer = line[len(COL):] + col_buffer = line.removeprefix(COL) elif col_buffer is not None: if line == '\n': col_buffer += line else: assert line.startswith(INDENT), line - col_buffer += line[len(INDENT):] + col_buffer += line.removeprefix(INDENT) else: raise AssertionError(line) @@ -90,11 +91,13 @@ def _render_cmd(code: str) -> str: class Renderer(markdown_code_blocks.CodeRenderer): def link( - self, link: str, text: Optional[str], title: Optional[str], + self, link: str, text: str | None, title: str | None, ) -> str: - if link.startswith(SELF_LINK_PREFIX): - a_id = link[len(SELF_LINK_PREFIX):] + if link.startswith('_#'): + a_id = link.removeprefix('_#') return f'{text}' + elif link.startswith('__#'): + return f'' else: return super().link(link, text, title) @@ -118,7 +121,21 @@ def codespan(self, text: str) -> str: else: return super().codespan(text) - def block_code(self, code: str, info: Optional[str] = None) -> str: + def image( + self, + src: str, + alt: str = '', + title: str | None = None, + ) -> str: + return ( + f'{html.escape(alt)}' + ) + + def block_code(self, code: str, info: str | None = None) -> str: copyable = False if info is not None: copyable_s = '#copyable' @@ -136,7 +153,7 @@ def block_code(self, code: str, info: Optional[str] = None) -> str: return ret -def md(s: str) -> str: +def md(s: str) -> markupsafe.Markup: html = markdown_code_blocks.highlight(s, Renderer=Renderer) # manually bless the highlighted output. return markupsafe.Markup(html)