Files
penpot/scripts/test_sync_pnpm_version.py
Andrey Antukh 183e31f18f 🔥 Remove corepack, use system pnpm everywhere
Corepack is gone from Node 25+, so every `corepack enable` call
fails. pnpm now ships as a system binary (devenv, CI runners and
Docker images install it directly) and auto-downloads the version
pinned in `packageManager` on mismatch.

Scripts, workflows and Dockerfiles call `pnpm` straight away; the
three deploy workflows use a single `pnpm/setup@v2` step; and the
new `scripts/sync-pnpm-version` stamps all 35 `packageManager`
fields from the system pnpm, replacing the `corepack use` sweep.

AI-assisted-by: muse-spark-1.3-contributor
2026-09-20 11:42:37 +02:00

153 lines
5.0 KiB
Python

#!/usr/bin/env python3
"""Tests for scripts/sync-pnpm-version.
Run with:
python3 scripts/test_sync_pnpm_version.py
Covers stamping the `packageManager` field across a package.json tree:
stale values get updated, missing fields get inserted, formatting of each
file is preserved (only the stamped line may change), --check reports
drift without writing, and stamping is idempotent.
"""
import json
import pathlib
import shutil
import subprocess
import sys
import tempfile
import unittest
# Loading scripts/sync-pnpm-version via subprocess; no bytecode emitted.
sys.dont_write_bytecode = True
SCRIPT_PATH = pathlib.Path(__file__).resolve().parent / "sync-pnpm-version"
FIELD = "pnpm@99.0.0+sha512." + "ab" * 64
def run_script(*args):
"""Run the script, returning the CompletedProcess."""
return subprocess.run(
["bash", str(SCRIPT_PATH), *args],
capture_output=True,
text=True,
)
def make_fixture(root):
"""Build a 3-file tree: stale value, already synced, missing field."""
stale = root / "stale"
stale.mkdir()
(stale / "package.json").write_text(
'{\n'
' "name": "stale",\n'
' "version": "1.0.0",\n'
' "private": true,\n'
' "packageManager": "pnpm@10.0.0+sha512.' + "00" * 64 + '",\n'
' "scripts": {\n'
' "test": "echo ok"\n'
' }\n'
'}\n'
)
synced = root / "synced"
synced.mkdir()
# 4-space indent on purpose: the stamp must not reformat the file.
(synced / "package.json").write_text(
'{\n'
' "name": "synced",\n'
' "version": "1.0.0",\n'
f' "packageManager": "{FIELD}"\n'
'}\n'
)
missing = root / "missing"
missing.mkdir()
(missing / "package.json").write_text(
'{\n'
' "name": "missing",\n'
' "version": "1.0.0",\n'
' "scripts": {\n'
' "test": "echo ok"\n'
' }\n'
'}\n'
)
return stale, synced, missing
class SyncPnpmVersionTests(unittest.TestCase):
def setUp(self):
self.tmp = pathlib.Path(tempfile.mkdtemp(prefix="sync-pnpm-"))
self.stale, self.synced, self.missing = make_fixture(self.tmp)
self.synced_before = (self.synced / "package.json").read_bytes()
def tearDown(self):
shutil.rmtree(self.tmp, ignore_errors=True)
def stamp(self, *extra):
return run_script("--root", str(self.tmp), "--field", FIELD, *extra)
def read(self, path):
return (path / "package.json").read_text()
def test_stamp_updates_stale_inserts_missing_keeps_synced(self):
proc = self.stamp()
self.assertEqual(proc.returncode, 0, proc.stderr)
stale_lines = self.read(self.stale).splitlines()
self.assertIn(f' "packageManager": "{FIELD}",', stale_lines)
data = json.loads(self.read(self.stale))
self.assertEqual(data["packageManager"], FIELD)
# Only the packageManager line changed in the stale file.
self.assertEqual(len(stale_lines), 9)
# The already-synced file is byte-identical (indent preserved).
self.assertEqual(
(self.synced / "package.json").read_bytes(), self.synced_before
)
# The missing field was inserted; the file stays valid JSON.
data = json.loads(self.read(self.missing))
self.assertEqual(data["packageManager"], FIELD)
self.assertEqual(data["name"], "missing")
def test_check_passes_once_synced(self):
self.assertEqual(self.stamp().returncode, 0)
proc = self.stamp("--check")
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
def test_check_fails_on_drift_without_writing(self):
self.assertEqual(self.stamp().returncode, 0)
before = (self.stale / "package.json").read_bytes()
(self.stale / "package.json").write_text(
self.read(self.stale).replace(FIELD, "pnpm@1.0.0+sha512." + "ff" * 64)
)
proc = self.stamp("--check")
self.assertNotEqual(proc.returncode, 0)
self.assertIn("stale/package.json", proc.stdout + proc.stderr)
# --check must not write: reverting the tamper restores a pass.
(self.stale / "package.json").write_bytes(before)
self.assertEqual(self.stamp("--check").returncode, 0)
def test_check_reports_missing_field(self):
proc = self.stamp("--check")
self.assertNotEqual(proc.returncode, 0)
self.assertIn("missing/package.json", proc.stdout + proc.stderr)
def test_stamp_is_idempotent(self):
self.assertEqual(self.stamp().returncode, 0)
first = {
p: (self.tmp / p / "package.json").read_bytes()
for p in ("stale", "synced", "missing")
}
second = self.stamp()
self.assertEqual(second.returncode, 0, second.stderr)
for name, content in first.items():
self.assertEqual(
(self.tmp / name / "package.json").read_bytes(), content
)
if __name__ == "__main__":
unittest.main()