diff --git a/setup.cfg b/setup.cfg index 01ef0bf..7c50c30 100644 --- a/setup.cfg +++ b/setup.cfg @@ -73,6 +73,7 @@ testing = pytest-cov pytest-xdist pytest-randomly + repo-review; python_version>="3.10" typecheck = mypy @@ -85,6 +86,10 @@ console_scripts = validate_pyproject.tool_schema = setuptools = validate_pyproject.api:load_builtin_plugin distutils = validate_pyproject.api:load_builtin_plugin +repo_review.checks = + validate_pyproject = validate_pyproject.repo_review:repo_review_checks +repo_review.families = + validate_pyproject = validate_pyproject.repo_review:repo_review_families [tool:pytest] # Specify command line options as you would do when invoking pytest directly. diff --git a/src/validate_pyproject/repo_review.py b/src/validate_pyproject/repo_review.py new file mode 100644 index 0000000..09fc779 --- /dev/null +++ b/src/validate_pyproject/repo_review.py @@ -0,0 +1,36 @@ +from typing import Any, Dict + +import fastjsonschema + +from . import api, plugins + +__all__ = ["VPP001", "repo_review_checks", "repo_review_families"] + + +class VPP001: + """Validate pyproject.toml""" + + family = "validate-pyproject" + + @staticmethod + def check(pyproject: Dict[str, Any]) -> str: + validator = api.Validator() + try: + validator(pyproject) + return "" + except fastjsonschema.JsonSchemaValueException as e: + return f"Invalid pyproject.toml! Error: {e}" + + +def repo_review_checks() -> Dict[str, VPP001]: + return {"VPP001": VPP001()} + + +def repo_review_families(pyproject: Dict[str, Any]) -> Dict[str, Dict[str, str]]: + has_distutils = "distutils" in pyproject.get("tool", {}) + plugin_names = (ep.name for ep in plugins.iterate_entry_points()) + plugin_list = ( + f"`[tool.{n}]`" for n in plugin_names if n != "distutils" or has_distutils + ) + descr = f"Checks `[build-system]`, `[project]`, {', '.join(plugin_list)}" + return {"validate-pyproject": {"name": "Validate-PyProject", "description": descr}} diff --git a/tests/test_repo_review.py b/tests/test_repo_review.py new file mode 100644 index 0000000..801ea52 --- /dev/null +++ b/tests/test_repo_review.py @@ -0,0 +1,40 @@ +from pathlib import Path + +import pytest + +repo_review_processor = pytest.importorskip("repo_review.processor") + +DIR = Path(__file__).parent.resolve() +EXAMPLES = DIR / "examples" +INVALID_EXAMPLES = DIR / "invalid-examples" + + +@pytest.mark.parametrize("name", ["atoml", "flit", "pdm", "pep_text", "trampolim"]) +def test_valid_example(name: str) -> None: + processed = repo_review_processor.process(EXAMPLES / name) + assert all(r.result for r in processed.results), f"{processed.results}" + + +@pytest.mark.parametrize("name", ["pdm/invalid-version", "pdm/redefining-as-dynamic"]) +def test_invalid_example(name: str) -> None: + processed = repo_review_processor.process(INVALID_EXAMPLES / name) + assert any( + not r.result and r.result is not None for r in processed.results + ), f"{processed.results}" + + +def test_no_distutils() -> None: + processed = repo_review_processor.process(EXAMPLES / "pep_text") + family = processed.families["validate-pyproject"] + assert "[tool.setuptools]" in family["description"] + assert "[tool.distutils]" not in family["description"] + + +def test_has_distutils(tmp_path: Path) -> None: + d = tmp_path / "no-distutils" + d.mkdir() + d.joinpath("pyproject.toml").write_text("[tool.distutils]") + processed = repo_review_processor.process(d) + family = processed.families["validate-pyproject"] + assert "[tool.setuptools]" in family["description"] + assert "[tool.distutils]" in family["description"]