Skip to content

Commit d317223

Browse files
committed
add warning for deprecates stages for remote repos on init
1 parent 7555e11 commit d317223

File tree

3 files changed

+112
-0
lines changed

3 files changed

+112
-0
lines changed

pre_commit/clientlib.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import functools
44
import logging
5+
import os.path
56
import re
67
import shlex
78
import sys
@@ -70,6 +71,43 @@ def transform_stage(stage: str) -> str:
7071
return _STAGES.get(stage, stage)
7172

7273

74+
MINIMAL_MANIFEST_SCHEMA = cfgv.Array(
75+
cfgv.Map(
76+
'Hook', 'id',
77+
cfgv.Required('id', cfgv.check_string),
78+
cfgv.Optional('stages', cfgv.check_array(cfgv.check_string), []),
79+
),
80+
)
81+
82+
83+
def warn_for_stages_on_repo_init(repo: str, directory: str) -> None:
84+
try:
85+
manifest = cfgv.load_from_filename(
86+
os.path.join(directory, C.MANIFEST_FILE),
87+
schema=MINIMAL_MANIFEST_SCHEMA,
88+
load_strategy=yaml_load,
89+
exc_tp=InvalidManifestError,
90+
)
91+
except InvalidManifestError:
92+
return # they'll get a better error message when it actually loads!
93+
94+
legacy_stages = {} # sorted set
95+
for hook in manifest:
96+
for stage in hook.get('stages', ()):
97+
if stage in _STAGES:
98+
legacy_stages[stage] = True
99+
100+
if legacy_stages:
101+
logger.warning(
102+
f'repo `{repo}` uses deprecated stage names '
103+
f'({", ".join(legacy_stages)}) which will be removed in a '
104+
f'future version. '
105+
f'Hint: often `pre-commit autoupdate --repo {shlex.quote(repo)}` '
106+
f'will fix this. '
107+
f'if it does not -- consider reporting an issue to that repo.',
108+
)
109+
110+
73111
class StagesMigrationNoDefault(NamedTuple):
74112
key: str
75113
default: Sequence[str]

pre_commit/store.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from typing import Callable
1111

1212
import pre_commit.constants as C
13+
from pre_commit import clientlib
1314
from pre_commit import file_lock
1415
from pre_commit import git
1516
from pre_commit.util import CalledProcessError
@@ -136,6 +137,7 @@ def _new_repo(
136137
deps: Sequence[str],
137138
make_strategy: Callable[[str], None],
138139
) -> str:
140+
original_repo = repo
139141
repo = self.db_repo_name(repo, deps)
140142

141143
def _get_result() -> str | None:
@@ -168,6 +170,9 @@ def _get_result() -> str | None:
168170
'INSERT INTO repos (repo, ref, path) VALUES (?, ?, ?)',
169171
[repo, ref, directory],
170172
)
173+
174+
clientlib.warn_for_stages_on_repo_init(original_repo, directory)
175+
171176
return directory
172177

173178
def _complete_clone(self, ref: str, git_cmd: Callable[..., None]) -> None:

tests/store_test.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
from __future__ import annotations
22

3+
import logging
34
import os.path
5+
import shlex
46
import sqlite3
57
import stat
68
from unittest import mock
79

810
import pytest
911

12+
import pre_commit.constants as C
1013
from pre_commit import git
1114
from pre_commit.store import _get_default_directory
1215
from pre_commit.store import _LOCAL_RESOURCES
@@ -91,6 +94,72 @@ def test_clone(store, tempdir_factory, caplog):
9194
assert store.select_all_repos() == [(path, rev, ret)]
9295

9396

97+
def test_warning_for_deprecated_stages_on_init(store, tempdir_factory, caplog):
98+
manifest = '''\
99+
- id: hook1
100+
name: hook1
101+
language: system
102+
entry: echo hook1
103+
stages: [commit, push]
104+
- id: hook2
105+
name: hook2
106+
language: system
107+
entry: echo hook2
108+
stages: [push, merge-commit]
109+
'''
110+
111+
path = git_dir(tempdir_factory)
112+
with open(os.path.join(path, C.MANIFEST_FILE), 'w') as f:
113+
f.write(manifest)
114+
cmd_output('git', 'add', '.', cwd=path)
115+
git_commit(cwd=path)
116+
rev = git.head_rev(path)
117+
118+
store.clone(path, rev)
119+
assert caplog.record_tuples[1] == (
120+
'pre_commit',
121+
logging.WARNING,
122+
f'repo `{path}` uses deprecated stage names '
123+
f'(commit, push, merge-commit) which will be removed in a future '
124+
f'version. '
125+
f'Hint: often `pre-commit autoupdate --repo {shlex.quote(path)}` '
126+
f'will fix this. '
127+
f'if it does not -- consider reporting an issue to that repo.',
128+
)
129+
130+
# should not re-warn
131+
caplog.clear()
132+
store.clone(path, rev)
133+
assert caplog.record_tuples == []
134+
135+
136+
def test_no_warning_for_non_deprecated_stages_on_init(
137+
store, tempdir_factory, caplog,
138+
):
139+
manifest = '''\
140+
- id: hook1
141+
name: hook1
142+
language: system
143+
entry: echo hook1
144+
stages: [pre-commit, pre-push]
145+
- id: hook2
146+
name: hook2
147+
language: system
148+
entry: echo hook2
149+
stages: [pre-push, pre-merge-commit]
150+
'''
151+
152+
path = git_dir(tempdir_factory)
153+
with open(os.path.join(path, C.MANIFEST_FILE), 'w') as f:
154+
f.write(manifest)
155+
cmd_output('git', 'add', '.', cwd=path)
156+
git_commit(cwd=path)
157+
rev = git.head_rev(path)
158+
159+
store.clone(path, rev)
160+
assert logging.WARNING not in {tup[1] for tup in caplog.record_tuples}
161+
162+
94163
def test_clone_cleans_up_on_checkout_failure(store):
95164
with pytest.raises(Exception) as excinfo:
96165
# This raises an exception because you can't clone something that

0 commit comments

Comments
 (0)