Skip to content

Commit

Permalink
Allow pre-commit to run in subpath (#2007)
Browse files Browse the repository at this point in the history
  • Loading branch information
LecrisUT authored Jul 6, 2024
1 parent a42eb01 commit 8b6a819
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 8 deletions.
18 changes: 10 additions & 8 deletions .pre-commit-hooks.yaml
Original file line number Diff line number Diff line change
@@ -1,34 +1,36 @@
- id: tmt-lint
name: tmt lint
entry: bash -c "git ls-files --error-unmatch $(python3 -c 'import tmt; print(tmt.Tree(logger=tmt.Logger.create(), path=\".\").root)')/.fmf/version && tmt lint --failed-only --source $@" PAD
files: '.*\.fmf$'
# Use a simple wrapper instead of simply `tmt lint` in order to reorder
# some arguments that need to be passed to `tmt`
entry: python -m tmt._pre_commit --pre-check lint --failed-only --source
files: '(?:.*\.fmf|.*/\.fmf/version)$'
verbose: false
pass_filenames: true
language: python
language_version: python3

- id: tmt-tests-lint
name: tmt tests lint
entry: bash -c "git ls-files --error-unmatch $(python3 -c 'import tmt; print(tmt.Tree(logger=tmt.Logger.create(), path=\".\").root)')/.fmf/version && tmt tests lint --failed-only --source $@" PAD
files: '.*\.fmf$'
entry: python -m tmt._pre_commit --pre-check tests lint --failed-only --source
files: '(?:.*\.fmf|.*/\.fmf/version)$'
verbose: false
pass_filenames: true
language: python
language_version: python3

- id: tmt-plans-lint
name: tmt plans lint
entry: bash -c "git ls-files --error-unmatch $(python3 -c 'import tmt; print(tmt.Tree(logger=tmt.Logger.create(), path=\".\").root)')/.fmf/version && tmt plans lint --failed-only --source $@" PAD
files: '.*\.fmf$'
entry: python -m tmt._pre_commit --pre-check plans lint --failed-only --source
files: '(?:.*\.fmf|.*/\.fmf/version)$'
verbose: false
pass_filenames: true
language: python
language_version: python3

- id: tmt-stories-lint
name: tmt stories lint
entry: bash -c "git ls-files --error-unmatch $(python3 -c 'import tmt; print(tmt.Tree(logger=tmt.Logger.create(), path=\".\").root)')/.fmf/version && tmt stories lint --failed-only --source $@" PAD
files: '.*\.fmf$'
entry: python -m tmt._pre_commit --pre-check stories lint --failed-only --source
files: '(?:.*\.fmf|.*/\.fmf/version)$'
verbose: false
pass_filenames: true
language: python
Expand Down
21 changes: 21 additions & 0 deletions tests/precommit/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,27 @@ EOF
rlAssertNotGrep '/good' $rlRun_LOG
rlAssertGrep '/wrong' $rlRun_LOG

# Check it works in different fmf_root
rlRun "mkdir tmt_root"
rlRun -s "git mv .fmf/ tmt_root/.fmf/"
# Should fail because fmf_root is in different location
# (Also tests that pre-commit runs when .fmf/version is changed)
rlRun -s "git commit -m 'wrong_fmf_root'" "1"
rlAssertGrep "$expected_command.*Failed" $rlRun_LOG
# Add the correct root
cat <<EOF > .pre-commit-config.yaml
repos:
- repo: $REPO
rev: "$REV"
hooks:
- id: "$hook"
args: [ --root, tmt_root ]
EOF
rlRun -s "git add .pre-commit-config.yaml"
rlRun -s "git mv main.fmf tmt_root"
rlRun -s "git commit -m 'pass different root'"
rlAssertGrep "$expected_command.*Passed" $rlRun_LOG

rlRun "popd"
rlRun "rm -rf $tmp" 0 "Removing tmp directory"
rlPhaseEnd
Expand Down
Empty file added tmt/_pre_commit/__init__.py
Empty file.
67 changes: 67 additions & 0 deletions tmt/_pre_commit/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import re
import sys

from tmt.__main__ import run_cli


def _run_precommit() -> None: # pyright: ignore[reportUnusedFunction] (used by project.scripts)
"""
A simple wrapper that re-orders cli arguments before :py:func:`run_cli`.
This utility is needed in order to move arguments like ``--root`` before
the ``lint`` keyword when run by ``pre-commit``.
Only a limited number of arguments are reordered.
"""

# Only re-ordering a few known/necessary cli arguments of `main` command
# Could be improved if the click commands can be introspected like with
# `attrs.fields`
# https://github.com/pallets/click/issues/2709

argv = sys.argv
# Get the last argument that starts with `-`. Other inputs after that are
# assumed to be filenames (which can be thousands of them)
for last_arg in reversed(range(len(argv))):
if argv[last_arg].startswith("-"):
break
else:
# If there were no args passed, then just `run_cli`
run_cli()
return

# At this point we need to check and re-order the arguments if needed
for pattern, nargs in [
(r"(--root$|-r)", 1),
(r"(--root=.*)", 0),
(r"(--verbose$|-v+)", 0),
(r"(--debug$|-d+)", 0),
(r"(--pre-check$)", 0),
]:
if any(match := re.match(pattern, arg) for arg in argv[1:last_arg + 1]):
assert match
# Actual argument matched
actual_arg = match.group(1)
indx = argv.index(actual_arg)
# Example of reorder args:
# ["tmt", "tests", "lint", "--fix", "--root", "/some/path", "some_file"]
# - argv[0]: name of the program is always first
# ["tmt"]
# - argv[indx:indx+1+nargs]: args to move (pass to `tmt.cli.main`)
# ["--root", "/some/path"]
# - argv[1:indx]: all other keywords (`lint` keyword is in here)
# ["tests", "lint", "--fix"]
# - argv[indx+1+nargs:]: All remaining keywords
# ["some_file"]
# After reorder:
# ["tmt", "--root", "/some/path", "tests", "lint", "--fix", "some_file"]
argv = (
argv[0:1] + argv[indx: indx + 1 + nargs] + argv[1:indx] + argv[indx + 1 + nargs:]
)
# Finally move the reordered args to sys.argv and run the cli
sys.argv = argv
run_cli()


if __name__ == "__main__":
_run_precommit()
17 changes: 17 additions & 0 deletions tmt/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,13 +307,18 @@ def write_dl(
'--force-color', is_flag=True, default=False,
help='Forces tmt to use colors in the output and logging.'
)
@option(
'--pre-check', is_flag=True, default=False, hidden=True,
help='Run pre-checks on the git root. (Used by pre-commit wrapper).'
)
def main(
click_contex: Context,
root: str,
context: list[str],
no_color: bool,
force_color: bool,
show_time: bool,
pre_check: bool,
**kwargs: Any) -> None:
""" Test Management Tool """

Expand All @@ -339,6 +344,18 @@ def main(
# Save click context and fmf context for future use
tmt.utils.Common.store_cli_invocation(click_contex)

# Run pre-checks
if pre_check:
git_command = tmt.utils.Command('git', 'rev-parse', '--show-toplevel')
git_root = git_command.run(cwd=None, logger=logger).stdout
if not git_root:
raise tmt.utils.RunError("git rev-parse did not produce a path", git_command, 0)
git_root = git_root.strip()
git_command = tmt.utils.Command(
'git', 'ls-files', '--error-unmatch', f"{git_root}/{root}/.fmf/version"
)
git_command.run(cwd=None, logger=logger)

# Initialize metadata tree (from given path or current directory)
tree = tmt.Tree(logger=logger, path=Path(root))

Expand Down
1 change: 1 addition & 0 deletions tmt/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ def option(
metavar: Optional[str] = None,
prompt: Optional[str] = None,
envvar: Optional[str] = None,
hidden: bool = False,
# Following parameters are our additions.
choices: Optional[Sequence[str]] = None,
deprecated: Optional[Deprecated] = None) -> ClickOptionDecoratorType:
Expand Down

0 comments on commit 8b6a819

Please sign in to comment.