pre-commit-localupdate 0.3.0__tar.gz → 0.4.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.3.0 → pre_commit_localupdate-0.4.0}/PKG-INFO +51 -59
- {pre_commit_localupdate-0.3.0 → pre_commit_localupdate-0.4.0}/README.md +49 -57
- pre_commit_localupdate-0.4.0/pre_commit_localupdate/__init__.py +1 -0
- pre_commit_localupdate-0.4.0/pre_commit_localupdate/__main__.py +42 -0
- {pre_commit_localupdate-0.3.0 → pre_commit_localupdate-0.4.0}/pre_commit_localupdate/cli.py +5 -3
- pre_commit_localupdate-0.4.0/pre_commit_localupdate/error.py +6 -0
- {pre_commit_localupdate-0.3.0 → pre_commit_localupdate-0.4.0}/pre_commit_localupdate/io.py +10 -10
- {pre_commit_localupdate-0.3.0 → pre_commit_localupdate-0.4.0}/pre_commit_localupdate/logs.py +1 -1
- {pre_commit_localupdate-0.3.0 → pre_commit_localupdate-0.4.0}/pre_commit_localupdate/packages/__init__.py +2 -0
- pre_commit_localupdate-0.4.0/pre_commit_localupdate/packages/golang.py +124 -0
- {pre_commit_localupdate-0.3.0 → pre_commit_localupdate-0.4.0}/pre_commit_localupdate/pre_commit_config.py +56 -31
- {pre_commit_localupdate-0.3.0 → pre_commit_localupdate-0.4.0}/pyproject.toml +2 -2
- pre_commit_localupdate-0.3.0/pre_commit_localupdate/__init__.py +0 -1
- pre_commit_localupdate-0.3.0/pre_commit_localupdate/__main__.py +0 -34
- {pre_commit_localupdate-0.3.0 → pre_commit_localupdate-0.4.0}/LICENSE +0 -0
- {pre_commit_localupdate-0.3.0 → pre_commit_localupdate-0.4.0}/pre_commit_localupdate/packages/julia.py +0 -0
- {pre_commit_localupdate-0.3.0 → pre_commit_localupdate-0.4.0}/pre_commit_localupdate/packages/node.py +0 -0
- {pre_commit_localupdate-0.3.0 → pre_commit_localupdate-0.4.0}/pre_commit_localupdate/packages/package.py +0 -0
- {pre_commit_localupdate-0.3.0 → pre_commit_localupdate-0.4.0}/pre_commit_localupdate/packages/python.py +0 -0
- {pre_commit_localupdate-0.3.0 → pre_commit_localupdate-0.4.0}/pre_commit_localupdate/packages/rust.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pre-commit-localupdate
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: A CLI tool to automatically update additional dependencies within local Python, Julia, Rust, and Node.js hooks in pre-commit config files.
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: A CLI tool to automatically update additional dependencies within local Python, Julia, Rust, Go, and Node.js hooks in pre-commit config files.
|
|
5
5
|
Author: M. Farzalipour Tabriz
|
|
6
6
|
Classifier: Development Status :: 3 - Alpha
|
|
7
7
|
Classifier: Environment :: Console
|
|
@@ -15,7 +15,7 @@ Description-Content-Type: text/markdown
|
|
|
15
15
|
|
|
16
16
|
# pre-commit-localupdate
|
|
17
17
|
|
|
18
|
-
A CLI tool to automatically update dependencies in `pre-commit-config.yml` files. It specifically targets `additional_dependencies` within local Python, Julia, Rust, 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, Rust, Go, 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. You can also pin a specific package to an older version by adding a `# freeze` comment.
|
|
19
19
|
|
|
20
20
|
## Installation
|
|
21
21
|
|
|
@@ -54,19 +54,19 @@ pre-commit-localupdate --debug
|
|
|
54
54
|
Given a `.pre-commit-config.yaml` with the following content:
|
|
55
55
|
|
|
56
56
|
```yaml
|
|
57
|
-
#
|
|
57
|
+
# File header is preserved. If there is no document start marker (---), it won't be added
|
|
58
58
|
---
|
|
59
59
|
repos:
|
|
60
60
|
# External hooks won't be touched. Use 'pre-commit autoupdate' command to update them
|
|
61
61
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
62
62
|
rev: v2.3.0
|
|
63
63
|
hooks:
|
|
64
|
-
- id: check-yaml
|
|
65
64
|
- id: end-of-file-fixer
|
|
66
65
|
- id: trailing-whitespace
|
|
66
|
+
|
|
67
67
|
- repo: local
|
|
68
68
|
hooks:
|
|
69
|
-
#
|
|
69
|
+
# All comment are preserved
|
|
70
70
|
- id: black
|
|
71
71
|
name: black
|
|
72
72
|
description: "Long strings are automatically folded into multilines by ruamel-yaml library!"
|
|
@@ -78,51 +78,45 @@ repos:
|
|
|
78
78
|
additional_dependencies:
|
|
79
79
|
# Loose version definitions are pinned to an exact version
|
|
80
80
|
- "black>=25.1.0"
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
minimum_pre_commit_version: '2.9.2'
|
|
81
|
+
# Updates can be prevented by adding a 'freeze' comment to them as:
|
|
82
|
+
- "white==0.1.0" # freeze
|
|
83
|
+
|
|
84
|
+
- id: julia-format
|
|
85
|
+
name: format julia code
|
|
86
|
+
description: Run `JuliaFormatter.jl` against Julia source files
|
|
87
|
+
language: julia
|
|
88
|
+
types: [julia]
|
|
89
|
+
entry: tools/formatter.jl
|
|
91
90
|
additional_dependencies:
|
|
92
|
-
# Double/single quoting style is preserved
|
|
93
|
-
- '
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
language: python
|
|
102
|
-
types_or: [python, pyi]
|
|
103
|
-
args: ["--strict"]
|
|
104
|
-
require_serial: true
|
|
105
|
-
minimum_pre_commit_version: '2.9.2'
|
|
91
|
+
# Double/single quoting style is preserved and version is added to packages with no version definition
|
|
92
|
+
- 'JuliaFormatter'
|
|
93
|
+
|
|
94
|
+
- id: mdbook-lint
|
|
95
|
+
name: mdbook-lint
|
|
96
|
+
description: rust package to lint markdown
|
|
97
|
+
entry: mdbook-lint lint --fix
|
|
98
|
+
language: rust
|
|
99
|
+
types: [markdown]
|
|
106
100
|
# Updating packages defined in flow style is also supported
|
|
107
|
-
additional_dependencies: [
|
|
101
|
+
additional_dependencies: ["cli:mdbook-lint"]
|
|
108
102
|
```
|
|
109
103
|
|
|
110
104
|
Running `pre-commit-localupdate` will update the file to (hypothetical latest versions):
|
|
111
105
|
|
|
112
106
|
```yaml
|
|
113
|
-
#
|
|
107
|
+
# File header is preserved. If there is no document start marker (---), it won't be added
|
|
114
108
|
---
|
|
115
109
|
repos:
|
|
116
110
|
# External hooks won't be touched. Use 'pre-commit autoupdate' command to update them
|
|
117
111
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
118
112
|
rev: v2.3.0
|
|
119
113
|
hooks:
|
|
120
|
-
- id: check-yaml
|
|
121
114
|
- id: end-of-file-fixer
|
|
122
115
|
- id: trailing-whitespace
|
|
116
|
+
|
|
123
117
|
- repo: local
|
|
124
118
|
hooks:
|
|
125
|
-
#
|
|
119
|
+
# All comment are preserved
|
|
126
120
|
- id: black
|
|
127
121
|
name: black
|
|
128
122
|
description: "Long strings are automatically folded into multilines by ruamel-yaml
|
|
@@ -135,35 +129,33 @@ repos:
|
|
|
135
129
|
additional_dependencies:
|
|
136
130
|
# Loose version definitions are pinned to an exact version
|
|
137
131
|
- "black==26.1.0"
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
minimum_pre_commit_version: '2.9.2'
|
|
132
|
+
# Updates can be prevented by adding a 'freeze' comment to them as:
|
|
133
|
+
- "white==0.1.0" # freeze
|
|
134
|
+
|
|
135
|
+
- id: julia-format
|
|
136
|
+
name: format julia code
|
|
137
|
+
description: Run `JuliaFormatter.jl` against Julia source files
|
|
138
|
+
language: julia
|
|
139
|
+
types: [julia]
|
|
140
|
+
entry: tools/formatter.jl
|
|
148
141
|
additional_dependencies:
|
|
149
|
-
# Double/single quoting style is preserved
|
|
150
|
-
- '
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
language: python
|
|
159
|
-
types_or: [python, pyi]
|
|
160
|
-
args: ["--strict"]
|
|
161
|
-
require_serial: true
|
|
162
|
-
minimum_pre_commit_version: '2.9.2'
|
|
142
|
+
# Double/single quoting style is preserved and version is added to packages with no version definition
|
|
143
|
+
- 'JuliaFormatter@2.3.0'
|
|
144
|
+
|
|
145
|
+
- id: mdbook-lint
|
|
146
|
+
name: mdbook-lint
|
|
147
|
+
description: rust package to lint markdown
|
|
148
|
+
entry: mdbook-lint lint --fix
|
|
149
|
+
language: rust
|
|
150
|
+
types: [markdown]
|
|
163
151
|
# Updating packages defined in flow style is also supported
|
|
164
|
-
additional_dependencies: [
|
|
152
|
+
additional_dependencies: ["cli:mdbook-lint:0.14.2"]
|
|
165
153
|
```
|
|
166
154
|
|
|
155
|
+
## Formatting
|
|
156
|
+
|
|
157
|
+
A considerable amount of effort has been put into making `pre-commit-localupdate` respect the original style and preserve the comments in the pre-commit configuration files. Although it is currently folding long strings (for example, in description lines) and enforcing block indentation for better readability.
|
|
158
|
+
|
|
167
159
|
## Requirements
|
|
168
160
|
|
|
169
161
|
- ruamel.yaml
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pre-commit-localupdate
|
|
2
2
|
|
|
3
|
-
A CLI tool to automatically update dependencies in `pre-commit-config.yml` files. It specifically targets `additional_dependencies` within local Python, Julia, Rust, 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, Rust, Go, 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. You can also pin a specific package to an older version by adding a `# freeze` comment.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -39,19 +39,19 @@ pre-commit-localupdate --debug
|
|
|
39
39
|
Given a `.pre-commit-config.yaml` with the following content:
|
|
40
40
|
|
|
41
41
|
```yaml
|
|
42
|
-
#
|
|
42
|
+
# File header is preserved. If there is no document start marker (---), it won't be added
|
|
43
43
|
---
|
|
44
44
|
repos:
|
|
45
45
|
# External hooks won't be touched. Use 'pre-commit autoupdate' command to update them
|
|
46
46
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
47
47
|
rev: v2.3.0
|
|
48
48
|
hooks:
|
|
49
|
-
- id: check-yaml
|
|
50
49
|
- id: end-of-file-fixer
|
|
51
50
|
- id: trailing-whitespace
|
|
51
|
+
|
|
52
52
|
- repo: local
|
|
53
53
|
hooks:
|
|
54
|
-
#
|
|
54
|
+
# All comment are preserved
|
|
55
55
|
- id: black
|
|
56
56
|
name: black
|
|
57
57
|
description: "Long strings are automatically folded into multilines by ruamel-yaml library!"
|
|
@@ -63,51 +63,45 @@ repos:
|
|
|
63
63
|
additional_dependencies:
|
|
64
64
|
# Loose version definitions are pinned to an exact version
|
|
65
65
|
- "black>=25.1.0"
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
minimum_pre_commit_version: '2.9.2'
|
|
66
|
+
# Updates can be prevented by adding a 'freeze' comment to them as:
|
|
67
|
+
- "white==0.1.0" # freeze
|
|
68
|
+
|
|
69
|
+
- id: julia-format
|
|
70
|
+
name: format julia code
|
|
71
|
+
description: Run `JuliaFormatter.jl` against Julia source files
|
|
72
|
+
language: julia
|
|
73
|
+
types: [julia]
|
|
74
|
+
entry: tools/formatter.jl
|
|
76
75
|
additional_dependencies:
|
|
77
|
-
# Double/single quoting style is preserved
|
|
78
|
-
- '
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
language: python
|
|
87
|
-
types_or: [python, pyi]
|
|
88
|
-
args: ["--strict"]
|
|
89
|
-
require_serial: true
|
|
90
|
-
minimum_pre_commit_version: '2.9.2'
|
|
76
|
+
# Double/single quoting style is preserved and version is added to packages with no version definition
|
|
77
|
+
- 'JuliaFormatter'
|
|
78
|
+
|
|
79
|
+
- id: mdbook-lint
|
|
80
|
+
name: mdbook-lint
|
|
81
|
+
description: rust package to lint markdown
|
|
82
|
+
entry: mdbook-lint lint --fix
|
|
83
|
+
language: rust
|
|
84
|
+
types: [markdown]
|
|
91
85
|
# Updating packages defined in flow style is also supported
|
|
92
|
-
additional_dependencies: [
|
|
86
|
+
additional_dependencies: ["cli:mdbook-lint"]
|
|
93
87
|
```
|
|
94
88
|
|
|
95
89
|
Running `pre-commit-localupdate` will update the file to (hypothetical latest versions):
|
|
96
90
|
|
|
97
91
|
```yaml
|
|
98
|
-
#
|
|
92
|
+
# File header is preserved. If there is no document start marker (---), it won't be added
|
|
99
93
|
---
|
|
100
94
|
repos:
|
|
101
95
|
# External hooks won't be touched. Use 'pre-commit autoupdate' command to update them
|
|
102
96
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
103
97
|
rev: v2.3.0
|
|
104
98
|
hooks:
|
|
105
|
-
- id: check-yaml
|
|
106
99
|
- id: end-of-file-fixer
|
|
107
100
|
- id: trailing-whitespace
|
|
101
|
+
|
|
108
102
|
- repo: local
|
|
109
103
|
hooks:
|
|
110
|
-
#
|
|
104
|
+
# All comment are preserved
|
|
111
105
|
- id: black
|
|
112
106
|
name: black
|
|
113
107
|
description: "Long strings are automatically folded into multilines by ruamel-yaml
|
|
@@ -120,35 +114,33 @@ repos:
|
|
|
120
114
|
additional_dependencies:
|
|
121
115
|
# Loose version definitions are pinned to an exact version
|
|
122
116
|
- "black==26.1.0"
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
minimum_pre_commit_version: '2.9.2'
|
|
117
|
+
# Updates can be prevented by adding a 'freeze' comment to them as:
|
|
118
|
+
- "white==0.1.0" # freeze
|
|
119
|
+
|
|
120
|
+
- id: julia-format
|
|
121
|
+
name: format julia code
|
|
122
|
+
description: Run `JuliaFormatter.jl` against Julia source files
|
|
123
|
+
language: julia
|
|
124
|
+
types: [julia]
|
|
125
|
+
entry: tools/formatter.jl
|
|
133
126
|
additional_dependencies:
|
|
134
|
-
# Double/single quoting style is preserved
|
|
135
|
-
- '
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
language: python
|
|
144
|
-
types_or: [python, pyi]
|
|
145
|
-
args: ["--strict"]
|
|
146
|
-
require_serial: true
|
|
147
|
-
minimum_pre_commit_version: '2.9.2'
|
|
127
|
+
# Double/single quoting style is preserved and version is added to packages with no version definition
|
|
128
|
+
- 'JuliaFormatter@2.3.0'
|
|
129
|
+
|
|
130
|
+
- id: mdbook-lint
|
|
131
|
+
name: mdbook-lint
|
|
132
|
+
description: rust package to lint markdown
|
|
133
|
+
entry: mdbook-lint lint --fix
|
|
134
|
+
language: rust
|
|
135
|
+
types: [markdown]
|
|
148
136
|
# Updating packages defined in flow style is also supported
|
|
149
|
-
additional_dependencies: [
|
|
137
|
+
additional_dependencies: ["cli:mdbook-lint:0.14.2"]
|
|
150
138
|
```
|
|
151
139
|
|
|
140
|
+
## Formatting
|
|
141
|
+
|
|
142
|
+
A considerable amount of effort has been put into making `pre-commit-localupdate` respect the original style and preserve the comments in the pre-commit configuration files. Although it is currently folding long strings (for example, in description lines) and enforcing block indentation for better readability.
|
|
143
|
+
|
|
152
144
|
## Requirements
|
|
153
145
|
|
|
154
146
|
- ruamel.yaml
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '0.4.0'
|
|
@@ -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
|
+
"""Module to update additional_dependencies in .pre-commit-config.yaml.
|
|
5
|
+
|
|
6
|
+
This script reads the .pre-commit-config.yaml file, identifies hooks defined
|
|
7
|
+
under 'repo: local' and updates the packages listed in 'additional_dependencies'
|
|
8
|
+
to their latest versions.
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import logging
|
|
13
|
+
import sys
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
from pre_commit_localupdate.cli import parse_args
|
|
17
|
+
from pre_commit_localupdate.error import PreCommitLocalUpdateError
|
|
18
|
+
from pre_commit_localupdate.logs import setup_logging
|
|
19
|
+
from pre_commit_localupdate.pre_commit_config import update_additional_dependencies
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def main() -> None:
|
|
23
|
+
"""Main entry point for the script."""
|
|
24
|
+
args = parse_args()
|
|
25
|
+
setup_logging(debug=args.debug)
|
|
26
|
+
|
|
27
|
+
try:
|
|
28
|
+
if update_additional_dependencies(Path(args.config), dry_run=args.dry_run):
|
|
29
|
+
if args.dry_run:
|
|
30
|
+
sys.exit(1)
|
|
31
|
+
logging.info("Done.")
|
|
32
|
+
else:
|
|
33
|
+
logging.info(
|
|
34
|
+
"Additional dependencies of local hooks are already up to date.",
|
|
35
|
+
)
|
|
36
|
+
except PreCommitLocalUpdateError as exc:
|
|
37
|
+
logging.exception(exc)
|
|
38
|
+
sys.exit(2)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
if __name__ == "__main__":
|
|
42
|
+
main()
|
|
@@ -9,7 +9,7 @@ from pre_commit_localupdate import __version__
|
|
|
9
9
|
def parse_args() -> argparse.Namespace:
|
|
10
10
|
"""Parse command line arguments."""
|
|
11
11
|
parser = argparse.ArgumentParser(
|
|
12
|
-
description="Automatically update additional dependencies within local Python, Julia, Rust, and Node.js hooks in pre-commit config
|
|
12
|
+
description="Automatically update additional dependencies within local Python, Julia, Rust, Go, and Node.js hooks in a pre-commit config file.",
|
|
13
13
|
)
|
|
14
14
|
parser.add_argument(
|
|
15
15
|
"--debug",
|
|
@@ -19,7 +19,7 @@ def parse_args() -> argparse.Namespace:
|
|
|
19
19
|
parser.add_argument(
|
|
20
20
|
"--dry-run",
|
|
21
21
|
action="store_true",
|
|
22
|
-
help="Dry run mode. Do not update the file and exit with a non-zero code if the configuration
|
|
22
|
+
help="Dry run mode. Do not update the file and exit with a non-zero code if the configuration file require an update.",
|
|
23
23
|
)
|
|
24
24
|
parser.add_argument(
|
|
25
25
|
"-c",
|
|
@@ -29,6 +29,8 @@ def parse_args() -> argparse.Namespace:
|
|
|
29
29
|
default=".pre-commit-config.yaml",
|
|
30
30
|
)
|
|
31
31
|
parser.add_argument(
|
|
32
|
-
"--version",
|
|
32
|
+
"--version",
|
|
33
|
+
action="version",
|
|
34
|
+
version=f"pre-commit-localupdate {__version__}",
|
|
33
35
|
)
|
|
34
36
|
return parser.parse_args()
|
|
@@ -2,28 +2,28 @@
|
|
|
2
2
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
3
3
|
|
|
4
4
|
import logging
|
|
5
|
-
import sys
|
|
6
5
|
from pathlib import Path
|
|
7
|
-
from typing import List, Tuple
|
|
8
6
|
|
|
7
|
+
from pre_commit_localupdate.error import PreCommitLocalUpdateError
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
|
|
10
|
+
def load_config_file(file_path: Path) -> tuple[list[str], str]:
|
|
11
11
|
"""Reads pre-commit configuration file and returns its header lines and content."""
|
|
12
12
|
logging.debug("Reading configuration file: %s", file_path)
|
|
13
13
|
|
|
14
|
-
raw_lines:
|
|
15
|
-
header_lines:
|
|
14
|
+
raw_lines: list[str] = []
|
|
15
|
+
header_lines: list[str] = []
|
|
16
16
|
content_start_index: int = 0
|
|
17
17
|
|
|
18
18
|
try:
|
|
19
19
|
with file_path.open("r", encoding="utf-8") as f:
|
|
20
20
|
raw_lines = f.readlines()
|
|
21
|
-
except FileNotFoundError:
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
except FileNotFoundError as exc:
|
|
22
|
+
error = f"File not found: {file_path}"
|
|
23
|
+
raise PreCommitLocalUpdateError(error) from exc
|
|
24
24
|
except OSError as exc:
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
error = f"IOError while reading file {file_path}"
|
|
26
|
+
raise PreCommitLocalUpdateError(error) from exc
|
|
27
27
|
|
|
28
28
|
logging.debug("Parsing file header...")
|
|
29
29
|
content_start_index = 0
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# SPDX-FileCopyrightText: 2026 M. Farzalipour Tabriz, Max Planck Institute for Physics
|
|
2
2
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
3
3
|
|
|
4
|
+
from .golang import GoPackage
|
|
4
5
|
from .julia import JuliaPackage
|
|
5
6
|
from .node import NodePackage
|
|
6
7
|
from .package import PackageBase
|
|
@@ -8,6 +9,7 @@ from .python import PyPackage
|
|
|
8
9
|
from .rust import RustPackage
|
|
9
10
|
|
|
10
11
|
SUPPORTED_PACKAGES: dict[str, type[PackageBase]] = {
|
|
12
|
+
"golang": GoPackage,
|
|
11
13
|
"julia": JuliaPackage,
|
|
12
14
|
"node": NodePackage,
|
|
13
15
|
"python": PyPackage,
|
|
@@ -0,0 +1,124 @@
|
|
|
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
|
+
|
|
7
|
+
import requests
|
|
8
|
+
|
|
9
|
+
from .package import PackageBase
|
|
10
|
+
|
|
11
|
+
# Go Proxy API endpoints
|
|
12
|
+
GO_PKG_LATEST_VERSION_API_URL = "https://proxy.golang.org/{package_path}/@latest"
|
|
13
|
+
|
|
14
|
+
REQUEST_TIMEOUT = 10
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class GoPackage(PackageBase):
|
|
18
|
+
"""Represents a Go module."""
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def from_specification(package, spec: str) -> "GoPackage" | None:
|
|
22
|
+
"""Parse a Go module specification string into a Package object.
|
|
23
|
+
|
|
24
|
+
Handles formats like:
|
|
25
|
+
- 'mvdan.cc/sh' (Module path only)
|
|
26
|
+
- 'mvdan.cc/sh@v1.3.0' (Module path with specific version)
|
|
27
|
+
- 'mvdan.cc/sh/v3' (Module path with major version suffix)
|
|
28
|
+
- 'mvdan.cc/sh/v3@v3.10.0' (Major suffix with version)
|
|
29
|
+
- 'mvdan.cc/sh/v3/cmd/shfmt' (Submodule)
|
|
30
|
+
- 'mvdan.cc/sh/v3/cmd/shfmt@v3.10.0' (Submodule with version)
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
package: The package specification string.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
A Package instance if parsing succeeds, otherwise None.
|
|
37
|
+
"""
|
|
38
|
+
clean_spec = spec.strip().strip('"').strip("'")
|
|
39
|
+
|
|
40
|
+
match = re.match(r"^([a-zA-Z0-9._/-]+)(@.+)?$", clean_spec)
|
|
41
|
+
|
|
42
|
+
if not match:
|
|
43
|
+
logging.warning(
|
|
44
|
+
"Could not parse the Go package specification: %s", clean_spec
|
|
45
|
+
)
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
name = match.group(1)
|
|
49
|
+
raw_spec = match.group(2)
|
|
50
|
+
|
|
51
|
+
module_path = package._resolve_module_path(name)
|
|
52
|
+
latest_version = package._fetch_latest_version(module_path)
|
|
53
|
+
|
|
54
|
+
return package(
|
|
55
|
+
name=name,
|
|
56
|
+
raw_spec=raw_spec,
|
|
57
|
+
latest_version=latest_version,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
@staticmethod
|
|
61
|
+
def _resolve_module_path(package_path: str) -> str:
|
|
62
|
+
"""
|
|
63
|
+
Resolve a submodule path to a module path.
|
|
64
|
+
|
|
65
|
+
If the path contains a major version suffix (e.g., /v2, /v3) followed by
|
|
66
|
+
additional path segments, it trims the path at the suffix.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
package_path: The full submodule path.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
The resolved module path.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
match = re.search(r"/v([2-9]|[1-9][0-9]+)(?=/)", package_path)
|
|
76
|
+
|
|
77
|
+
if match:
|
|
78
|
+
return package_path[: match.end()]
|
|
79
|
+
|
|
80
|
+
return package_path
|
|
81
|
+
|
|
82
|
+
@staticmethod
|
|
83
|
+
def _fetch_latest_version(package_path: str) -> str | None:
|
|
84
|
+
"""Fetch the latest version of a Go module from proxy.golang.org.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
package_path: The module path (e.g., mvdan.cc/sh/v3).
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
The latest version string (e.g., v3.10.0) if found, otherwise None.
|
|
91
|
+
"""
|
|
92
|
+
logging.debug("Fetching latest version for %s", package_path)
|
|
93
|
+
try:
|
|
94
|
+
url = GO_PKG_LATEST_VERSION_API_URL.format(package_path=package_path)
|
|
95
|
+
|
|
96
|
+
response = requests.get(url, timeout=REQUEST_TIMEOUT)
|
|
97
|
+
response.raise_for_status()
|
|
98
|
+
|
|
99
|
+
data = response.json()
|
|
100
|
+
version = data.get("Version")
|
|
101
|
+
|
|
102
|
+
if isinstance(version, str):
|
|
103
|
+
return version
|
|
104
|
+
|
|
105
|
+
return None
|
|
106
|
+
except requests.exceptions.RequestException as exc:
|
|
107
|
+
logging.warning(
|
|
108
|
+
"Could not fetch latest version for %s: %s", package_path, exc
|
|
109
|
+
)
|
|
110
|
+
return None
|
|
111
|
+
except (KeyError, ValueError) as exc:
|
|
112
|
+
logging.warning("Could not parse response for %s: %s", package_path, exc)
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
def latest_version_specification(self) -> str | None:
|
|
116
|
+
"""Version specification of package pinned to the latest version.
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
The latest version specification string if found, otherwise None.
|
|
120
|
+
"""
|
|
121
|
+
if not self.latest_version:
|
|
122
|
+
return None
|
|
123
|
+
|
|
124
|
+
return f"{self.name}@{self.latest_version}"
|
|
@@ -3,11 +3,14 @@
|
|
|
3
3
|
|
|
4
4
|
import io
|
|
5
5
|
import logging
|
|
6
|
-
import
|
|
6
|
+
import os
|
|
7
|
+
import re
|
|
8
|
+
import tempfile
|
|
7
9
|
from pathlib import Path
|
|
8
10
|
|
|
9
11
|
import ruamel.yaml
|
|
10
12
|
|
|
13
|
+
from pre_commit_localupdate.error import PreCommitLocalUpdateError
|
|
11
14
|
from pre_commit_localupdate.io import load_config_file
|
|
12
15
|
from pre_commit_localupdate.packages import SUPPORTED_PACKAGES
|
|
13
16
|
|
|
@@ -21,12 +24,12 @@ def update_additional_dependencies(file_path: Path, *, dry_run: bool = False) ->
|
|
|
21
24
|
|
|
22
25
|
Args:
|
|
23
26
|
file_path: Path to the pre-commit configuration file.
|
|
27
|
+
dry_run: Do not update the pre-commit configuration file.
|
|
24
28
|
|
|
25
29
|
Returns:
|
|
26
|
-
True if the file
|
|
30
|
+
True if the file needed updating, False otherwise.
|
|
27
31
|
|
|
28
32
|
"""
|
|
29
|
-
|
|
30
33
|
header_lines, yaml_content = load_config_file(file_path)
|
|
31
34
|
|
|
32
35
|
logging.debug("Parsing YAML content...")
|
|
@@ -41,13 +44,13 @@ def update_additional_dependencies(file_path: Path, *, dry_run: bool = False) ->
|
|
|
41
44
|
|
|
42
45
|
try:
|
|
43
46
|
config = yaml.load(yaml_content)
|
|
44
|
-
except
|
|
45
|
-
|
|
46
|
-
sys.exit(2)
|
|
47
|
+
except ruamel.yaml.error.YAMLError as exc:
|
|
48
|
+
raise PreCommitLocalUpdateError("Failed to parse YAML content.") from exc
|
|
47
49
|
|
|
48
50
|
if config is None:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
raise PreCommitLocalUpdateError(
|
|
52
|
+
"Configuration file is empty or could not be parsed.",
|
|
53
|
+
)
|
|
51
54
|
|
|
52
55
|
update_required = False
|
|
53
56
|
|
|
@@ -65,18 +68,27 @@ def update_additional_dependencies(file_path: Path, *, dry_run: bool = False) ->
|
|
|
65
68
|
if hook.get("language") not in SUPPORTED_PACKAGES:
|
|
66
69
|
continue
|
|
67
70
|
|
|
68
|
-
|
|
69
|
-
continue
|
|
71
|
+
deps_list = hook.get("additional_dependencies")
|
|
70
72
|
|
|
71
|
-
|
|
73
|
+
if not deps_list:
|
|
74
|
+
continue
|
|
72
75
|
|
|
73
|
-
|
|
76
|
+
package_type = SUPPORTED_PACKAGES[hook.get("language")]
|
|
74
77
|
|
|
75
78
|
for i, dep_spec in enumerate(deps_list):
|
|
76
79
|
dep_str = str(dep_spec)
|
|
77
80
|
|
|
81
|
+
if hasattr(deps_list, "ca") and deps_list.ca.items:
|
|
82
|
+
comment_data = deps_list.ca.items.get(i)
|
|
83
|
+
if comment_data:
|
|
84
|
+
if re.match(
|
|
85
|
+
r"^#\s*freeze(\s|$)", comment_data[0].value.lower()
|
|
86
|
+
):
|
|
87
|
+
logging.debug("Skipping frozen dependency: %s", dep_str)
|
|
88
|
+
continue
|
|
89
|
+
|
|
78
90
|
logging.debug("Checking dependency: %s", dep_str)
|
|
79
|
-
package =
|
|
91
|
+
package = package_type.from_specification(dep_str)
|
|
80
92
|
if not package:
|
|
81
93
|
continue
|
|
82
94
|
|
|
@@ -103,26 +115,39 @@ def update_additional_dependencies(file_path: Path, *, dry_run: bool = False) ->
|
|
|
103
115
|
package.name,
|
|
104
116
|
package.version_specification(),
|
|
105
117
|
)
|
|
118
|
+
else:
|
|
119
|
+
raise PreCommitLocalUpdateError("Failed to parse pre-commit hooks!")
|
|
106
120
|
|
|
107
121
|
if update_required:
|
|
108
122
|
if dry_run:
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
)
|
|
126
|
-
|
|
123
|
+
return True
|
|
124
|
+
|
|
125
|
+
logging.debug("Writing modifications to disk...")
|
|
126
|
+
stream = io.StringIO()
|
|
127
|
+
yaml.dump(config, stream)
|
|
128
|
+
modified_body = stream.getvalue()
|
|
129
|
+
final_content = "".join(header_lines) + modified_body
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
with tempfile.NamedTemporaryFile(
|
|
133
|
+
mode="w",
|
|
134
|
+
encoding="utf-8",
|
|
135
|
+
dir=file_path.parent,
|
|
136
|
+
delete=False,
|
|
137
|
+
) as tmp_file:
|
|
138
|
+
tmp_file.write(final_content)
|
|
139
|
+
os.fsync(tmp_file.fileno())
|
|
140
|
+
temp_file_path = tmp_file.name
|
|
141
|
+
|
|
142
|
+
os.replace(temp_file_path, file_path)
|
|
143
|
+
logging.info("Successfully updated %s", file_path)
|
|
144
|
+
return True
|
|
145
|
+
|
|
146
|
+
except OSError as exc:
|
|
147
|
+
if "temp_file_path" in locals() and os.path.exists(temp_file_path):
|
|
148
|
+
os.unlink(temp_file_path)
|
|
149
|
+
raise PreCommitLocalUpdateError(
|
|
150
|
+
f"IOError while writing to file {file_path}"
|
|
151
|
+
) from exc
|
|
127
152
|
|
|
128
153
|
return False
|
|
@@ -23,12 +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 additional dependencies within local Python, Julia, Rust, and Node.js hooks in pre-commit config files."
|
|
26
|
+
description = "A CLI tool to automatically update additional dependencies within local Python, Julia, Rust, Go, and Node.js hooks in pre-commit config files."
|
|
27
27
|
dynamic = []
|
|
28
28
|
name = "pre-commit-localupdate"
|
|
29
29
|
readme = "README.md"
|
|
30
30
|
requires-python = "<3.15,>=3.11"
|
|
31
|
-
version = "0.
|
|
31
|
+
version = "0.4.0"
|
|
32
32
|
|
|
33
33
|
[project.scripts]
|
|
34
34
|
pre-commit-localupdate = "pre_commit_localupdate.__main__:main"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '0.3.0'
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2026 M. Farzalipour Tabriz, Max Planck Institute for Physics
|
|
2
|
-
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
3
|
-
|
|
4
|
-
"""Module to update Python additional_dependencies in .pre-commit-config.yaml.
|
|
5
|
-
|
|
6
|
-
This script reads the .pre-commit-config.yaml file, identifies hooks defined
|
|
7
|
-
under 'repo: local' that use 'language: python', and updates the packages
|
|
8
|
-
listed in 'additional_dependencies' to their latest versions available on PyPI.
|
|
9
|
-
|
|
10
|
-
It preserves the original file formatting, comments, and structure, only
|
|
11
|
-
modifying the version strings within the dependency lines.
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
import logging
|
|
15
|
-
from pathlib import Path
|
|
16
|
-
|
|
17
|
-
from pre_commit_localupdate.cli import parse_args
|
|
18
|
-
from pre_commit_localupdate.logs import setup_logging
|
|
19
|
-
from pre_commit_localupdate.pre_commit_config import update_additional_dependencies
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def main() -> None:
|
|
23
|
-
"""Main entry point for the script."""
|
|
24
|
-
args = parse_args()
|
|
25
|
-
setup_logging(args.debug)
|
|
26
|
-
|
|
27
|
-
if update_additional_dependencies(Path(args.config), dry_run=args.dry_run):
|
|
28
|
-
logging.info("Done.")
|
|
29
|
-
else:
|
|
30
|
-
logging.info("File content is already up to date.")
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if __name__ == "__main__":
|
|
34
|
-
main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|