From 0aed5d9fa112d54fdd0cda548ee86ee1528d93aa Mon Sep 17 00:00:00 2001 From: Hades Date: Tue, 24 Feb 2026 13:06:36 +0000 Subject: [PATCH 1/6] ci: add coverage requirement. --- Makefile | 4 ++-- pyproject.toml | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index a3c6b93..c14c64d 100644 --- a/Makefile +++ b/Makefile @@ -31,11 +31,11 @@ test_all: test_unit test_integration test_system # TESTING BY LEVEL test_unit: @uv run python -c "$$PRETTYPRINT_PYSCRIPT" RUNNING UNIT TESTS; \ - uv run pytest --cov=src src/ -x + uv run pytest src/ -x test_integration: @uv run python -c "$$PRETTYPRINT_PYSCRIPT" RUNNING INTEGRATION TESTS; \ - uv run pytest --cov=src tests/*/test_integration_*.py -x + uv run pytest tests/*/test_integration_*.py -x test_system: @uv run python -c "$$PRETTYPRINT_PYSCRIPT" RUNNING SYSTEM TESTS; \ diff --git a/pyproject.toml b/pyproject.toml index 74716d3..a59d874 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,7 +73,9 @@ universal = true [tool.pytest] addopts = [ "--doctest-modules", - "--strict-markers" + "--strict-markers", + "--cov=src", + "--cov-fail-under=38", ] ########## LINTING AND FORMATTING TOOL CONFIGURATION ################################### @@ -102,7 +104,6 @@ select = ["F", "I"] [tool.ruff.lint.isort] lines-between-types = 1 -# force_single_line = "true" [tool.ruff.format] quote-style = "double" From e83b5cf40fa831d808cfa0b14649b7ace3d335cb Mon Sep 17 00:00:00 2001 From: Hades Date: Tue, 24 Feb 2026 14:13:14 +0000 Subject: [PATCH 2/6] ci: run pre-commit linting. --- .github/workflows/pre-commit.yaml | 15 ++++ .pre-commit-config.yaml | 130 ++++++++++++++++++++++-------- Makefile | 6 +- README.md | 102 ++++++++++++----------- 4 files changed, 167 insertions(+), 86 deletions(-) create mode 100644 .github/workflows/pre-commit.yaml diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml new file mode 100644 index 0000000..ed28750 --- /dev/null +++ b/.github/workflows/pre-commit.yaml @@ -0,0 +1,15 @@ +--- +name: pre-commit +on: + pull_request: + push: + branches: [main] +jobs: + pre-commit: + runs-on: ubuntu-latest + env: + SKIP: add-copyright + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 + - uses: pre-commit/action@v3.0.1 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fb11e16..4d6818b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,38 +12,65 @@ exclude: | ) repos: - # GENERAL PURPOSE ################################################################## + # PROCEDURAL ######################################################################## - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: + # Forbid comitting large files - id: check-added-large-files args: [--maxkb=500] + # Forbid names that would conflict in non-case-sensitive filesystems - id: check-case-conflict - - id: check-executables-have-shebangs + # Forbid merge conflict markers - id: check-merge-conflict args: [--assume-in-merge] - - id: check-shebang-scripts-are-executable + # Check that symlinks are up to date - id: check-symlinks - - id: check-vcs-permalinks + # Check for destroyed symlinks - id: destroyed-symlinks - - id: detect-private-key - - id: end-of-file-fixer - - id: fix-byte-order-marker + # Forbid allow submodules - id: forbid-submodules - - id: mixed-line-ending - - id: name-tests-test - args: [--pytest-test-first] + # Don't allow committing to protected branches. - id: no-commit-to-branch args: [-b, main, -b, master, -b, dev, -b, develop] stages: [pre-commit] - - id: trailing-whitespace - args: [--markdown-linebreak-ext=md] - repo: https://github.com/pre-commit/sync-pre-commit-deps rev: v0.0.3 hooks: + # Sync additional dependencies between hooks - id: sync-pre-commit-deps + - repo: https://github.com/commitizen-tools/commitizen + rev: v4.13.8 + hooks: + # Require conventional commit messages + - id: commitizen + + # GENERAL PURPOSE ################################################################### + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + # Forbid executable files without shebangs + - id: check-executables-have-shebangs + # Forbid shebangs in non-executable files + - id: check-shebang-scripts-are-executable + # Require that vcs links are permalinks + - id: check-vcs-permalinks + # Insert blank newlines at the ends of files + - id: end-of-file-fixer + # + - id: fix-byte-order-marker + # Forbid mixed line endings + - id: mixed-line-ending + # Enforce test naming convention + - id: name-tests-test + args: [--pytest-test-first] + exclude: tests/examples/.* + # Remove trailing whitespaces at the ends of lines + - id: trailing-whitespace + args: [--markdown-linebreak-ext=md] + - repo: https://github.com/pre-commit/pygrep-hooks rev: 'v1.10.0' hooks: @@ -52,39 +79,53 @@ repos: - repo: https://github.com/asottile/yesqa rev: v1.5.0 hooks: + # Remove outdated noqa markers - id: yesqa - - repo: https://github.com/asottile/add-trailing-comma - rev: v4.0.0 - hooks: - - id: add-trailing-comma - - - repo: https://github.com/asottile/setup-cfg-fmt - rev: v3.2.0 - hooks: - - id: setup-cfg-fmt - - - repo: https://github.com/commitizen-tools/commitizen - rev: v4.13.8 - hooks: - - id: commitizen - - repo: https://github.com/codespell-project/codespell rev: v2.4.1 hooks: + # Spellchecking - id: codespell args: [-w] - repo: https://github.com/BenjaminMummery/pre-commit-hooks rev: v2.8.0 hooks: + # Add a copyright notice to files that don't have one - id: add-copyright exclude: CHANGELOG.md + # Append jira issue from the branch name to the commit - id: add-msg-issue - - id: update-copyright + # Update existing copyright markers. + # - id: update-copyright + # Sort the .gitignore file (respects sections) - id: sort-file-contents files: .gitignore + # SECURITY ########################################################################## + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: detect-private-key + + - repo: https://github.com/gitleaks/gitleaks + rev: v8.30.0 + hooks: + - id: gitleaks + + - repo: https://github.com/thoughtworks/talisman + rev: 'v1.37.0' + hooks: + - id: talisman-push + - id: talisman-commit + + # CONFIGURATION ##################################################################### + - repo: https://github.com/asottile/setup-cfg-fmt + rev: v3.2.0 + hooks: + - id: setup-cfg-fmt + # C++ ############################################################################### - repo: https://github.com/pre-commit/mirrors-clang-format rev: 'v21.1.8' @@ -99,10 +140,10 @@ repos: - id: cmake-lint # MARKDOWN ######################################################################### - - repo: https://github.com/frnmst/md-toc - rev: 9.0.0 + - repo: https://github.com/thlorenz/doctoc + rev: 'v2.3.0' hooks: - - id: md-toc + - id: doctoc # PYTHON ########################################################################### - repo: https://github.com/pre-commit/pre-commit-hooks @@ -111,6 +152,7 @@ repos: - id: check-ast - id: check-builtin-literals - id: check-docstring-first + exclude: tests/examples/.* - id: debug-statements - id: requirements-txt-fixer @@ -125,6 +167,11 @@ repos: - id: python-no-log-warn - id: python-use-type-annotations + - repo: https://github.com/asottile/add-trailing-comma + rev: v4.0.0 + hooks: + - id: add-trailing-comma + - repo: https://github.com/asottile/pyupgrade rev: v3.21.2 hooks: @@ -161,7 +208,7 @@ repos: hooks: - id: interrogate args: [--config=pyproject.toml] - exclude: test_.*\.py|conftest.py + exclude: tests/.*|test_.*\.py|conftest.py - repo: https://github.com/pycqa/pydocstyle rev: 6.3.0 @@ -169,7 +216,7 @@ repos: - id: pydocstyle args: ['--ignore=D105,D107,D202,D203,D204,D212,D406,D407,D413'] additional_dependencies: [tomli] - exclude: test_.*\.py|conftest.py + exclude: tests/.*|test_.*\.py|conftest.py # YAML ############################################################################# - repo: https://github.com/pre-commit/pre-commit-hooks @@ -230,6 +277,23 @@ repos: --indent 4, ] + # JUPYTER NOTEBOOKS ################################################################# + - repo: https://github.com/nbQA-dev/nbQA + rev: 1.9.1 + hooks: + - id: nbqa-black + - id: nbqa-pyupgrade + args: ["--py37-plus"] + - id: nbqa-isort + args: ["--float-to-top"] + + # TERRAFORM ######################################################################### + - repo: https://github.com/AleksaC/terraform-py + rev: v1.14.5 + hooks: + - id: tf-fmt + - id: tf-validate + # TOML ############################################################################## - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 diff --git a/Makefile b/Makefile index c14c64d..0f61b01 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY : test_unit test_system test_integration +.PHONY: all clean test define PRETTYPRINT_PYSCRIPT import sys, os @@ -40,3 +40,7 @@ test_integration: test_system: @uv run python -c "$$PRETTYPRINT_PYSCRIPT" RUNNING SYSTEM TESTS; \ uv run pytest tests/*/test_system_*.py -x + +# RUNNING PRE-COMMIT HOOKS +lint: + @SKIP=add-copyright uv run pre-commit run --all-files diff --git a/README.md b/README.md index c317ada..818875d 100644 --- a/README.md +++ b/README.md @@ -6,42 +6,41 @@ A selection of quality-of-life tools for use with [pre-commit](https://github.co ## Table of Contents - - -- [pre-commit-hooks](#pre-commit-hooks) - - [Table of Contents](#table-of-contents) - - [1. Usage](#1-usage) - - [1.1 Usage with Pre-Commit](#11-usage-with-pre-commit) - - [1.2 Usage in a vanilla hook](#12-usage-in-a-vanilla-hook) - - [2. Hooks](#2-hooks) - - [2.1 The `add-copyright` Hook](#21-the-add-copyright-hook) - - [2.1.1 Configuration](#211-configuration) - - [CLI Arguments](#cli-arguments) - - [`.pre-commit-config.yaml` Configuration](#pre-commit-configyaml-configuration) - - [Config file configuration](#config-file-configuration) - - [2.1.2 Command line arguments](#212-command-line-arguments) - - [`pyproject.toml`](#pyprojecttoml) - - [2.1.3 `.add-copyright-hook-config.yaml` file](#213-add-copyright-hook-configyaml-file) - - [2.1.4 Language Support](#214-language-support) - - [2.2 The `update-copyright` Hook](#22-the-update-copyright-hook) - - [2.3 The `add-msg-issue` Hook](#23-the-add-msg-issue-hook) - - [2.3.1 Example 1: Usage when defining the commit msg from command line](#231-example-1-usage-when-defining-the-commit-msg-from-command-line) - - [2.3.2 Example 2: Usage when defining the commit msg from editor](#232-example-2-usage-when-defining-the-commit-msg-from-editor) - - [2.3.3 Defining a custom template](#233-defining-a-custom-template) - - [2.4 The `sort-file-contents` hook](#24-the-sort-file-contents-hook) - - [2.4.1 Section - aware sorting](#241-section---aware-sorting) - - [2.4.2 Uniqueness](#242-uniqueness) - - [2.5 The `no-import-testtools-in-src` hook](#25-the-no-import-testtools-in-src-hook) - - [2.6 The `americanise` hook](#26-the-americanise-hook) - - [2.6.1 Configuration](#261-configuration) - - [`.pre-commit-config.yaml` Configuration](#pre-commit-configyaml-configuration-1) - - [Inline ignores](#inline-ignores) - - [3. Development](#3-development) - - [3.1 Testing](#31-testing) - - [3.1.1 Testing scheme](#311-testing-scheme) - - [3.1.2 Running Tests](#312-running-tests) - - + + + +- [1. Usage](#1-usage) + - [1.1 Usage with Pre-Commit](#11-usage-with-pre-commit) + - [1.2 Usage in a vanilla hook](#12-usage-in-a-vanilla-hook) +- [2. Hooks](#2-hooks) + - [2.1 The `add-copyright` Hook](#21-the-add-copyright-hook) + - [2.1.1 Configuration](#211-configuration) + - [CLI Arguments](#cli-arguments) + - [`.pre-commit-config.yaml` Configuration](#pre-commit-configyaml-configuration) + - [Config file configuration](#config-file-configuration) + - [2.1.2 Command line arguments](#212-command-line-arguments) + - [`pyproject.toml`](#pyprojecttoml) + - [2.1.3 `.add-copyright-hook-config.yaml` file](#213-add-copyright-hook-configyaml-file) + - [2.1.4 Language Support](#214-language-support) + - [2.2 The `update-copyright` Hook](#22-the-update-copyright-hook) + - [2.3 The `add-msg-issue` Hook](#23-the-add-msg-issue-hook) + - [2.3.1 Example 1: Usage when defining the commit msg from command line](#231-example-1-usage-when-defining-the-commit-msg-from-command-line) + - [2.3.2 Example 2: Usage when defining the commit msg from editor](#232-example-2-usage-when-defining-the-commit-msg-from-editor) + - [2.3.3 Defining a custom template](#233-defining-a-custom-template) + - [2.4 The `sort-file-contents` hook](#24-the-sort-file-contents-hook) + - [2.4.1 Section - aware sorting](#241-section---aware-sorting) + - [2.4.2 Uniqueness](#242-uniqueness) + - [2.5 The `no-import-testtools-in-src` hook](#25-the-no-import-testtools-in-src-hook) + - [2.6 The `americanise` hook](#26-the-americanise-hook) + - [2.6.1 Configuration](#261-configuration) + - [`.pre-commit-config.yaml` Configuration](#pre-commit-configyaml-configuration-1) + - [Inline ignores](#inline-ignores) +- [3. Development](#3-development) + - [3.1 Testing](#31-testing) + - [3.1.1 Testing scheme](#311-testing-scheme) + - [3.1.2 Running Tests](#312-running-tests) + + ## 1. Usage @@ -217,8 +216,8 @@ The add-copyright hook currently runs on changed source files of the following t | SQL | `.sql` | `-- Copyright (c) 1969 Buzz` | | Swift | `.swift` | `// Copyright (c) 1969 Buzz` | - [^1]: For python files we also support inserting copyright info into/as module-level docstrings. To enable this, insert the following lines into your `pyproject.toml` or `.add-copyright-hook-config.yaml`: + ```yaml [tool.add-copyright.python] docstr=true @@ -229,7 +228,6 @@ The add-copyright hook currently runs on changed source files of the following t Check changed source files for something that looks like a copyright comment. If one is found, the end date is checked against the current date and updated if it is out of date. - ### 2.3 The `add-msg-issue` Hook Search the branch name for something that looks like an issue message, and insert it into the commit message. @@ -258,7 +256,7 @@ You should be greeted with something that looks like: # # On branch feature/TEST-01/demo # Changes to be committed: -# new file: test.py +# new file: test.py # ``` @@ -275,6 +273,7 @@ If the default template is not to your liking, you can define your own by passin - id: add-msg-issue args: ["--template", "{issue_id}: {subject}\n\n{body}"] ``` + The template must include the following keywords: ```python @@ -380,7 +379,6 @@ def initialise(): # pragma: no americanise print("initialize") ``` - ## 3. Development ### 3.1 Testing @@ -388,6 +386,7 @@ def initialise(): # pragma: no americanise #### 3.1.1 Testing scheme Tests are organised in three levels: + 1. Unit: tests for individual methods. All other methods should be mocked. Hooks have a single entry point so are best tested with the integration tests, unit tests should be used where necessary. @@ -395,23 +394,22 @@ Tests are organised in three levels: 3. System: end-to-end tests. Uses the `pre-commit try_repo` facility. - #### 3.1.2 Running Tests The provided `Makefile` defines commands for running various combinations of tests: - General Purpose: - - `test`: run unit and integration tests and show coverage (fail fast). - - `test_all`: as `test`, but also runs system tests (fail fast). - - `clean`: remove the test venv and all temporary files. + - `test`: run unit and integration tests and show coverage (fail fast). + - `test_all`: as `test`, but also runs system tests (fail fast). + - `clean`: remove the test venv and all temporary files. - Testing by Level: run all tests of the specified level and show coverage (fail fast). - - `test_unit` - - `test_integration` - - `test_system` + - `test_unit` + - `test_integration` + - `test_system` - Testing by hook: run all tests for the specified hook and show coverage (fail slow). - - `test_add_copyright` - - `test_add_issue` - - `test_sort_file_contents` - - `test_update_copyright` + - `test_add_copyright` + - `test_add_issue` + - `test_sort_file_contents` + - `test_update_copyright` - Testing shared resources: - - `test_shared`: run all unit tests for utilities on which multiple hooks rely and show coverage (fail fast). + - `test_shared`: run all unit tests for utilities on which multiple hooks rely and show coverage (fail fast). From d370a95b939bcb1709203c5b82c3fe68029e013d Mon Sep 17 00:00:00 2001 From: Hades Date: Tue, 24 Feb 2026 14:13:58 +0000 Subject: [PATCH 3/6] ci: remove style step. This is covered by the pre-commit step. --- .github/workflows/style.yml | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 .github/workflows/style.yml diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml deleted file mode 100644 index 3587101..0000000 --- a/.github/workflows/style.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Style -on: - push: - branches: [main] - pull_request: - branches: [main] -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true -permissions: - contents: read -jobs: - style: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - uses: astral-sh/ruff-action@v3 - with: - src: ./src From 00dda5b74db93fdf16031605f02b24ebd774ebd7 Mon Sep 17 00:00:00 2001 From: Benjamin Mummery Date: Tue, 24 Feb 2026 14:27:05 +0000 Subject: [PATCH 4/6] test: set minimum coverage. --- .github/workflows/python_tests.yml | 4 ++-- Makefile | 4 ++-- pyproject.toml | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/python_tests.yml b/.github/workflows/python_tests.yml index 1867607..302fc88 100644 --- a/.github/workflows/python_tests.yml +++ b/.github/workflows/python_tests.yml @@ -31,7 +31,7 @@ jobs: run: uv sync --locked --all-extras --dev - name: Unit tests with pytest run: | - uv run pytest src + uv run pytest src --cov-fail-under=0 integration_tests: runs-on: ubuntu-latest needs: unit_tests @@ -75,4 +75,4 @@ jobs: run: uv sync --locked --all-extras --dev - name: Unit tests with pytest run: |- - uv run pytest tests/*/test_system_*.py + uv run pytest tests/*/test_system_*.py --cov-fail-under=0 diff --git a/Makefile b/Makefile index 0f61b01..f341456 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ test_all: test_unit test_integration test_system # TESTING BY LEVEL test_unit: @uv run python -c "$$PRETTYPRINT_PYSCRIPT" RUNNING UNIT TESTS; \ - uv run pytest src/ -x + uv run pytest src/ -x --cov-fail-under=0 test_integration: @uv run python -c "$$PRETTYPRINT_PYSCRIPT" RUNNING INTEGRATION TESTS; \ @@ -39,7 +39,7 @@ test_integration: test_system: @uv run python -c "$$PRETTYPRINT_PYSCRIPT" RUNNING SYSTEM TESTS; \ - uv run pytest tests/*/test_system_*.py -x + uv run pytest tests/*/test_system_*.py -x --cov-fail-under=0 # RUNNING PRE-COMMIT HOOKS lint: diff --git a/pyproject.toml b/pyproject.toml index a59d874..28218a4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,13 +69,12 @@ universal = true ########## TESTING TOOL CONFIGURATION ################################################## -# [tool.pytest.ini_options] [tool.pytest] addopts = [ "--doctest-modules", "--strict-markers", "--cov=src", - "--cov-fail-under=38", + "--cov-fail-under=80", ] ########## LINTING AND FORMATTING TOOL CONFIGURATION ################################### From 6ab505e4f13b98e7233646de217825e257abe144 Mon Sep 17 00:00:00 2001 From: Benjamin Mummery Date: Tue, 24 Feb 2026 14:31:53 +0000 Subject: [PATCH 5/6] ci: exclude copyright hooks from ci linting. --- .github/workflows/pre-commit.yaml | 2 +- .pre-commit-config.yaml | 2 +- Makefile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml index ed28750..f48421f 100644 --- a/.github/workflows/pre-commit.yaml +++ b/.github/workflows/pre-commit.yaml @@ -8,7 +8,7 @@ jobs: pre-commit: runs-on: ubuntu-latest env: - SKIP: add-copyright + SKIP: update-copyright steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v3 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4d6818b..1f198bc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -98,7 +98,7 @@ repos: # Append jira issue from the branch name to the commit - id: add-msg-issue # Update existing copyright markers. - # - id: update-copyright + - id: update-copyright # Sort the .gitignore file (respects sections) - id: sort-file-contents files: .gitignore diff --git a/Makefile b/Makefile index f341456..6bba444 100644 --- a/Makefile +++ b/Makefile @@ -43,4 +43,4 @@ test_system: # RUNNING PRE-COMMIT HOOKS lint: - @SKIP=add-copyright uv run pre-commit run --all-files + @SKIP=update-copyright uv run pre-commit run --all-files From c1fccbf3ad8da7e26f9d74e92bde1282c9f84639 Mon Sep 17 00:00:00 2001 From: Benjamin Mummery Date: Tue, 24 Feb 2026 14:42:07 +0000 Subject: [PATCH 6/6] ci: set minimum coverage to 98% --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 28218a4..e0beffd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,7 +74,7 @@ addopts = [ "--doctest-modules", "--strict-markers", "--cov=src", - "--cov-fail-under=80", + "--cov-fail-under=98", ] ########## LINTING AND FORMATTING TOOL CONFIGURATION ###################################