feat(licenses_collector): update license collection by adding detailed frontend dependency information and improving license notice generation

This commit is contained in:
Ivan
2026-04-16 19:19:47 -05:00
parent 5221ca36ce
commit 5416c71094
8 changed files with 8127 additions and 77 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+8 -3
View File
@@ -449,9 +449,14 @@ def write_embedded_license_artifacts(repo_root: Path | None = None) -> dict[str,
frontend_path = data_dir / _FRONTEND_LICENSES_FILENAME
notices_path = data_dir / _THIRD_PARTY_NOTICES_FILENAME
frontend_rows = frontend if isinstance(frontend, list) else []
should_write_frontend = bool(frontend_rows) or not frontend_path.exists() or frontend_source in (
"pnpm",
"node_modules",
should_write_frontend = (
bool(frontend_rows)
or not frontend_path.exists()
or frontend_source
in (
"pnpm",
"node_modules",
)
)
if should_write_frontend:
frontend_path.write_text(
+1 -1
View File
@@ -963,7 +963,7 @@
"licenses": {
"section_label": "Rechtliches",
"title": "Lizenzen Dritter",
"description": "Versionen, Autoren und SPDX- oder deklarierte Lizenzangaben zur Laufzeit. Daten stammen aus der installierten Python-Umgebung und von pnpm, falls verfügbar.",
"description": "Versionen, Autoren und SPDX- oder deklarierte Lizenzangaben zur Laufzeit. Daten stammen aus der installierten Python-Umgebung. Frontend-Daten nutzen pnpm, falls es funktioniert; sonst werden Pakete aus node_modules gelesen (z. B. wenn pnpm licenses an der Lockfile scheitert).",
"short_description": "Versionen, Autoren und Lizenzen für Backend und Frontend.",
"search_placeholder": "Pakete, Versionen, Autoren, Lizenzen suchen...",
"generated_at": "Erstellt um {time}",
+1 -1
View File
@@ -1025,7 +1025,7 @@
"licenses": {
"section_label": "Legal",
"title": "Third-party licenses",
"description": "Runtime dependency versions, authors, and SPDX or declared license strings. Data is collected from the installed Python environment and from pnpm when available.",
"description": "Runtime dependency versions, authors, and SPDX or declared license strings. Data is collected from the installed Python environment. Frontend data uses pnpm when it works; otherwise packages are read from node_modules (e.g. when pnpm licenses fails on the lockfile).",
"short_description": "Dependency versions, authors, and licenses for backend and frontend.",
"search_placeholder": "Search packages, versions, authors, licenses...",
"generated_at": "Generated at {time}",
+1 -1
View File
@@ -1075,7 +1075,7 @@
"licenses": {
"section_label": "Note legali",
"title": "Licenze di terze parti",
"description": "Versioni, autori e licenze SPDX o dichiarate delle dipendenze a runtime. I dati provengono dall'ambiente Python installato e da pnpm se disponibile.",
"description": "Versioni, autori e licenze SPDX o dichiarate delle dipendenze a runtime. I dati provengono dall'ambiente Python installato. Per il frontend si usa pnpm se funziona; altrimenti i pacchetti si leggono da node_modules (ad es. se pnpm licenses fallisce sul lockfile).",
"short_description": "Versioni, autori e licenze per backend e frontend.",
"search_placeholder": "Cerca pacchetti, versioni, autori, licenze...",
"generated_at": "Generato alle {time}",
+1 -1
View File
@@ -963,7 +963,7 @@
"licenses": {
"section_label": "Правовая информация",
"title": "Лицензии сторонних компонентов",
"description": "Версии, авторы и SPDX или заявленные лицензии зависимостей во время работы. Данные берутся из установленной среды Python и из pnpm, если доступен.",
"description": "Версии, авторы и SPDX или заявленные лицензии зависимостей во время работы. Данные берутся из установленной среды Python. Для фронтенда используется pnpm, если команда работает; иначе пакеты читаются из node_modules (например, если pnpm licenses падает на lockfile).",
"short_description": "Версии, авторы и лицензии для бэкенда и фронтенда.",
"search_placeholder": "Поиск по пакетам, версиям, авторам, лицензиям...",
"generated_at": "Сформировано: {time}",
+35
View File
@@ -4,8 +4,10 @@ from pathlib import Path
from unittest.mock import patch
from meshchatx.src.backend.licenses_collector import (
_filter_out_workspace_root_package,
_flatten_pnpm_licenses_json,
build_licenses_payload,
collect_frontend_from_node_modules,
render_third_party_notices,
write_embedded_license_artifacts,
)
@@ -36,6 +38,39 @@ def test_flatten_pnpm_licenses_json_maps_and_sorts():
assert nov["version"] == "?"
def test_filter_out_workspace_root_package_drops_app_not_deps(tmp_path):
(tmp_path / "package.json").write_text(
'{"name":"my-app","version":"1.0.0"}\n',
encoding="utf-8",
)
rows = [
{"name": "my-app", "version": "1.0.0", "author": "X", "license": "MIT"},
{"name": "left-pad", "version": "1.0.0", "author": "Y", "license": "MIT"},
]
out = _filter_out_workspace_root_package(rows, tmp_path)
assert len(out) == 1
assert out[0]["name"] == "left-pad"
def test_collect_frontend_from_node_modules_dedupes_and_reads_license(tmp_path):
nm = tmp_path / "node_modules"
(nm / "alpha").mkdir(parents=True)
(nm / "alpha" / "package.json").write_text(
'{"name":"alpha","version":"1.0.0","license":"MIT","author":"A"}',
encoding="utf-8",
)
(nm / "nested" / "beta").mkdir(parents=True)
(nm / "nested" / "beta" / "package.json").write_text(
'{"name":"beta","version":"2.0.0","license":{"type":"Apache-2.0"}}',
encoding="utf-8",
)
rows = collect_frontend_from_node_modules(tmp_path)
names = [r["name"] for r in rows]
assert "alpha" in names and "beta" in names
beta = next(r for r in rows if r["name"] == "beta")
assert beta["license"] == "Apache-2.0"
def test_flatten_pnpm_licenses_json_non_dict_package_skipped():
data = {"MIT": ["not-a-dict", {"name": "ok", "versions": ["1"], "author": "x"}]}
rows = _flatten_pnpm_licenses_json(data)