diff --git a/MANIFEST.in b/MANIFEST.in index 384a7b5441..7363b92974 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,3 +4,4 @@ graft nf_core/module-template graft nf_core/pipeline-template graft nf_core/subworkflow-template include requirements.txt +include .pre-commit-config.yaml diff --git a/nf_core/lint_utils.py b/nf_core/lint_utils.py index b2521daef9..b86e1a853d 100644 --- a/nf_core/lint_utils.py +++ b/nf_core/lint_utils.py @@ -1,5 +1,6 @@ import logging import subprocess +from pathlib import Path import rich from rich.console import Console @@ -53,7 +54,7 @@ def print_fixes(lint_obj): def run_prettier_on_file(file): - """Runs Prettier on a file if Prettier is installed. + """Run the pre-commit hook prettier on a file. Args: file (Path | str): A file identifier as a string or pathlib.Path. @@ -62,12 +63,17 @@ def run_prettier_on_file(file): If Prettier is not installed, a warning is logged. """ + nf_core_pre_commit_config = Path(nf_core.__file__).parent.parent / ".pre-commit-config.yaml" try: subprocess.run( - ["prettier", "--write", file], - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - check=False, + ["pre-commit", "run", "--config", nf_core_pre_commit_config, "prettier", "--files", file], + capture_output=True, + check=True, ) - except FileNotFoundError: - log.warning("Prettier is not installed. Please install it and run it on the pipeline to fix linting issues.") + except subprocess.CalledProcessError as e: + if ": SyntaxError: " in e.stdout.decode(): + raise ValueError(f"Can't format {file} because it has a synthax error.\n{e.stdout.decode()}") from e + raise ValueError( + "There was an error running the prettier pre-commit hook.\n" + f"STDOUT: {e.stdout.decode()}\nSTDERR: {e.stderr.decode()}" + ) from e diff --git a/requirements-dev.txt b/requirements-dev.txt index 33692786fe..42ce780ce4 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,7 +1,6 @@ black isort myst_parser -pre-commit pytest-cov pytest-datafiles requests-mock diff --git a/requirements.txt b/requirements.txt index c60791b0e5..b3d1f251bf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,6 +6,7 @@ jinja2 jsonschema>=3.0 markdown>=3.3 packaging +pre-commit prompt_toolkit>=3.0.3 pytest>=7.0.0 pytest-workflow>=1.6.0 diff --git a/tests/test_lint_utils.py b/tests/test_lint_utils.py new file mode 100644 index 0000000000..d5af915fae --- /dev/null +++ b/tests/test_lint_utils.py @@ -0,0 +1,65 @@ +import shutil + +import git +import pytest + +import nf_core.lint_utils + +JSON_WITH_SYNTAX_ERROR = "{'a':1, 1}" +JSON_MALFORMED = "{'a':1}" +JSON_FORMATTED = '{ "a": 1 }\n' + +WHICH_PRE_COMMIT = shutil.which("pre-commit") + + +@pytest.fixture() +def temp_git_repo(tmp_path_factory): + tmp_git_dir = tmp_path_factory.mktemp("tmp_git_dir") + repo = git.Repo.init(tmp_git_dir) + return tmp_git_dir, repo + + +@pytest.fixture(name="formatted_json") +def git_dir_with_json(temp_git_repo): + tmp_git_dir, repo = temp_git_repo + file = tmp_git_dir / "formatted.json" + with open(file, "w", encoding="utf-8") as f: + f.write(JSON_FORMATTED) + repo.git.add(file) + return file + + +@pytest.fixture(name="malformed_json") +def git_dir_with_json_malformed(temp_git_repo): + tmp_git_dir, repo = temp_git_repo + file = tmp_git_dir / "malformed.json" + with open(file, "w", encoding="utf-8") as f: + f.write(JSON_MALFORMED) + repo.git.add(file) + return file + + +@pytest.fixture(name="synthax_error_json") +def git_dir_with_json_syntax_error(temp_git_repo): + tmp_git_dir, repo = temp_git_repo + file = tmp_git_dir / "synthax-error.json" + with open(file, "w", encoding="utf-8") as f: + f.write(JSON_WITH_SYNTAX_ERROR) + repo.git.add(file) + return file + + +def test_run_prettier_on_formatted_file(formatted_json): + nf_core.lint_utils.run_prettier_on_file(formatted_json) + assert formatted_json.read_text() == JSON_FORMATTED + + +def test_run_prettier_on_malformed_file(malformed_json): + nf_core.lint_utils.run_prettier_on_file(malformed_json) + assert malformed_json.read_text() == JSON_FORMATTED + + +def test_run_prettier_on_synthax_error_file(synthax_error_json): + with pytest.raises(ValueError) as exc_info: + nf_core.lint_utils.run_prettier_on_file(synthax_error_json) + assert exc_info.value.args[0].startswith(f"Can't format {synthax_error_json} because it has a synthax error.")