Repository: pre-commit/pre-commit

Issue:
`minimum_pre_commit_version` at the top level in configuration
Similar to the one that's currently allowed on individual hooks, allow this at the top level of the `.pre-commit-config.yaml`


Discussion:
Code hints: https://github.com/pre-commit/pre-commit/blob/185a288645d900c35f248dc1ca189c5085da21e1/pre_commit/clientlib.py#L220-L234

https://github.com/pre-commit/pre-commit/blob/185a288645d900c35f248dc1ca189c5085da21e1/pre_commit/clientlib.py#L60

here's where it happens on a per-hook basis: https://github.com/pre-commit/pre-commit/blob/185a288645d900c35f248dc1ca189c5085da21e1/pre_commit/repository.py#L121-L130

though for this you'd do it when parsing the configuration.  The reason the version checking is deferred to the `repository` stage for the per-hook check is sometimes the hooks aren't enabled (and for local hooks)

Resolving patch:
diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py
--- a/pre_commit/clientlib.py
+++ b/pre_commit/clientlib.py
@@ -13,6 +13,7 @@
 import pre_commit.constants as C
 from pre_commit.error_handler import FatalError
 from pre_commit.languages.all import all_languages
+from pre_commit.util import parse_version
 
 
 def check_type_tag(tag):
@@ -23,6 +24,16 @@ def check_type_tag(tag):
         )
 
 
+def check_min_version(version):
+    if parse_version(version) > parse_version(C.VERSION):
+        raise cfgv.ValidationError(
+            'pre-commit version {} is required but version {} is installed.  '
+            'Perhaps run `pip install --upgrade pre-commit`.'.format(
+                version, C.VERSION,
+            ),
+        )
+
+
 def _make_argparser(filenames_help):
     parser = argparse.ArgumentParser()
     parser.add_argument('filenames', nargs='*', help=filenames_help)
@@ -231,6 +242,11 @@ def _entry(modname):
     ),
     cfgv.Optional('exclude', cfgv.check_regex, '^$'),
     cfgv.Optional('fail_fast', cfgv.check_bool, False),
+    cfgv.Optional(
+        'minimum_pre_commit_version',
+        cfgv.check_and(cfgv.check_string, check_min_version),
+        '0',
+    ),
 )
 
 


Test patch:
diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py
--- a/tests/clientlib_test.py
+++ b/tests/clientlib_test.py
@@ -3,6 +3,7 @@
 import cfgv
 import pytest
 
+import pre_commit.constants as C
 from pre_commit.clientlib import check_type_tag
 from pre_commit.clientlib import CONFIG_HOOK_DICT
 from pre_commit.clientlib import CONFIG_REPO_DICT
@@ -234,3 +235,23 @@ def test_meta_hook_invalid(config_repo):
 def test_default_language_version_invalid(mapping):
     with pytest.raises(cfgv.ValidationError):
         cfgv.validate(mapping, DEFAULT_LANGUAGE_VERSION)
+
+
+def test_minimum_pre_commit_version_failing():
+    with pytest.raises(cfgv.ValidationError) as excinfo:
+        cfg = {'repos': [], 'minimum_pre_commit_version': '999'}
+        cfgv.validate(cfg, CONFIG_SCHEMA)
+    assert str(excinfo.value) == (
+        '\n'
+        '==> At Config()\n'
+        '==> At key: minimum_pre_commit_version\n'
+        '=====> pre-commit version 999 is required but version {} is '
+        'installed.  Perhaps run `pip install --upgrade pre-commit`.'.format(
+            C.VERSION,
+        )
+    )
+
+
+def test_minimum_pre_commit_version_passing():
+    cfg = {'repos': [], 'minimum_pre_commit_version': '0'}
+    cfgv.validate(cfg, CONFIG_SCHEMA)