diff --git a/graphify/manifest_ingest.py b/graphify/manifest_ingest.py index ae3aa61fc..18f39fffd 100644 --- a/graphify/manifest_ingest.py +++ b/graphify/manifest_ingest.py @@ -226,17 +226,20 @@ def _parse_pom(text: str) -> dict | None: text = re.sub(r'\sxmlns="[^"]*"', '', text, count=1) root = ET.fromstring(text) aid = root.findtext("artifactId") - gid = root.findtext("groupId") + gid = root.findtext("groupId") or root.findtext("parent/groupId") + version = root.findtext("version") or root.findtext("parent/version") if not aid: return None name = f"{gid}:{aid}" if gid else aid deps: list[str] = [] - for dep in root.findall(".//dependencies/dependency"): + project_deps = root.findall("dependencies/dependency") + profile_deps = root.findall("profiles/profile/dependencies/dependency") + for dep in project_deps + profile_deps: da = dep.findtext("artifactId") dg = dep.findtext("groupId") if da: deps.append(f"{dg}:{da}" if dg else da) - return {"name": name, "version": root.findtext("version"), "deps": deps} + return {"name": name, "version": version, "deps": deps} _PARSERS = { diff --git a/tests/test_manifest_ingest.py b/tests/test_manifest_ingest.py index 2b97f5fb9..74181b595 100644 --- a/tests/test_manifest_ingest.py +++ b/tests/test_manifest_ingest.py @@ -75,6 +75,55 @@ def test_pom_parses_artifact_and_deps(tmp_path): assert any(e["target"] == "pkg_org_lib_core" for e in r["edges"]) +def test_pom_includes_only_top_level_dependencies(tmp_path): + p = _write(tmp_path / "pom.xml", + 'com.acmeapp' + 'org.lib' + 'runtime') + r = extract_package_manifest(p) + deps = {e["target"] for e in r["edges"] if e["relation"] == "depends_on"} + assert deps == {"pkg_org_lib_runtime"} + + +def test_pom_excludes_dependency_management_and_plugin_dependencies(tmp_path): + p = _write(tmp_path / "pom.xml", + 'com.acmeapp' + 'org.managed' + 'bom-entry' + 'org.plugin' + 'helper' + '') + r = extract_package_manifest(p) + deps = {e["target"] for e in r["edges"] if e["relation"] == "depends_on"} + assert deps == set() + + +def test_pom_uses_parent_group_id_when_project_group_id_is_missing(tmp_path): + p = _write(tmp_path / "pom.xml", + 'com.parentparent' + '1.0child') + r = extract_package_manifest(p) + assert _pkg_nodes(r)[0]["label"] == "com.parent:child" + + +def test_pom_uses_parent_version_when_project_version_is_missing(tmp_path): + p = _write(tmp_path / "pom.xml", + 'com.parentparent' + '1.2.3child') + r = extract_package_manifest(p) + assert _pkg_nodes(r)[0]["version"] == "1.2.3" + + +def test_pom_includes_profile_dependencies(tmp_path): + p = _write(tmp_path / "pom.xml", + 'com.acmeapp' + 'optional-featureorg.profile' + 'feature') + r = extract_package_manifest(p) + deps = {e["target"] for e in r["edges"] if e["relation"] == "depends_on"} + assert deps == {"pkg_org_profile_feature"} + + # ── #1377: a package referenced by N manifests is ONE node ─────────────────── def test_apm_dependency_collapses_to_single_canonical_node(tmp_path):