pre-commit-localupdate 0.1.0__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pre_commit_localupdate-0.1.0/README.md → pre_commit_localupdate-0.2.0/PKG-INFO +47 -6
- pre_commit_localupdate-0.1.0/PKG-INFO → pre_commit_localupdate-0.2.0/README.md +32 -21
- pre_commit_localupdate-0.2.0/pre_commit_localupdate/__init__.py +1 -0
- {pre_commit_localupdate-0.1.0 → pre_commit_localupdate-0.2.0}/pre_commit_localupdate/__main__.py +1 -1
- {pre_commit_localupdate-0.1.0 → pre_commit_localupdate-0.2.0}/pre_commit_localupdate/cli.py +10 -2
- pre_commit_localupdate-0.2.0/pre_commit_localupdate/io.py +42 -0
- pre_commit_localupdate-0.2.0/pre_commit_localupdate/julia.py +98 -0
- {pre_commit_localupdate-0.1.0 → pre_commit_localupdate-0.2.0}/pre_commit_localupdate/pre_commit_config.py +31 -50
- {pre_commit_localupdate-0.1.0 → pre_commit_localupdate-0.2.0}/pyproject.toml +9 -3
- pre_commit_localupdate-0.1.0/pre_commit_localupdate/__init__.py +0 -0
- {pre_commit_localupdate-0.1.0 → pre_commit_localupdate-0.2.0}/LICENSE +0 -0
- {pre_commit_localupdate-0.1.0 → pre_commit_localupdate-0.2.0}/pre_commit_localupdate/logs.py +0 -0
- {pre_commit_localupdate-0.1.0 → pre_commit_localupdate-0.2.0}/pre_commit_localupdate/node.py +0 -0
- {pre_commit_localupdate-0.1.0 → pre_commit_localupdate-0.2.0}/pre_commit_localupdate/package.py +0 -0
- {pre_commit_localupdate-0.1.0 → pre_commit_localupdate-0.2.0}/pre_commit_localupdate/python.py +0 -0
|
@@ -1,10 +1,25 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: pre-commit-localupdate
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: A CLI tool to automatically update additional dependencies within local Python and Node.js hooks in pre-commit config files.
|
|
5
|
+
Author: M. Farzalipour Tabriz
|
|
6
|
+
Classifier: Development Status :: 3 - Alpha
|
|
7
|
+
Classifier: Environment :: Console
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Project-URL: source, https://gitlab.mpcdf.mpg.de/tbz/pre-commit-localupdate.git
|
|
11
|
+
Requires-Python: <3.15,>=3.11
|
|
12
|
+
Requires-Dist: requests>=2.32.5
|
|
13
|
+
Requires-Dist: ruamel-yaml>=0.19.1
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
1
16
|
# pre-commit-localupdate
|
|
2
17
|
|
|
3
|
-
A CLI tool to automatically update dependencies in `pre-commit-config.yml` files. It specifically targets `additional_dependencies` within local Python and Node.js hooks to ensure your tooling stays up-to-date. It also adds version to unversioned packages and pins exact version of loosely defined ones.
|
|
18
|
+
A CLI tool to automatically update dependencies in `pre-commit-config.yml` files. It specifically targets `additional_dependencies` within local Python, Julia, and Node.js hooks to ensure your tooling stays up-to-date. It also adds version to unversioned packages and pins exact version of loosely defined ones.
|
|
4
19
|
|
|
5
20
|
## Installation
|
|
6
21
|
|
|
7
|
-
```
|
|
22
|
+
```shell
|
|
8
23
|
pip install pre-commit-localupdate
|
|
9
24
|
```
|
|
10
25
|
|
|
@@ -12,16 +27,28 @@ pip install pre-commit-localupdate
|
|
|
12
27
|
|
|
13
28
|
To check and update the `additional_dependencies` in your `.pre-commit-config.yaml` file, simply run:
|
|
14
29
|
|
|
15
|
-
```
|
|
30
|
+
```shell
|
|
16
31
|
pre-commit-localupdate
|
|
17
32
|
```
|
|
18
33
|
|
|
19
34
|
By default, the tool looks for `.pre-commit-config.yaml` in the current directory. To specify a custom file path, use the `-c` or `--config` argument:
|
|
20
35
|
|
|
21
|
-
```
|
|
36
|
+
```shell
|
|
22
37
|
pre-commit-localupdate --config path/to/.pre-commit-config.yaml
|
|
23
38
|
```
|
|
24
39
|
|
|
40
|
+
To check the dependencies without updating, use the `--dry-run` flag. The command will exit with a non-zero status code if any package needs updating:
|
|
41
|
+
|
|
42
|
+
```shell
|
|
43
|
+
pre-commit-localupdate --dry-run
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
To get debug output use `--debug` flag:
|
|
47
|
+
|
|
48
|
+
```shell
|
|
49
|
+
pre-commit-localupdate --debug
|
|
50
|
+
```
|
|
51
|
+
|
|
25
52
|
## Example
|
|
26
53
|
|
|
27
54
|
Given a `.pre-commit-config.yaml` with the following content:
|
|
@@ -30,6 +57,13 @@ Given a `.pre-commit-config.yaml` with the following content:
|
|
|
30
57
|
# Comments in the file header are preserved
|
|
31
58
|
---
|
|
32
59
|
repos:
|
|
60
|
+
# External hooks won't be touched. Use 'pre-commit autoupdate' command to update them
|
|
61
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
62
|
+
rev: v2.3.0
|
|
63
|
+
hooks:
|
|
64
|
+
- id: check-yaml
|
|
65
|
+
- id: end-of-file-fixer
|
|
66
|
+
- id: trailing-whitespace
|
|
33
67
|
- repo: local
|
|
34
68
|
hooks:
|
|
35
69
|
# Comment about hooks are preserved
|
|
@@ -42,7 +76,7 @@ repos:
|
|
|
42
76
|
require_serial: true
|
|
43
77
|
types_or: [python, pyi]
|
|
44
78
|
additional_dependencies:
|
|
45
|
-
# Loose version definitions
|
|
79
|
+
# Loose version definitions are pinned to an exact version
|
|
46
80
|
- "black>=25.1.0"
|
|
47
81
|
|
|
48
82
|
- id: mypy
|
|
@@ -79,6 +113,13 @@ Running `pre-commit-localupdate` will update the file to (hypothetical latest ve
|
|
|
79
113
|
# Comments in the file header are preserved
|
|
80
114
|
---
|
|
81
115
|
repos:
|
|
116
|
+
# External hooks won't be touched. Use 'pre-commit autoupdate' command to update them
|
|
117
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
118
|
+
rev: v2.3.0
|
|
119
|
+
hooks:
|
|
120
|
+
- id: check-yaml
|
|
121
|
+
- id: end-of-file-fixer
|
|
122
|
+
- id: trailing-whitespace
|
|
82
123
|
- repo: local
|
|
83
124
|
hooks:
|
|
84
125
|
# Comment about hooks are preserved
|
|
@@ -92,7 +133,7 @@ repos:
|
|
|
92
133
|
require_serial: true
|
|
93
134
|
types_or: [python, pyi]
|
|
94
135
|
additional_dependencies:
|
|
95
|
-
# Loose version definitions
|
|
136
|
+
# Loose version definitions are pinned to an exact version
|
|
96
137
|
- "black==26.1.0"
|
|
97
138
|
|
|
98
139
|
- id: mypy
|
|
@@ -1,25 +1,10 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: pre-commit-localupdate
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: A CLI tool to automatically update `additional_dependencies` within local Python hooks in `pre-commit-config.yml` files.
|
|
5
|
-
Author: M. Farzalipour Tabriz
|
|
6
|
-
Classifier: Development Status :: 3 - Alpha
|
|
7
|
-
Classifier: Environment :: Console
|
|
8
|
-
Classifier: Intended Audience :: Developers
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Project-URL: source, https://gitlab.mpcdf.mpg.de/tbz/pre-commit-localupdate.git
|
|
11
|
-
Requires-Python: <3.15,>=3.10
|
|
12
|
-
Requires-Dist: requests>=2.32.5
|
|
13
|
-
Requires-Dist: ruamel-yaml>=0.19.1
|
|
14
|
-
Description-Content-Type: text/markdown
|
|
15
|
-
|
|
16
1
|
# pre-commit-localupdate
|
|
17
2
|
|
|
18
|
-
A CLI tool to automatically update dependencies in `pre-commit-config.yml` files. It specifically targets `additional_dependencies` within local Python and Node.js hooks to ensure your tooling stays up-to-date. It also adds version to unversioned packages and pins exact version of loosely defined ones.
|
|
3
|
+
A CLI tool to automatically update dependencies in `pre-commit-config.yml` files. It specifically targets `additional_dependencies` within local Python, Julia, and Node.js hooks to ensure your tooling stays up-to-date. It also adds version to unversioned packages and pins exact version of loosely defined ones.
|
|
19
4
|
|
|
20
5
|
## Installation
|
|
21
6
|
|
|
22
|
-
```
|
|
7
|
+
```shell
|
|
23
8
|
pip install pre-commit-localupdate
|
|
24
9
|
```
|
|
25
10
|
|
|
@@ -27,16 +12,28 @@ pip install pre-commit-localupdate
|
|
|
27
12
|
|
|
28
13
|
To check and update the `additional_dependencies` in your `.pre-commit-config.yaml` file, simply run:
|
|
29
14
|
|
|
30
|
-
```
|
|
15
|
+
```shell
|
|
31
16
|
pre-commit-localupdate
|
|
32
17
|
```
|
|
33
18
|
|
|
34
19
|
By default, the tool looks for `.pre-commit-config.yaml` in the current directory. To specify a custom file path, use the `-c` or `--config` argument:
|
|
35
20
|
|
|
36
|
-
```
|
|
21
|
+
```shell
|
|
37
22
|
pre-commit-localupdate --config path/to/.pre-commit-config.yaml
|
|
38
23
|
```
|
|
39
24
|
|
|
25
|
+
To check the dependencies without updating, use the `--dry-run` flag. The command will exit with a non-zero status code if any package needs updating:
|
|
26
|
+
|
|
27
|
+
```shell
|
|
28
|
+
pre-commit-localupdate --dry-run
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
To get debug output use `--debug` flag:
|
|
32
|
+
|
|
33
|
+
```shell
|
|
34
|
+
pre-commit-localupdate --debug
|
|
35
|
+
```
|
|
36
|
+
|
|
40
37
|
## Example
|
|
41
38
|
|
|
42
39
|
Given a `.pre-commit-config.yaml` with the following content:
|
|
@@ -45,6 +42,13 @@ Given a `.pre-commit-config.yaml` with the following content:
|
|
|
45
42
|
# Comments in the file header are preserved
|
|
46
43
|
---
|
|
47
44
|
repos:
|
|
45
|
+
# External hooks won't be touched. Use 'pre-commit autoupdate' command to update them
|
|
46
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
47
|
+
rev: v2.3.0
|
|
48
|
+
hooks:
|
|
49
|
+
- id: check-yaml
|
|
50
|
+
- id: end-of-file-fixer
|
|
51
|
+
- id: trailing-whitespace
|
|
48
52
|
- repo: local
|
|
49
53
|
hooks:
|
|
50
54
|
# Comment about hooks are preserved
|
|
@@ -57,7 +61,7 @@ repos:
|
|
|
57
61
|
require_serial: true
|
|
58
62
|
types_or: [python, pyi]
|
|
59
63
|
additional_dependencies:
|
|
60
|
-
# Loose version definitions
|
|
64
|
+
# Loose version definitions are pinned to an exact version
|
|
61
65
|
- "black>=25.1.0"
|
|
62
66
|
|
|
63
67
|
- id: mypy
|
|
@@ -94,6 +98,13 @@ Running `pre-commit-localupdate` will update the file to (hypothetical latest ve
|
|
|
94
98
|
# Comments in the file header are preserved
|
|
95
99
|
---
|
|
96
100
|
repos:
|
|
101
|
+
# External hooks won't be touched. Use 'pre-commit autoupdate' command to update them
|
|
102
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
103
|
+
rev: v2.3.0
|
|
104
|
+
hooks:
|
|
105
|
+
- id: check-yaml
|
|
106
|
+
- id: end-of-file-fixer
|
|
107
|
+
- id: trailing-whitespace
|
|
97
108
|
- repo: local
|
|
98
109
|
hooks:
|
|
99
110
|
# Comment about hooks are preserved
|
|
@@ -107,7 +118,7 @@ repos:
|
|
|
107
118
|
require_serial: true
|
|
108
119
|
types_or: [python, pyi]
|
|
109
120
|
additional_dependencies:
|
|
110
|
-
# Loose version definitions
|
|
121
|
+
# Loose version definitions are pinned to an exact version
|
|
111
122
|
- "black==26.1.0"
|
|
112
123
|
|
|
113
124
|
- id: mypy
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '0.2.0'
|
{pre_commit_localupdate-0.1.0 → pre_commit_localupdate-0.2.0}/pre_commit_localupdate/__main__.py
RENAMED
|
@@ -24,7 +24,7 @@ def main() -> None:
|
|
|
24
24
|
args = parse_args()
|
|
25
25
|
setup_logging(args.debug)
|
|
26
26
|
|
|
27
|
-
if update_additional_dependencies(Path(args.config)):
|
|
27
|
+
if update_additional_dependencies(Path(args.config), dry_run=args.dry_run):
|
|
28
28
|
logging.info("Done.")
|
|
29
29
|
else:
|
|
30
30
|
logging.info("File content is already up to date.")
|
|
@@ -2,18 +2,24 @@
|
|
|
2
2
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
3
3
|
|
|
4
4
|
import argparse
|
|
5
|
+
from pre_commit_localupdate import __version__
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
def parse_args() -> argparse.Namespace:
|
|
8
9
|
"""Parse command line arguments."""
|
|
9
10
|
parser = argparse.ArgumentParser(
|
|
10
|
-
description="
|
|
11
|
+
description="Automatically update additional dependencies within local Python and Node.js hooks in pre-commit config files."
|
|
11
12
|
)
|
|
12
13
|
parser.add_argument(
|
|
13
14
|
"--debug",
|
|
14
15
|
action="store_true",
|
|
15
16
|
help="Enable debug logging",
|
|
16
17
|
)
|
|
18
|
+
parser.add_argument(
|
|
19
|
+
"--dry-run",
|
|
20
|
+
action="store_true",
|
|
21
|
+
help="Dry run mode. Do not update the file and exit with a non-zero code if the configuration files require an update.",
|
|
22
|
+
)
|
|
17
23
|
parser.add_argument(
|
|
18
24
|
"-c",
|
|
19
25
|
"--config",
|
|
@@ -21,5 +27,7 @@ def parse_args() -> argparse.Namespace:
|
|
|
21
27
|
help="pre-commit config file path",
|
|
22
28
|
default=".pre-commit-config.yaml",
|
|
23
29
|
)
|
|
24
|
-
|
|
30
|
+
parser.add_argument(
|
|
31
|
+
"--version", action="version", version=f"pre-commit-localupdate {__version__}"
|
|
32
|
+
)
|
|
25
33
|
return parser.parse_args()
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 M. Farzalipour Tabriz, Max Planck Institute for Physics
|
|
2
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
3
|
+
|
|
4
|
+
import logging
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import sys
|
|
7
|
+
from typing import List, Tuple
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def load_config_file(file_path: Path) -> Tuple[List[str], str]:
|
|
11
|
+
logging.debug("Reading configuration file: %s", file_path)
|
|
12
|
+
|
|
13
|
+
raw_lines: List[str] = []
|
|
14
|
+
header_lines: List[str] = []
|
|
15
|
+
yaml_start_index: int = 0
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
with file_path.open("r", encoding="utf-8") as f:
|
|
19
|
+
raw_lines = f.readlines()
|
|
20
|
+
except FileNotFoundError:
|
|
21
|
+
logging.exception("File not found: %s", file_path)
|
|
22
|
+
sys.exit(2)
|
|
23
|
+
except OSError as exc:
|
|
24
|
+
logging.exception("IOError while reading file %s: %s", file_path, exc)
|
|
25
|
+
sys.exit(2)
|
|
26
|
+
|
|
27
|
+
logging.debug("Parsing document header...")
|
|
28
|
+
yaml_start_index = 0
|
|
29
|
+
for i, line in enumerate(raw_lines):
|
|
30
|
+
stripped: str = line.strip()
|
|
31
|
+
if stripped == "---":
|
|
32
|
+
logging.debug("YAML marker found.")
|
|
33
|
+
yaml_start_index = i + 1
|
|
34
|
+
break
|
|
35
|
+
if stripped and not stripped.startswith("#"):
|
|
36
|
+
yaml_start_index = i
|
|
37
|
+
break
|
|
38
|
+
|
|
39
|
+
header_lines = raw_lines[:yaml_start_index]
|
|
40
|
+
yaml_content: str = "".join(raw_lines[yaml_start_index:])
|
|
41
|
+
|
|
42
|
+
return header_lines, yaml_content
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 M. Farzalipour Tabriz, Max Planck Institute for Physics
|
|
2
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
3
|
+
|
|
4
|
+
import logging
|
|
5
|
+
import re
|
|
6
|
+
import tomllib
|
|
7
|
+
import requests
|
|
8
|
+
|
|
9
|
+
from pre_commit_localupdate.package import PackageBase
|
|
10
|
+
|
|
11
|
+
# Julia General Registry Source
|
|
12
|
+
JULIA_PKG_API_URL = "https://raw.githubusercontent.com/JuliaRegistries/General/refs/heads/master/{package_name_first_letter}/{package_name}/Versions.toml"
|
|
13
|
+
REQUEST_TIMEOUT = 10
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class JuliaPackage(PackageBase):
|
|
17
|
+
"""Represents a Julia package."""
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def from_specification(package, spec: str) -> "JuliaPackage" | None:
|
|
21
|
+
"""Parse a package specification string into a Package object.
|
|
22
|
+
|
|
23
|
+
Handles formats like 'Example@0.4.1', 'Example@0.4', or just 'Example'.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
spec: The package specification string.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
A Package instance if parsing succeeds, otherwise None.
|
|
30
|
+
|
|
31
|
+
"""
|
|
32
|
+
clean_spec = spec.strip().strip('"').strip("'")
|
|
33
|
+
match = re.match(r"^([a-zA-Z0-9_]+)(?:@([a-zA-Z0-9._+,-]+))?$", clean_spec)
|
|
34
|
+
|
|
35
|
+
if not match:
|
|
36
|
+
logging.warning("Could not parse the package specification: %s", clean_spec)
|
|
37
|
+
return None
|
|
38
|
+
|
|
39
|
+
name = match.group(1)
|
|
40
|
+
raw_spec = match.group(2)
|
|
41
|
+
latest_version = package._get_latest_version(name)
|
|
42
|
+
|
|
43
|
+
return package(
|
|
44
|
+
name=name,
|
|
45
|
+
raw_spec=raw_spec,
|
|
46
|
+
latest_version=latest_version,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
@staticmethod
|
|
50
|
+
def _get_latest_version(package_name: str) -> str | None:
|
|
51
|
+
"""Fetch the latest version of a package from the Julia General Registry.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
The latest version string if found, otherwise None.
|
|
55
|
+
|
|
56
|
+
"""
|
|
57
|
+
logging.debug("Fetching latest version for %s", package_name)
|
|
58
|
+
try:
|
|
59
|
+
url = JULIA_PKG_API_URL.format(
|
|
60
|
+
package_name=package_name, package_name_first_letter=package_name[0]
|
|
61
|
+
)
|
|
62
|
+
response = requests.get(url, timeout=REQUEST_TIMEOUT)
|
|
63
|
+
response.raise_for_status()
|
|
64
|
+
|
|
65
|
+
data = tomllib.loads(response.text)
|
|
66
|
+
|
|
67
|
+
versions = list(data.keys())
|
|
68
|
+
if not versions:
|
|
69
|
+
return None
|
|
70
|
+
|
|
71
|
+
versions.sort(reverse=True)
|
|
72
|
+
latest = versions[0]
|
|
73
|
+
|
|
74
|
+
if latest and isinstance(latest, str):
|
|
75
|
+
return latest
|
|
76
|
+
|
|
77
|
+
return None
|
|
78
|
+
except requests.exceptions.RequestException as exc:
|
|
79
|
+
logging.warning(
|
|
80
|
+
"Could not fetch latest version for %s: %s", package_name, exc
|
|
81
|
+
)
|
|
82
|
+
return None
|
|
83
|
+
except (KeyError, ValueError, tomllib.TOMLDecodeError) as exc:
|
|
84
|
+
logging.warning("Could not parse response for %s: %s", package_name, exc)
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
def latest_version_specification(package) -> str | None:
|
|
88
|
+
"""Version specification of package pinned to the latest version.
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
The latest version specification string if found, otherwise None.
|
|
92
|
+
Format: PackageName@version
|
|
93
|
+
|
|
94
|
+
"""
|
|
95
|
+
if not package.latest_version:
|
|
96
|
+
return None
|
|
97
|
+
|
|
98
|
+
return f"{package.name}@{package.latest_version}"
|
|
@@ -4,20 +4,24 @@
|
|
|
4
4
|
import io
|
|
5
5
|
import logging
|
|
6
6
|
from pathlib import Path
|
|
7
|
+
import sys
|
|
7
8
|
|
|
8
9
|
import ruamel.yaml
|
|
9
10
|
|
|
10
11
|
from pre_commit_localupdate.node import NodePackage
|
|
11
12
|
from pre_commit_localupdate.package import PackageBase
|
|
12
13
|
from pre_commit_localupdate.python import PyPackage
|
|
14
|
+
from pre_commit_localupdate.julia import JuliaPackage
|
|
15
|
+
from pre_commit_localupdate.io import load_config_file
|
|
13
16
|
|
|
14
17
|
LANGUAGE_PACKAGE_MAP: dict[str, type[PackageBase]] = {
|
|
15
18
|
"python": PyPackage,
|
|
16
19
|
"node": NodePackage,
|
|
20
|
+
"julia": JuliaPackage,
|
|
17
21
|
}
|
|
18
22
|
|
|
19
23
|
|
|
20
|
-
def update_additional_dependencies(file_path: Path) -> bool:
|
|
24
|
+
def update_additional_dependencies(file_path: Path, *, dry_run: bool = False) -> bool:
|
|
21
25
|
"""Reads the configuration file, identifies outdated Python packages in
|
|
22
26
|
local hooks, and updates them directly in the file.
|
|
23
27
|
|
|
@@ -31,38 +35,10 @@ def update_additional_dependencies(file_path: Path) -> bool:
|
|
|
31
35
|
True if the file was modified and successfully written, False otherwise.
|
|
32
36
|
|
|
33
37
|
"""
|
|
34
|
-
logging.debug("Reading configuration file: %s", file_path)
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
header_lines = []
|
|
38
|
-
yaml_start_index = 0
|
|
39
|
-
|
|
40
|
-
try:
|
|
41
|
-
with file_path.open("r", encoding="utf-8") as f:
|
|
42
|
-
raw_lines = f.readlines()
|
|
43
|
-
except FileNotFoundError:
|
|
44
|
-
logging.exception("File not found: %s", file_path)
|
|
45
|
-
return False
|
|
46
|
-
except OSError as exc:
|
|
47
|
-
logging.exception("IOError while reading file %s: %s", file_path, exc)
|
|
48
|
-
return False
|
|
49
|
-
|
|
50
|
-
logging.debug("Parsing document header...")
|
|
51
|
-
yaml_start_index = 0
|
|
52
|
-
for i, line in enumerate(raw_lines):
|
|
53
|
-
stripped = line.strip()
|
|
54
|
-
if stripped == "---":
|
|
55
|
-
logging.debug("YAML marker found.")
|
|
56
|
-
yaml_start_index = i + 1
|
|
57
|
-
break
|
|
58
|
-
if stripped and not stripped.startswith("#"):
|
|
59
|
-
yaml_start_index = i
|
|
60
|
-
break
|
|
61
|
-
|
|
62
|
-
header_lines = raw_lines[:yaml_start_index]
|
|
39
|
+
header_lines, yaml_content = load_config_file(file_path)
|
|
63
40
|
|
|
64
41
|
logging.debug("Parsing YAML content...")
|
|
65
|
-
yaml_content = "".join(raw_lines[yaml_start_index:])
|
|
66
42
|
|
|
67
43
|
yaml = ruamel.yaml.YAML()
|
|
68
44
|
yaml.preserve_quotes = True
|
|
@@ -76,13 +52,13 @@ def update_additional_dependencies(file_path: Path) -> bool:
|
|
|
76
52
|
config = yaml.load(yaml_content)
|
|
77
53
|
except Exception as exc:
|
|
78
54
|
logging.exception("Failed to parse YAML content from %s: %s", file_path, exc)
|
|
79
|
-
|
|
55
|
+
sys.exit(2)
|
|
80
56
|
|
|
81
57
|
if config is None:
|
|
82
58
|
logging.warning("Configuration file is empty or could not be parsed.")
|
|
83
|
-
|
|
59
|
+
sys.exit(2)
|
|
84
60
|
|
|
85
|
-
|
|
61
|
+
update_required = False
|
|
86
62
|
|
|
87
63
|
if "repos" in config:
|
|
88
64
|
logging.debug("Scanning repositories for local hooks")
|
|
@@ -123,7 +99,7 @@ def update_additional_dependencies(file_path: Path) -> bool:
|
|
|
123
99
|
!= package.version_specification()
|
|
124
100
|
):
|
|
125
101
|
logging.info(
|
|
126
|
-
"
|
|
102
|
+
"%s needs updating to %s",
|
|
127
103
|
package.version_specification(),
|
|
128
104
|
package.latest_version_specification(),
|
|
129
105
|
)
|
|
@@ -131,7 +107,7 @@ def update_additional_dependencies(file_path: Path) -> bool:
|
|
|
131
107
|
i
|
|
132
108
|
] = package.latest_version_specification()
|
|
133
109
|
|
|
134
|
-
|
|
110
|
+
update_required = True
|
|
135
111
|
else:
|
|
136
112
|
logging.debug(
|
|
137
113
|
"%s is already correctly defined and up to date (%s).",
|
|
@@ -139,20 +115,25 @@ def update_additional_dependencies(file_path: Path) -> bool:
|
|
|
139
115
|
package.version_specification(),
|
|
140
116
|
)
|
|
141
117
|
|
|
142
|
-
if
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
118
|
+
if update_required:
|
|
119
|
+
if dry_run:
|
|
120
|
+
sys.exit(1)
|
|
121
|
+
else:
|
|
122
|
+
logging.debug("Writing modified content to disk")
|
|
123
|
+
try:
|
|
124
|
+
stream = io.StringIO()
|
|
125
|
+
yaml.dump(config, stream)
|
|
126
|
+
modified_body = stream.getvalue()
|
|
127
|
+
final_content = "".join(header_lines) + modified_body
|
|
128
|
+
|
|
129
|
+
with file_path.open("w", encoding="utf-8") as f:
|
|
130
|
+
f.write(final_content)
|
|
131
|
+
logging.info("Successfully updated %s", file_path)
|
|
132
|
+
return True
|
|
133
|
+
except OSError as exc:
|
|
134
|
+
logging.exception(
|
|
135
|
+
"IOError while writing to file %s: %s", file_path, exc
|
|
136
|
+
)
|
|
137
|
+
return False
|
|
157
138
|
|
|
158
139
|
return False
|
|
@@ -23,11 +23,12 @@ dependencies = [
|
|
|
23
23
|
"requests>=2.32.5",
|
|
24
24
|
"ruamel-yaml>=0.19.1",
|
|
25
25
|
]
|
|
26
|
-
description = "A CLI tool to automatically update
|
|
26
|
+
description = "A CLI tool to automatically update additional dependencies within local Python and Node.js hooks in pre-commit config files."
|
|
27
|
+
dynamic = []
|
|
27
28
|
name = "pre-commit-localupdate"
|
|
28
29
|
readme = "README.md"
|
|
29
|
-
requires-python = "<3.15,>=3.
|
|
30
|
-
version = "0.
|
|
30
|
+
requires-python = "<3.15,>=3.11"
|
|
31
|
+
version = "0.2.0"
|
|
31
32
|
|
|
32
33
|
[project.scripts]
|
|
33
34
|
pre-commit-localupdate = "pre_commit_localupdate.__main__:main"
|
|
@@ -35,6 +36,11 @@ pre-commit-localupdate = "pre_commit_localupdate.__main__:main"
|
|
|
35
36
|
[project.urls]
|
|
36
37
|
source = "https://gitlab.mpcdf.mpg.de/tbz/pre-commit-localupdate.git"
|
|
37
38
|
|
|
39
|
+
[tool.pdm.version]
|
|
40
|
+
source = "scm"
|
|
41
|
+
write_template = "__version__ = '{}'"
|
|
42
|
+
write_to = "pre_commit_localupdate/__init__.py"
|
|
43
|
+
|
|
38
44
|
[tool.tomlsort]
|
|
39
45
|
sort_table_keys = true
|
|
40
46
|
trailing_comma_inline_array = true
|
|
File without changes
|
|
File without changes
|
{pre_commit_localupdate-0.1.0 → pre_commit_localupdate-0.2.0}/pre_commit_localupdate/logs.py
RENAMED
|
File without changes
|
{pre_commit_localupdate-0.1.0 → pre_commit_localupdate-0.2.0}/pre_commit_localupdate/node.py
RENAMED
|
File without changes
|
{pre_commit_localupdate-0.1.0 → pre_commit_localupdate-0.2.0}/pre_commit_localupdate/package.py
RENAMED
|
File without changes
|
{pre_commit_localupdate-0.1.0 → pre_commit_localupdate-0.2.0}/pre_commit_localupdate/python.py
RENAMED
|
File without changes
|