92 lines
2.6 KiB
Python
92 lines
2.6 KiB
Python
# File used in CI to ensure pre-commit dependencies are kept up-to-date.
|
|
|
|
import argparse
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import yaml
|
|
|
|
|
|
pre_commit_file = Path(".pre-commit-config.yaml")
|
|
require_dev = Path("requirements-dev.txt")
|
|
require = Path("requirements.txt")
|
|
|
|
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--update", action="store_true")
|
|
args = parser.parse_args()
|
|
|
|
|
|
def replace_dependency_version(pre_commit_text: str, dependency: str) -> tuple[str, bool]:
|
|
"""
|
|
Regex-based replacement of a dependency version in the pre-commit config file.
|
|
using regex here ensures we only replace the version of the dependency while
|
|
keeping the overall file intact.
|
|
"""
|
|
package_name = dependency.split("==", 1)[0]
|
|
pattern = re.compile(rf"^(\s*-\s+){re.escape(package_name)}==.*$", re.MULTILINE)
|
|
updated_text, replacements = pattern.subn(rf"\1{dependency}", pre_commit_text, count=1)
|
|
return updated_text, replacements > 0 and updated_text != pre_commit_text
|
|
|
|
|
|
with require_dev.open("r") as rfile:
|
|
requirements = rfile.readlines()
|
|
|
|
with require.open("r") as rfile:
|
|
requirements.extend(rfile.readlines())
|
|
|
|
# Extract relevant types only
|
|
supported = ("types-", "SQLAlchemy", "scipy-stubs")
|
|
|
|
# Find relevant dependencies
|
|
# Only keep the first part of the line up to the first space
|
|
type_reqs = [r.strip("\n").split()[0] for r in requirements if r.startswith(supported)]
|
|
|
|
with pre_commit_file.open("r") as file:
|
|
pre_commit_text = file.read()
|
|
|
|
updated = False
|
|
for req in type_reqs:
|
|
pre_commit_text, req_updated = replace_dependency_version(pre_commit_text, req)
|
|
updated = updated or req_updated
|
|
|
|
if args.update and updated:
|
|
with pre_commit_file.open("w") as file:
|
|
file.write(pre_commit_text)
|
|
|
|
with pre_commit_file.open("r") as file:
|
|
f = yaml.load(file, Loader=yaml.SafeLoader)
|
|
|
|
|
|
mypy_repo = [
|
|
repo for repo in f["repos"] if repo["repo"] == "https://github.com/pre-commit/mirrors-mypy"
|
|
]
|
|
|
|
hooks = mypy_repo[0]["hooks"][0]["additional_dependencies"]
|
|
|
|
errors = []
|
|
for hook in hooks:
|
|
if hook not in type_reqs:
|
|
errors.append(f"{hook} is missing in requirements-dev.txt.")
|
|
|
|
for req in type_reqs:
|
|
if req not in hooks:
|
|
errors.append(f"{req} is missing in pre-commit config file.")
|
|
|
|
if updated:
|
|
if args.update:
|
|
errors.append(".pre-commit-config.yaml was updated to match the requirements files.")
|
|
else:
|
|
errors.append(
|
|
".pre-commit-config.yaml is outdated. Run build_helpers/pre_commit_update.py --update."
|
|
)
|
|
|
|
|
|
if errors:
|
|
for e in errors:
|
|
print(e)
|
|
sys.exit(1 if not (args.update and updated) else 0)
|
|
|
|
sys.exit(0)
|