add warning for deprecates stages for remote repos on init

This commit is contained in:
Anthony Sottile 2024-09-30 20:29:19 -04:00
parent 7555e11098
commit d31722386e
3 changed files with 112 additions and 0 deletions

View file

@ -2,6 +2,7 @@ from __future__ import annotations
import functools import functools
import logging import logging
import os.path
import re import re
import shlex import shlex
import sys import sys
@ -70,6 +71,43 @@ def transform_stage(stage: str) -> str:
return _STAGES.get(stage, stage) return _STAGES.get(stage, stage)
MINIMAL_MANIFEST_SCHEMA = cfgv.Array(
cfgv.Map(
'Hook', 'id',
cfgv.Required('id', cfgv.check_string),
cfgv.Optional('stages', cfgv.check_array(cfgv.check_string), []),
),
)
def warn_for_stages_on_repo_init(repo: str, directory: str) -> None:
try:
manifest = cfgv.load_from_filename(
os.path.join(directory, C.MANIFEST_FILE),
schema=MINIMAL_MANIFEST_SCHEMA,
load_strategy=yaml_load,
exc_tp=InvalidManifestError,
)
except InvalidManifestError:
return # they'll get a better error message when it actually loads!
legacy_stages = {} # sorted set
for hook in manifest:
for stage in hook.get('stages', ()):
if stage in _STAGES:
legacy_stages[stage] = True
if legacy_stages:
logger.warning(
f'repo `{repo}` uses deprecated stage names '
f'({", ".join(legacy_stages)}) which will be removed in a '
f'future version. '
f'Hint: often `pre-commit autoupdate --repo {shlex.quote(repo)}` '
f'will fix this. '
f'if it does not -- consider reporting an issue to that repo.',
)
class StagesMigrationNoDefault(NamedTuple): class StagesMigrationNoDefault(NamedTuple):
key: str key: str
default: Sequence[str] default: Sequence[str]

View file

@ -10,6 +10,7 @@ from collections.abc import Sequence
from typing import Callable from typing import Callable
import pre_commit.constants as C import pre_commit.constants as C
from pre_commit import clientlib
from pre_commit import file_lock from pre_commit import file_lock
from pre_commit import git from pre_commit import git
from pre_commit.util import CalledProcessError from pre_commit.util import CalledProcessError
@ -136,6 +137,7 @@ class Store:
deps: Sequence[str], deps: Sequence[str],
make_strategy: Callable[[str], None], make_strategy: Callable[[str], None],
) -> str: ) -> str:
original_repo = repo
repo = self.db_repo_name(repo, deps) repo = self.db_repo_name(repo, deps)
def _get_result() -> str | None: def _get_result() -> str | None:
@ -168,6 +170,9 @@ class Store:
'INSERT INTO repos (repo, ref, path) VALUES (?, ?, ?)', 'INSERT INTO repos (repo, ref, path) VALUES (?, ?, ?)',
[repo, ref, directory], [repo, ref, directory],
) )
clientlib.warn_for_stages_on_repo_init(original_repo, directory)
return directory return directory
def _complete_clone(self, ref: str, git_cmd: Callable[..., None]) -> None: def _complete_clone(self, ref: str, git_cmd: Callable[..., None]) -> None:

View file

@ -1,12 +1,15 @@
from __future__ import annotations from __future__ import annotations
import logging
import os.path import os.path
import shlex
import sqlite3 import sqlite3
import stat import stat
from unittest import mock from unittest import mock
import pytest import pytest
import pre_commit.constants as C
from pre_commit import git from pre_commit import git
from pre_commit.store import _get_default_directory from pre_commit.store import _get_default_directory
from pre_commit.store import _LOCAL_RESOURCES from pre_commit.store import _LOCAL_RESOURCES
@ -91,6 +94,72 @@ def test_clone(store, tempdir_factory, caplog):
assert store.select_all_repos() == [(path, rev, ret)] assert store.select_all_repos() == [(path, rev, ret)]
def test_warning_for_deprecated_stages_on_init(store, tempdir_factory, caplog):
manifest = '''\
- id: hook1
name: hook1
language: system
entry: echo hook1
stages: [commit, push]
- id: hook2
name: hook2
language: system
entry: echo hook2
stages: [push, merge-commit]
'''
path = git_dir(tempdir_factory)
with open(os.path.join(path, C.MANIFEST_FILE), 'w') as f:
f.write(manifest)
cmd_output('git', 'add', '.', cwd=path)
git_commit(cwd=path)
rev = git.head_rev(path)
store.clone(path, rev)
assert caplog.record_tuples[1] == (
'pre_commit',
logging.WARNING,
f'repo `{path}` uses deprecated stage names '
f'(commit, push, merge-commit) which will be removed in a future '
f'version. '
f'Hint: often `pre-commit autoupdate --repo {shlex.quote(path)}` '
f'will fix this. '
f'if it does not -- consider reporting an issue to that repo.',
)
# should not re-warn
caplog.clear()
store.clone(path, rev)
assert caplog.record_tuples == []
def test_no_warning_for_non_deprecated_stages_on_init(
store, tempdir_factory, caplog,
):
manifest = '''\
- id: hook1
name: hook1
language: system
entry: echo hook1
stages: [pre-commit, pre-push]
- id: hook2
name: hook2
language: system
entry: echo hook2
stages: [pre-push, pre-merge-commit]
'''
path = git_dir(tempdir_factory)
with open(os.path.join(path, C.MANIFEST_FILE), 'w') as f:
f.write(manifest)
cmd_output('git', 'add', '.', cwd=path)
git_commit(cwd=path)
rev = git.head_rev(path)
store.clone(path, rev)
assert logging.WARNING not in {tup[1] for tup in caplog.record_tuples}
def test_clone_cleans_up_on_checkout_failure(store): def test_clone_cleans_up_on_checkout_failure(store):
with pytest.raises(Exception) as excinfo: with pytest.raises(Exception) as excinfo:
# This raises an exception because you can't clone something that # This raises an exception because you can't clone something that