Skip to content

Commit

Permalink
ENH: modify pre-commit config with context manager (#319)
Browse files Browse the repository at this point in the history
* BEHAVIOR: do not run `pre-commit autoupdate` after modifications
* ENH: import test config from actual YAML file
* ENH: modify pre-commit config with context manager
* ENH: perform validation check on pre-commit input
* FEAT: define `Precommit` loader class
* MAINT: ban relative imports
* MAINT: convert `utilities.precommit` to module
* MAINT: split `precommit` utilities into submodules
* MAINT: write tests for pre-commit-config getters
  • Loading branch information
redeboer authored Mar 10, 2024
1 parent fdfdc6e commit 0d7784c
Show file tree
Hide file tree
Showing 32 changed files with 768 additions and 587 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@
"src/compwa_policy/.github/workflows/pr-linting.yml": true,
"src/compwa_policy/.github/workflows/release-drafter.yml": true,
"src/compwa_policy/.template/.gitpod.yml": true,
"src/compwa_policy/.template/.prettierrc": true
"src/compwa_policy/.template/.prettierrc": true,
"tests/**/.pre-commit-config*.yaml": true
},
"telemetry.telemetryLevel": "off",
"yaml.schemas": {
Expand Down
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"obj",
"compwa_policy.check_dev_files.dependabot.DependabotOption",
),
"Frequency": "typing.Literal",
"IO": "typing.IO",
"Iterable": "typing.Iterable",
"K": "typing.TypeVar",
Expand Down
8 changes: 3 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ dependencies = [
"ini2toml",
"nbformat",
"pip-tools",
"pre-commit",
"ruamel.yaml", # better YAML dumping
"tomlkit", # preserve original TOML formatting
'rtoml', # fast, read-only parsing
Expand Down Expand Up @@ -145,10 +144,6 @@ module = ["ruamel.*"]
ignore_missing_imports = true
module = ["nbformat.*"]

[[tool.mypy.overrides]]
ignore_missing_imports = true
module = ["pre_commit.commands.autoupdate.*"]

[tool.pyright]
exclude = [
"**/.git",
Expand Down Expand Up @@ -272,6 +267,9 @@ ignore = [
]
task-tags = ["cspell"]

[tool.ruff.lint.flake8-tidy-imports]
ban-relative-imports = "all"

[tool.ruff.lint.isort]
known-first-party = ["compwa_policy"]
split-on-trailing-comma = false
Expand Down
36 changes: 20 additions & 16 deletions src/compwa_policy/check_dev_files/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@
from argparse import ArgumentParser
from typing import TYPE_CHECKING, Any, Sequence

from compwa_policy.check_dev_files.deprecated import remove_deprecated_tools
from compwa_policy.utilities.executor import Executor

from . import (
from compwa_policy.check_dev_files import (
black,
citation,
commitlint,
Expand All @@ -37,6 +34,9 @@
update_pip_constraints,
vscode,
)
from compwa_policy.check_dev_files.deprecated import remove_deprecated_tools
from compwa_policy.utilities.executor import Executor
from compwa_policy.utilities.precommit import ModifiablePrecommit

if TYPE_CHECKING:
from compwa_policy.utilities.pyproject import PythonVersion
Expand All @@ -50,18 +50,21 @@ def main(argv: Sequence[str] | None = None) -> int:
args.repo_title = args.repo_name
has_notebooks = not args.no_notebooks
dev_python_version = __get_python_version(args.dev_python_version)
with Executor(raise_exception=False) as do:
do(citation.main)
with Executor(
raise_exception=False
) as do, ModifiablePrecommit.load() as precommit_config:
do(citation.main, precommit_config)
do(commitlint.main)
do(conda.main, dev_python_version)
do(cspell.main, args.no_cspell_update)
do(cspell.main, precommit_config, args.no_cspell_update)
do(dependabot.main, args.dependabot)
do(editorconfig.main, args.no_python)
do(editorconfig.main, precommit_config, args.no_python)
if not args.allow_labels:
do(github_labels.main)
if not args.no_github_actions:
do(
github_workflows.main,
precommit_config,
allow_deprecated=args.allow_deprecated_workflows,
doc_apt_packages=_to_list(args.doc_apt_packages),
github_pages=args.github_pages,
Expand All @@ -76,12 +79,12 @@ def main(argv: Sequence[str] | None = None) -> int:
)
if has_notebooks:
do(jupyter.main)
do(nbstripout.main)
do(toml.main) # has to run before pre-commit
do(prettier.main, args.no_prettierrc)
do(nbstripout.main, precommit_config)
do(toml.main, precommit_config) # has to run before pre-commit
do(prettier.main, precommit_config, args.no_prettierrc)
if is_python_repo:
if args.no_ruff:
do(black.main, has_notebooks)
do(black.main, precommit_config, has_notebooks)
if not args.no_github_actions:
do(
release_drafter.main,
Expand All @@ -92,19 +95,20 @@ def main(argv: Sequence[str] | None = None) -> int:
do(mypy.main)
do(pyright.main)
do(pytest.main)
do(pyupgrade.main, args.no_ruff)
do(pyupgrade.main, precommit_config, args.no_ruff)
if not args.no_ruff:
do(ruff.main, has_notebooks)
do(ruff.main, precommit_config, has_notebooks)
if args.pin_requirements != "no":
do(
update_pip_constraints.main,
precommit_config,
frequency=args.pin_requirements,
)
do(readthedocs.main, dev_python_version)
do(remove_deprecated_tools, args.keep_issue_templates)
do(remove_deprecated_tools, precommit_config, args.keep_issue_templates)
do(vscode.main, has_notebooks)
do(gitpod.main, args.no_gitpod, dev_python_version)
do(precommit.main)
do(precommit.main, precommit_config)
do(tox.main, has_notebooks)
return 1 if do.error_messages else 0

Expand Down
22 changes: 9 additions & 13 deletions src/compwa_policy/check_dev_files/black.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,29 @@

from compwa_policy.utilities import CONFIG_PATH, vscode
from compwa_policy.utilities.executor import Executor
from compwa_policy.utilities.precommit import (
Hook,
Repo,
remove_precommit_hook,
update_single_hook_precommit_repo,
)
from compwa_policy.utilities.precommit import ModifiablePrecommit
from compwa_policy.utilities.precommit.struct import Hook, Repo
from compwa_policy.utilities.pyproject import ModifiablePyproject, complies_with_subset
from compwa_policy.utilities.toml import to_toml_array


def main(has_notebooks: bool) -> None:
def main(precommit: ModifiablePrecommit, has_notebooks: bool) -> None:
if not CONFIG_PATH.pyproject.exists():
return
with Executor() as do, ModifiablePyproject.load() as pyproject:
do(_remove_outdated_settings, pyproject)
do(_update_black_settings, pyproject)
do(
remove_precommit_hook,
precommit.remove_hook,
hook_id="black",
repo_url="https://github.com/psf/black",
)
do(
remove_precommit_hook,
precommit.remove_hook,
hook_id="black-jupyter",
repo_url="https://github.com/psf/black",
)
do(_update_precommit_repo, has_notebooks)
do(_update_precommit_repo, precommit, has_notebooks)
do(vscode.add_extension_recommendation, "ms-python.black-formatter")
do(
vscode.update_settings,
Expand All @@ -45,7 +41,7 @@ def main(has_notebooks: bool) -> None:
},
},
)
do(remove_precommit_hook, "nbqa-black")
do(precommit.remove_hook, "nbqa-black")


def _remove_outdated_settings(pyproject: ModifiablePyproject) -> None:
Expand Down Expand Up @@ -78,7 +74,7 @@ def _update_black_settings(pyproject: ModifiablePyproject) -> None:
pyproject.append_to_changelog(msg)


def _update_precommit_repo(has_notebooks: bool) -> None:
def _update_precommit_repo(precommit: ModifiablePrecommit, has_notebooks: bool) -> None:
expected_repo = Repo(
repo="https://github.com/psf/black-pre-commit-mirror",
rev="",
Expand All @@ -91,4 +87,4 @@ def _update_precommit_repo(has_notebooks: bool) -> None:
types_or=YAML(typ="rt").load("[jupyter]"),
)
expected_repo["hooks"].append(black_jupyter)
update_single_hook_precommit_repo(expected_repo)
precommit.update_single_hook_repo(expected_repo)
29 changes: 12 additions & 17 deletions src/compwa_policy/check_dev_files/citation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import json
import os
from textwrap import dedent
from typing import cast
from typing import TYPE_CHECKING, cast

from html2text import HTML2Text
from ruamel.yaml import YAML
Expand All @@ -15,16 +15,13 @@
from compwa_policy.errors import PrecommitError
from compwa_policy.utilities import CONFIG_PATH, vscode
from compwa_policy.utilities.executor import Executor
from compwa_policy.utilities.precommit import (
Hook,
Repo,
find_repo_with_index,
load_roundtrip_precommit_config,
update_single_hook_precommit_repo,
)
from compwa_policy.utilities.precommit.struct import Hook, Repo

if TYPE_CHECKING:
from compwa_policy.utilities.precommit import ModifiablePrecommit

def main() -> None:

def main(precommit: ModifiablePrecommit) -> None:
with Executor() as do:
if CONFIG_PATH.zenodo.exists():
do(convert_zenodo_json)
Expand All @@ -33,7 +30,7 @@ def main() -> None:
if CONFIG_PATH.zenodo.exists():
do(remove_zenodo_json)
do(check_citation_keys)
do(add_json_schema_precommit)
do(add_json_schema_precommit, precommit)
do(vscode.add_extension_recommendation, "redhat.vscode-yaml")
do(update_vscode_settings)

Expand Down Expand Up @@ -168,7 +165,7 @@ def check_citation_keys() -> None:
raise PrecommitError(msg)


def add_json_schema_precommit() -> None:
def add_json_schema_precommit(precommit: ModifiablePrecommit) -> None:
if not CONFIG_PATH.citation.exists():
return
# cspell:ignore jsonschema schemafile
Expand All @@ -184,17 +181,15 @@ def add_json_schema_precommit() -> None:
],
pass_filenames=False,
)
config, yaml = load_roundtrip_precommit_config()
repo_url = "https://github.com/python-jsonschema/check-jsonschema"
idx_and_repo = find_repo_with_index(config, repo_url)
existing_repos = config["repos"]
idx_and_repo = precommit.find_repo_with_index(repo_url)
if idx_and_repo is None:
repo = Repo(
repo=repo_url,
rev="",
hooks=[expected_hook],
)
update_single_hook_precommit_repo(repo)
precommit.update_single_hook_repo(repo)
else:
repo_idx, repo = idx_and_repo
existing_hooks = repo["hooks"]
Expand All @@ -208,11 +203,11 @@ def add_json_schema_precommit() -> None:
existing_hooks.append(expected_hook)
else:
existing_hooks[hook_idx] = expected_hook
existing_repos = precommit.document["repos"]
repos_yaml = cast(CommentedSeq, existing_repos)
repos_yaml.yaml_set_comment_before_after_key(repo_idx + 1, before="\n")
yaml.dump(config, CONFIG_PATH.precommit)
msg = f"Updated check-jsonschema hook in {CONFIG_PATH.precommit}"
raise PrecommitError(msg)
precommit.append_to_changelog(msg)


def update_vscode_settings() -> None:
Expand Down
34 changes: 13 additions & 21 deletions src/compwa_policy/check_dev_files/cspell.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,14 @@
from compwa_policy.errors import PrecommitError
from compwa_policy.utilities import COMPWA_POLICY_DIR, CONFIG_PATH, rename_file, vscode
from compwa_policy.utilities.executor import Executor
from compwa_policy.utilities.precommit import (
Hook,
Repo,
find_repo,
load_precommit_config,
load_roundtrip_precommit_config,
update_single_hook_precommit_repo,
)
from compwa_policy.utilities.precommit.struct import Hook, Repo
from compwa_policy.utilities.readme import add_badge, remove_badge

if TYPE_CHECKING:
from pathlib import Path

from compwa_policy.utilities.precommit import ModifiablePrecommit

__VSCODE_EXTENSION_NAME = "streetsidesoftware.code-spell-checker"

# cspell:ignore pelling
Expand All @@ -44,38 +39,35 @@
__EXPECTED_CONFIG = json.load(__STREAM)


def main(no_cspell_update: bool) -> None:
def main(precommit: ModifiablePrecommit, no_cspell_update: bool) -> None:
rename_file("cspell.json", str(CONFIG_PATH.cspell))
with Executor() as do:
do(_update_cspell_repo_url)
do(_update_cspell_repo_url, precommit)
has_cspell_hook = False
if CONFIG_PATH.cspell.exists():
config = load_precommit_config()
has_cspell_hook = find_repo(config, __REPO_URL) is not None
has_cspell_hook = precommit.find_repo(__REPO_URL) is not None
if not has_cspell_hook:
do(_remove_configuration)
else:
do(_update_precommit_repo)
do(_update_precommit_repo, precommit)
if not no_cspell_update:
do(_update_config_content)
do(_sort_config_entries)
do(add_badge, __BADGE)
do(vscode.add_extension_recommendation, __VSCODE_EXTENSION_NAME)


def _update_cspell_repo_url(path: Path = CONFIG_PATH.precommit) -> None:
def _update_cspell_repo_url(precommit: ModifiablePrecommit) -> None:
old_url_patters = [
r".*/mirrors-cspell(.git)?$",
]
config, yaml = load_roundtrip_precommit_config(path)
for pattern in old_url_patters:
repo = find_repo(config, pattern)
repo = precommit.find_repo(pattern)
if repo is None:
continue
repo["repo"] = __REPO_URL
yaml.dump(config, path)
msg = f"Updated cSpell pre-commit repo URL to {__REPO_URL} in {path}"
raise PrecommitError(msg)
msg = f"Updated cSpell pre-commit repo URL to {__REPO_URL}"
precommit.append_to_changelog(msg)


def _remove_configuration() -> None:
Expand All @@ -101,13 +93,13 @@ def _remove_configuration() -> None:
do(vscode.remove_extension_recommendation, __VSCODE_EXTENSION_NAME)


def _update_precommit_repo() -> None:
def _update_precommit_repo(precommit: ModifiablePrecommit) -> None:
expected_hook = Repo(
repo=__REPO_URL,
rev="",
hooks=[Hook(id="cspell")],
)
update_single_hook_precommit_repo(expected_hook)
precommit.update_single_hook_repo(expected_hook)


def _update_config_content() -> None:
Expand Down
Loading

0 comments on commit 0d7784c

Please sign in to comment.