Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion scripts/ci/materialize_base_javascript_packages.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
#!/usr/bin/env python3
"""Materialize pnpm locks from a validated pull-request base commit."""
"""Materialize pnpm locks from a validated pull-request base commit.

A ``pnpm-lock.yaml`` whose sibling ``package.json`` does not pin an exact pnpm
``packageManager`` is treated as a genuine pnpm project only when no sibling
``package-lock.json`` exists; otherwise it is a vestigial second lockfile in an
npm-managed project and is skipped so the downstream npm install path handles it
instead of failing coverage evidence.
"""

from __future__ import annotations

Expand Down Expand Up @@ -97,6 +104,14 @@ def base_pnpm_projects(
if not isinstance(package_manager, str) or not PNPM_SPEC_RE.fullmatch(
package_manager
):
if str(project_root / "package-lock.json") in regular_paths:
# A sibling package-lock.json means npm owns this project and
# the pnpm-lock.yaml is a vestigial second lockfile. Skip pnpm
# materialization so the downstream npm (package-lock.json)
# install path handles it, instead of failing the whole
# coverage-evidence job. A genuine pnpm-only project (no sibling
# package-lock.json) still must pin an exact pnpm packageManager.
continue
raise ValueError(
f"trusted base package manifest {package_path} must declare an exact pnpm packageManager version"
)
Expand Down
28 changes: 28 additions & 0 deletions tests/test_materialize_base_javascript_packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,34 @@ def fake_git(_repo_root: Path, _command: str, object_spec: str) -> bytes:
materializer.base_pnpm_projects(tmp_path, "a" * 40)


def test_skips_npm_project_with_vestigial_pnpm_lock(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""An npm project's stray pnpm-lock.yaml is skipped, not fail-closed.

A base tree with a ``pnpm-lock.yaml`` plus a sibling ``package-lock.json``
and no exact pnpm ``packageManager`` is npm-managed, so pnpm materialization
is skipped (the downstream npm install path owns it) rather than failing the
whole coverage-evidence job.
"""
regular_paths = {
"frontend/package.json",
"frontend/pnpm-lock.yaml",
"frontend/package-lock.json",
}
monkeypatch.setattr(
materializer, "_regular_base_paths", lambda *_args: regular_paths
)

def fake_git(_repo_root: Path, _command: str, object_spec: str) -> bytes:
if object_spec.endswith(":frontend/package.json"):
return b"{}"
raise AssertionError(f"unexpected git object: {object_spec}")

monkeypatch.setattr(materializer, "_git", fake_git)
assert materializer.base_pnpm_projects(tmp_path, "a" * 40) == []


def test_rejects_mutable_or_non_pnpm_package_manager(tmp_path: Path) -> None:
"""Only an exact pnpm runner specification may populate the trusted store."""
repo, base_sha = fixture_repo(tmp_path)
Expand Down
Loading