Repository: pre-commit/pre-commit-mirror-maker

Issue:
Add support for `types_or`
Looks like `--types` is supported by not `types_or` equivalent.

Discussion:
henryiii: Not related to this pr, but shouldn't flake8 be below some of the other hooks, like autopep8? autopep8 is a modifying hook, and flake8 is not.
henryiii: (totally forgot about the minimum required even after asking about it, will add then un-draft)
henryiii: Are you okay with adding `minimum_pre_commit_version: '0'` to the output on non-type_or repos, or should that line be conditional, only if non zero?
henryiii: @asottile, I assumed you were fine with `minimum_pre_commit_version: '0'` showing up in all non-types_or repos, but happy to change that if it is better to make it conditional, only showing up if set. I think this is ready for review.
henryiii: Manually writing `--types-or=a,b` still works, but now `--types-or=a --types-or=b` also works. I did not apply this to `--types` (but I could if you want). I think everything is addressed.

Patch:
diff --git a/pre_commit_mirror_maker/all/.pre-commit-hooks.yaml b/pre_commit_mirror_maker/all/.pre-commit-hooks.yaml
index ddf38ac..8ecd0d8 100644
--- a/pre_commit_mirror_maker/all/.pre-commit-hooks.yaml
+++ b/pre_commit_mirror_maker/all/.pre-commit-hooks.yaml
@@ -6,3 +6,4 @@
     args: {args}
     require_serial: {require_serial}
     additional_dependencies: {additional_dependencies}
+    minimum_pre_commit_version: {minimum_pre_commit_version}
diff --git a/pre_commit_mirror_maker/main.py b/pre_commit_mirror_maker/main.py
index a967fb5..342cd29 100644
--- a/pre_commit_mirror_maker/main.py
+++ b/pre_commit_mirror_maker/main.py
@@ -47,7 +47,10 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
     mutex.add_argument(
         '--files-regex', help='Files regex to use in hooks.yaml',
     )
-    mutex.add_argument('--types', help='`identify` type to match')
+    mutex.add_argument('--types', help='`identify` type to AND match')
+    mutex.add_argument(
+        '--types-or', action='append', help='`identify` type to OR match',
+    )
 
     parser.add_argument(
         '--id', help='Hook id, defaults to the entry point.',
@@ -70,16 +73,30 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
     )
     args = parser.parse_args(argv)
 
+    minimum_pre_commit_version = '0'
+
+    if args.types_or:
+        match_key = 'types_or'
+        match_val = '[{}]'.format(', '.join(args.types_or))
+        minimum_pre_commit_version = '2.9.2'
+    elif args.types:
+        match_key = 'types'
+        match_val = f'[{args.types}]'
+    else:
+        match_key = 'files'
+        match_val = args.files_regex
+
     make_repo(
         args.repo_path,
         name=args.package_name,
         language=args.language,
         entry=args.entry or args.package_name,
         id=args.id or args.entry or args.package_name,
-        match_key='types' if args.types else 'files',
-        match_val=f'[{args.types}]' if args.types else args.files_regex,
+        match_key=match_key,
+        match_val=match_val,
         args=json.dumps(split_by_commas(args.args)),
         require_serial=json.dumps(args.require_serial),
+        minimum_pre_commit_version=minimum_pre_commit_version,
     )
     return 0
 


Test patch:
diff --git a/tests/main_test.py b/tests/main_test.py
index 36c298b..cbfdfce 100644
--- a/tests/main_test.py
+++ b/tests/main_test.py
@@ -40,7 +40,7 @@ def test_main_passes_args(mock_make_repo):
         '.',
         language='ruby', name='scss-lint', entry='scss-lint-entry',
         id='scss-lint-id', match_key='files', match_val=r'\.scss$', args='[]',
-        require_serial='false',
+        require_serial='false', minimum_pre_commit_version='0',
     )
 
 
@@ -75,3 +75,48 @@ def test_main_with_args(mock_make_repo):
     ))
     expected = '["-i", "--ignore=E265,E501"]'
     assert mock_make_repo.call_args[1]['args'] == expected
+
+
+def test_main_with_types_and_types_or(mock_make_repo, capsys):
+    with pytest.raises(SystemExit) as exc_info:
+        main.main((
+            '.',
+            '--language', 'python',
+            '--package-name', 'yapf',
+            '--types=c',
+            '--types-or=c',
+            '--types-or=c++',
+        ))
+
+    assert exc_info.value.args[0] == 2
+
+    out, err = capsys.readouterr()
+    assert out == ''
+    assert 'argument --types-or: not allowed with argument --types' in err
+
+
+def test_main_types(mock_make_repo):
+    assert not main.main((
+        '.',
+        '--language', 'python',
+        '--package-name', 'yapf',
+        '--types=c',
+    ))
+    print(mock_make_repo.call_args[1])
+    assert mock_make_repo.call_args[1]['match_key'] == 'types'
+    assert mock_make_repo.call_args[1]['match_val'] == '[c]'
+    assert mock_make_repo.call_args[1]['minimum_pre_commit_version'] == '0'
+
+
+def test_main_types_or_multi(mock_make_repo):
+    assert not main.main((
+        '.',
+        '--language', 'python',
+        '--package-name', 'yapf',
+        '--types-or=c++',
+        '--types-or=c',
+    ))
+    print(mock_make_repo.call_args[1])
+    assert mock_make_repo.call_args[1]['match_key'] == 'types_or'
+    assert mock_make_repo.call_args[1]['match_val'] == '[c++, c]'
+    assert mock_make_repo.call_args[1]['minimum_pre_commit_version'] == '2.9.2'
diff --git a/tests/make_repo_test.py b/tests/make_repo_test.py
index 8303431..544218e 100644
--- a/tests/make_repo_test.py
+++ b/tests/make_repo_test.py
@@ -66,6 +66,7 @@ def test_commit_version(in_git_dir):
         version='0.24.1', language='ruby', name='scss-lint', entry='scss-lint',
         id='scss-lint', match_key='files', match_val=r'\.scss$', args='[]',
         additional_dependencies='[]', require_serial='false',
+        minimum_pre_commit_version='0',
     )
 
     # Assert that our things got copied over
@@ -86,6 +87,7 @@ def test_arguments(in_git_dir):
         version='0.6.2', language='python', name='yapf', entry='yapf',
         id='yapf', match_key='files', match_val=r'\.py$', args='["-i"]',
         additional_dependencies='["scikit-learn"]', require_serial='false',
+        minimum_pre_commit_version='2.9.0',
     )
     contents = in_git_dir.join('.pre-commit-hooks.yaml').read()
     assert yaml.safe_load(contents) == [{
@@ -97,6 +99,7 @@ def test_arguments(in_git_dir):
         'args': ['-i'],
         'require_serial': False,
         'additional_dependencies': ['scikit-learn'],
+        'minimum_pre_commit_version': '2.9.0',
     }]
 
 
@@ -112,7 +115,7 @@ def test_make_repo_starting_empty(in_git_dir, fake_versions):
         '.',
         language='ruby', name='scss-lint', entry='scss-lint', id='scss-lint',
         match_key='files', match_val=r'\.scss$', args='[]',
-        require_serial='false',
+        require_serial='false', minimum_pre_commit_version='0',
     )
 
     # Assert that our things got copied over
@@ -144,7 +147,7 @@ def test_make_repo_starting_at_version(in_git_dir, fake_versions):
         '.',
         language='ruby', name='scss-lint', entry='scss-lint', id='scss-lint',
         match_key='files', match_val=r'\.scss$', args='[]',
-        require_serial='false',
+        require_serial='false', minimum_pre_commit_version='0',
     )
 
     assert not in_git_dir.join('hooks.yaml').exists()
@@ -164,7 +167,7 @@ def test_ruby_integration(in_git_dir):
         '.',
         language='ruby', name='scss-lint', entry='scss-lint', id='scss-lint',
         match_key='files', match_val=r'\.scss$', args='[]',
-        require_serial='false',
+        require_serial='false', minimum_pre_commit_version='0',
     )
     # Our files should exist
     assert in_git_dir.join('.version').exists()
@@ -184,7 +187,7 @@ def test_node_integration(in_git_dir):
         '.',
         language='node', name='jshint', entry='jshint', id='jshint',
         match_key='files', match_val=r'\.js$', args='[]',
-        require_serial='false',
+        require_serial='false', minimum_pre_commit_version='0',
     )
     # Our files should exist
     assert in_git_dir.join('.version').exists()
@@ -204,7 +207,7 @@ def test_python_integration(in_git_dir):
         '.',
         language='python', name='flake8', entry='flake8', id='flake8',
         match_key='files', match_val=r'\.py$', args='[]',
-        require_serial='false',
+        require_serial='false', minimum_pre_commit_version='0',
     )
     # Our files should exist
     assert in_git_dir.join('.version').exists()
@@ -228,6 +231,7 @@ def test_rust_integration(in_git_dir):
         language='rust', name='shellharden', entry='shellharden',
         id='shellharden', match_key='types', match_val='shell',
         args='["--replace"]', require_serial='false',
+        minimum_pre_commit_version='0',
     )
     # Our files should exist
     assert in_git_dir.join('.version').exists()