From 09a0e838946a4b7cb615968fb524a9e18326cd7c Mon Sep 17 00:00:00 2001 From: "Augusto W. Andreoli" Date: Sun, 21 Mar 2021 20:42:59 +0100 Subject: [PATCH] feat: root files for other programming languages (#321) * feat: add .pre-commit-config.yaml as a root file * test: run raises QuitComplainingError when no root dir found * feat: add Rust, Golang and JavaScript root files --- docs/auto_detection.rst | 23 ++++++++++++++--------- docs/targets.rst | 1 + src/nitpick/constants.py | 33 +++++++++++++++++++++++++++++---- tests/helpers.py | 6 +++++- tests/test_config.py | 7 ++++++- 5 files changed, 55 insertions(+), 15 deletions(-) diff --git a/docs/auto_detection.rst b/docs/auto_detection.rst index 0b27a770..ed9634a0 100644 --- a/docs/auto_detection.rst +++ b/docs/auto_detection.rst @@ -10,15 +10,20 @@ Root dir of the project Nitpick_ tries to find the root dir of the project using some hardcoded assumptions. -#. Starting from the current working directory, it will search for files that are usually in the root of a Python project: - - - ``pyproject.toml`` - - ``setup.py`` - - ``setup.cfg`` - - ``requirements*.txt`` - - ``Pipfile`` (Pipenv_) - - ``app.py`` and ``wsgi.py`` (`Flask CLI`_) - - ``autoapp.py`` +#. Starting from the current working directory, it will search for files that are usually in the root of a project: + + - ``.pre-commit-config.yaml`` (pre-commit_) + - ``pyproject.toml`` + - ``setup.py`` + - ``setup.cfg`` + - ``requirements*.txt`` + - ``Pipfile`` (Pipenv_) + - ``tox.ini`` (tox_) + - ``package.json`` (JavaScript, NodeJS) + - ``Cargo.*`` (Rust) + - ``go.mod``, ``go.sum`` (Golang) + - ``app.py`` and ``wsgi.py`` (`Flask CLI`_) + - ``autoapp.py`` (Flask_) #. If none of these root files were found, search for ``manage.py``. On Django_ projects, it can be in another dir inside the root dir (:issue:`21`). diff --git a/docs/targets.rst b/docs/targets.rst index 2b03fb08..5e3261ef 100644 --- a/docs/targets.rst +++ b/docs/targets.rst @@ -11,6 +11,7 @@ .. _Django: https://github.com/django/django .. _EditorConfig: https://editorconfig.org .. _flake8: https://gitlab.com/pycqa/flake8 +.. _Flask: https://github.com/pallets/flask/ .. _Flask CLI: https://flask.palletsprojects.com/en/1.1.x/cli/ .. _Invoke: https://github.com/pyinvoke/invoke .. _IPython: https://github.com/ipython/ipython diff --git a/src/nitpick/constants.py b/src/nitpick/constants.py index 3f5ec909..40cd8046 100644 --- a/src/nitpick/constants.py +++ b/src/nitpick/constants.py @@ -14,15 +14,40 @@ READ_THE_DOCS_URL = "https://nitpick.rtfd.io/en/latest/" # Special files +# Python PYPROJECT_TOML = "pyproject.toml" +SETUP_PY = "setup.py" SETUP_CFG = "setup.cfg" -ROOT_PYTHON_FILES = ("setup.py", "app.py", "wsgi.py", "autoapp.py") -ROOT_FILES = (PYPROJECT_TOML, SETUP_CFG, "requirements*.txt", "Pipfile") + ROOT_PYTHON_FILES +REQUIREMENTS_STAR_TXT = "requirements*.txt" +PIPFILE_STAR = "Pipfile.*" +ROOT_PYTHON_FILES = ("app.py", "wsgi.py", "autoapp.py") MANAGE_PY = "manage.py" -PRE_COMMIT_CONFIG_YAML = ".pre-commit-config.yaml" -EDITOR_CONFIG = ".editorconfig" TOX_INI = "tox.ini" PYLINTRC = ".pylintrc" +# Tools +PRE_COMMIT_CONFIG_YAML = ".pre-commit-config.yaml" +EDITOR_CONFIG = ".editorconfig" +# JavaScript +PACKAGE_JSON = "package.json" +# Rust +CARGO_STAR = "Cargo.*" +# Golang +GO_MOD = "go.mod" +GO_SUM = "go.sum" +# All root files +ROOT_FILES = ( + PRE_COMMIT_CONFIG_YAML, + PYPROJECT_TOML, + SETUP_PY, + SETUP_CFG, + REQUIREMENTS_STAR_TXT, + PIPFILE_STAR, + TOX_INI, + PACKAGE_JSON, + CARGO_STAR, + GO_MOD, + GO_SUM, +) + ROOT_PYTHON_FILES SINGLE_QUOTE = "'" DOUBLE_QUOTE = '"' diff --git a/tests/helpers.py b/tests/helpers.py index f643d079..d258027d 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -323,10 +323,14 @@ def _simulate_cli(self, command: str, str_or_lines: StrOrList = None, *args: str expected = list(always_iterable(str_or_lines)) return result, actual, expected - def cli_run(self, str_or_lines: StrOrList = None, apply=False, violations=0) -> "ProjectMock": + def cli_run(self, str_or_lines: StrOrList = None, apply=False, violations=0, exception_class=None) -> "ProjectMock": """Assert the expected CLI output for the chosen command.""" cli_args = [] if apply else ["--check"] result, actual, expected = self._simulate_cli("run", str_or_lines, *cli_args) + if exception_class: + assert isinstance(result.exception, exception_class) + return self + if violations: expected.append(f"Violations: ❌ {violations} to change manually.") elif str_or_lines: diff --git a/tests/test_config.py b/tests/test_config.py index f8767b2f..eb9e55f7 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -3,6 +3,7 @@ from nitpick.constants import PYPROJECT_TOML, SETUP_CFG from nitpick.core import Nitpick +from nitpick.exceptions import QuitComplainingError from tests.helpers import ProjectMock @@ -19,10 +20,14 @@ def test_singleton(): def test_no_root_dir(tmp_path): """No root dir.""" - ProjectMock(tmp_path, pyproject_toml=False, setup_py=False).create_symlink("hello.py").flake8().assert_single_error( + project = ProjectMock(tmp_path, pyproject_toml=False, setup_py=False) + project.create_symlink("hello.py").flake8().assert_single_error( "NIP101 No root dir found (is this a Python project?)" ) + # TODO: don't abort with QuitComplainingError when root files are missing + project.cli_run(exception_class=QuitComplainingError) + def test_multiple_root_dirs(tmp_path): """Multiple possible "root dirs" found (e.g.: a requirements.txt file inside a docs dir)."""