Skip to content

Commit ddc4fbb

Browse files
committed
Sync node hooks
1 parent efe5df1 commit ddc4fbb

File tree

3 files changed

+77
-10
lines changed

3 files changed

+77
-10
lines changed

README.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ $ sync-pre-commit-deps path/to/.pre-commit-config.yaml
3030

3131
## what it does
3232

33-
Ensures tools which declare `flake8`, `black`, or `mypy` as additional dependencies will have those versions synced with the `flake8`, `black`, or `mypy` versions in the rest of the config. For example, `flake8` under `yesqa` is updated from `5.0.0` to `6.0.0`.
33+
Hooks like `black`, `yesqa`, and `eslint` reference additional dependencies which are also `pre-commit` hooks. This tool syncs the version in `additional_dependencies` with the version in `rev`.
34+
35+
For example, `flake8` under `yesqa` is updated from `5.0.0` to `6.0.0` because the `flake8` hook uses `6.0.0`:
3436

3537
```diff
3638
repos:
@@ -46,3 +48,24 @@ Ensures tools which declare `flake8`, `black`, or `mypy` as additional dependenc
4648
- - flake8==5.0.0
4749
+ - flake8==6.0.0
4850
```
51+
52+
Another example, the `eslint` version in `additional_dependencies` is updated to match the version in `rev`:
53+
54+
```diff
55+
- repo: https://github.com/pre-commit/mirrors-eslint
56+
rev: v4.15.0
57+
hooks:
58+
- id: eslint
59+
additional_dependencies:
60+
- - eslint@4.14.0
61+
+ - eslint@4.15.0
62+
- eslint-config-google@0.7.1
63+
- eslint-loader@1.6.1
64+
- eslint-plugin-react@6.10.3
65+
- babel-eslint@6.1.2
66+
```
67+
68+
## what it doesn't do
69+
70+
- Does not add new additional dependencies. Only updates versions for dependencies that are already specified.
71+
- Does not sync versions from `package.json`, `requirements.txt`, `pyproject.toml`, etc.

sync_pre_commit_deps.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
from __future__ import annotations
22

33
import argparse
4+
import re
45
from collections.abc import Sequence
56

67
import ruamel.yaml
78

8-
SUPPORTED = frozenset(('black', 'flake8', 'mypy'))
9+
SUPPORTED = frozenset({
10+
'black', 'flake8', 'mypy', 'eslint', 'csslint', 'fixmyjs', 'jshint',
11+
'prettier',
12+
})
913

14+
_SEPS = ('==', '@')
15+
_RE_SEP = re.compile(rf'^(.+)({"|".join(_SEPS)})(.+)$')
1016

1117
_ARGUMENT_HELP_TEMPLATE = (
1218
'The `{}` argument to the YAML dumper. '
@@ -56,21 +62,23 @@ def main(argv: Sequence[str] | None = None) -> int:
5662
if repo['repo'] not in ('local', 'meta'):
5763
for hook in repo['hooks']:
5864
if (hid := hook['id']) in SUPPORTED:
59-
# `mirrors-mypy` uses versions with a 'v' prefix, so we
60-
# have to strip it out to get the mypy version.
65+
# `mirrors-mypy` and `eslint` revs have a 'v' prefix, so we
66+
# have to strip that out to get the additional_dependency
67+
# version.
6168
cleaned_rev = repo['rev'].removeprefix('v')
6269
versions[hid] = cleaned_rev
6370

6471
updated = []
6572
for repo in loaded['repos']:
6673
for hook in repo['hooks']:
6774
for i, dep in enumerate(hook.get('additional_dependencies', ())):
68-
name, _, cur_version = dep.partition('==')
69-
target_version = versions.get(name, cur_version)
70-
if target_version != cur_version:
71-
name_and_version = f'{name}=={target_version}'
72-
hook['additional_dependencies'][i] = name_and_version
73-
updated.append((hook['id'], name))
75+
if match := _RE_SEP.match(dep):
76+
name, sep, cur_version = match.groups()
77+
target_version = versions.get(name, cur_version)
78+
if target_version != cur_version:
79+
updated_dep = f'{name}{sep}{target_version}'
80+
hook['additional_dependencies'][i] = updated_dep
81+
updated.append((hook['id'], name))
7482

7583
if updated:
7684
print(f'Writing updates to {filename}:')

tests/sync_pre_commit_deps_test.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,20 @@
2222
' - black==23.3.0\n',
2323
id='already correct version',
2424
),
25+
pytest.param(
26+
'repos:\n'
27+
'- repo: https://github.com/psf/black\n'
28+
' rev: 23.3.0\n'
29+
' hooks:\n'
30+
' - id: black\n'
31+
'- repo: https://github.com/adamchainz/blacken-docs\n'
32+
' rev: 1.15.0\n'
33+
' hooks:\n'
34+
' - id: blacken-docs\n'
35+
' additional_dependencies:\n'
36+
' - black>=22.3.0\n',
37+
id='sep not supported',
38+
),
2539
pytest.param(
2640
'repos:\n'
2741
'- repo: https://github.com/adamchainz/blacken-docs\n'
@@ -64,6 +78,14 @@
6478
' id: black\n',
6579
id='unicode no-op',
6680
),
81+
pytest.param(
82+
'repos:\n'
83+
'- repo: https://github.com/pre-commit/mirrors-eslint\n'
84+
' rev: v8.39.0\n'
85+
' hooks:\n'
86+
' - id: eslint\n',
87+
id='does not have eslint in additional_dependencies',
88+
),
6789
),
6890
)
6991
def test_main_noop(tmpdir, s):
@@ -100,6 +122,14 @@ def test_main_writes_all(tmpdir):
100122
' rev: v1.13.0\n'
101123
' hooks:\n'
102124
' - id: mypy\n'
125+
# gives the `eslint` version and also has its
126+
# additional_dependencies rewritten
127+
'- repo: https://github.com/pre-commit/mirrors-eslint\n'
128+
' rev: v8.39.0\n'
129+
' hooks:\n'
130+
' - id: eslint\n'
131+
' additional_dependencies:\n'
132+
' - eslint@8.38.0\n'
103133
# all repos below should have their additional_dependencies rewritten
104134
'- repo: https://github.com/asottile/yesqa\n'
105135
' rev: v1.5.0\n'
@@ -149,6 +179,12 @@ def test_main_writes_all(tmpdir):
149179
' rev: v1.13.0\n'
150180
' hooks:\n'
151181
' - id: mypy\n'
182+
'- repo: https://github.com/pre-commit/mirrors-eslint\n'
183+
' rev: v8.39.0\n'
184+
' hooks:\n'
185+
' - id: eslint\n'
186+
' additional_dependencies:\n'
187+
' - eslint@8.39.0\n'
152188
'- repo: https://github.com/asottile/yesqa\n'
153189
' rev: v1.5.0\n'
154190
' hooks:\n'

0 commit comments

Comments
 (0)