diff --git a/exasol/toolbox/nox/tasks.py b/exasol/toolbox/nox/tasks.py index 2fa04e388..106dfb8ee 100644 --- a/exasol/toolbox/nox/tasks.py +++ b/exasol/toolbox/nox/tasks.py @@ -1,5 +1,11 @@ from __future__ import annotations +from io import ( + BytesIO, + TextIOWrapper, +) +from subprocess import run + __all__ = [ "Mode", "fix", @@ -239,6 +245,38 @@ def _coverage( session.run(*command) +@nox.session(name="audit", python=False) +def audit(session: Session) -> None: + """Audit project dependencies in regard of their license.""" + + def _packages(): + result = run( + ["poetry", "show", "--no-ansi", "--no-interaction", "--only", "main"], + capture_output=True, + check=True, + ) + stream = TextIOWrapper(BytesIO(result.stdout)) + lines = (line for line in stream) + return (line.split(" ")[0] for line in lines) + + packages = [ + package + for package in _packages() + if package not in PROJECT_CONFIG.audit_exceptions + ] + session.run( + "poetry", + "run", + "python", + "-m", + "piplicenses", + "--packages", + *packages, + "--allow-only", + ";".join(PROJECT_CONFIG.audit_licenses), + ) + + @nox.session(name="build-docs", python=False) def build_docs(session: Session) -> None: """Builds the project documentation""" diff --git a/noxconfig.py b/noxconfig.py index 3501a8253..d6a5b5534 100644 --- a/noxconfig.py +++ b/noxconfig.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass +from inspect import cleandoc from pathlib import Path from typing import ( Any, @@ -18,6 +19,26 @@ class Config: version_file: Path = Path(__file__).parent / "exasol" / "toolbox" / "version.py" path_filters: Iterable[str] = ("dist", ".eggs", "venv") + audit_licenses = ["Apache Software License"] + audit_exceptions = { + "pylint": cleandoc( + """ + The project only makes use of pylint command line. + + It only was added as normal dependency to save the "clients" the step + of manually adding it as dependency. + + Note(s): + + Pylint could be marked, added as optional (extra) dependency to make it obvious + that it is an opt in, controlled by the "user/client". + + Replacing pylint with an alternative (like `ruff `_) + with a more would remove the ambiguity and need for justification. + """ + ) + } + @staticmethod def pre_integration_tests_hook( _session: Session, _config: Config, _context: MutableMapping[str, Any]