🔧 Skip build output when stamping the pnpm version

The script walks the filesystem, so it stamped generated copies too, such
as media-processor/target/package.json: --check counted files git does
not track and failed whenever one of those copies was stale. Prune
target/ like the other generated trees, with a test for it.

Memory: the JDK and ImageMagick image pins have traps the code cannot
show, now in workflow/docker-images; memory-maintenance gains the rule
that a memory must not restate what the code already says; updating-pnpm
notes the lockfile-only refresh.

AI-assisted-by: deepseek-v4.1-flash
This commit is contained in:
Andrey Antukh 2026-10-29 14:09:43 +00:00
parent 76d403cfdb
commit c70cc56299
6 changed files with 31 additions and 4 deletions

View File

@ -16,6 +16,7 @@ You are working on the GitHub project `penpot/penpot`, a monorepo.
- Before `gh issue create` → `mem:workflow/creating-issues` (title derivation, body template, labels, Issue Type)
- Before `gh pr create` / `gh pr edit` → `mem:workflow/creating-prs` (title format, body structure, "Note:" line)
- Before a repo-wide pnpm version update → `mem:workflow/updating-pnpm` (workspace layout, `scripts/sync-pnpm-version` flow, the stamp-missing-field and ignored-builds gotchas, verification steps)
- Before bumping a non-JS dependency pinned in `docker/images/` (JDK, ImageMagick) → `mem:workflow/docker-images`
- **Never `git push`, force-push, or modify `git origin`** (or any other remote). The user pushes from their own shell; if a push is required, say so and wait. Never amend a commit that the user has already pushed unless explicitly asked.
- **Never edit `CHANGES.md` by hand.** The changelog is generated from GitHub milestones during the release process; update it only via the `update-changelog` skill flow or on explicit user request.
- You have access to the GitHub CLI `gh` or corresponding MCP tools.

View File

@ -26,6 +26,7 @@ No manual line wrapping: one line per bullet or paragraph, however long. Memorie
## Add/update threshold
Add or update memories only with stable, non-obvious project conventions that avoid complex rediscovery in the future.
Do not restate what the code already says (comments included): keep only what code cannot represent — decisions and their reasons, cross-file invariants, ordering constraints, environment and tool behavior, and traps that break builds.
Do not add: quick-read facts; generic language/framework knowledge; one-off task notes; volatile line-level details; behavior likely to change soon.
## Maintenance Actions

View File

@ -0,0 +1,6 @@
# Non-JS dependencies in the production images
Node and pnpm pins: `mem:workflow/updating-node` and `mem:workflow/updating-pnpm`. Only the parts the Dockerfiles cannot show:
- JDK: the image tracks a non-LTS line, so there is no minor to pick — the last build of the line is the ceiling; moving line is a major and needs a real build to validate the `jlink` module list.
- ImageMagick: publish `penpotapp/imagemagick:<ver>` **before** bumping the `COPY --from` refs in the backend, exporter and devenv Dockerfiles; otherwise both builds break on the missing tag.

View File

@ -27,8 +27,8 @@ file (never pipe tool output through filters).
members) must carry a `packageManager` field with the identical
`pnpm@<version>+sha512.<hash>` value. Do not let them drift.
`external/` (vendored trees with their own lifecycles), `.opencode/`,
`.pnpm-store/`, `bundles/` and `docker/images/bundle-*` copies are
never stamped.
`.pnpm-store/`, `bundles/`, `target/` build output and
`docker/images/bundle-*` copies are never stamped.
- pnpm is a system binary everywhere (devenv image, CI runners, Docker
images). Nothing may call corepack: it is gone from Node 25+. pnpm
auto-downloads the `packageManager` version on mismatch
@ -60,6 +60,7 @@ file (never pipe tool output through filters).
4. Run `scripts/sync-pnpm-version --install` (plain `pnpm install` in
each of the 11 workspace roots) to refresh lockfile metadata, then
fix any failing workspace (see gotchas) and re-run that directory.
For a version-only bump, `pnpm install --lockfile-only` in each root is enough: it rewrites only the pnpm self-reference entries and needs no node_modules. The repo-root `pnpm-lock.yaml` is rewritten by itself on the first `pnpm` call that self-installs the target version.
## Gotchas

View File

@ -27,7 +27,8 @@ Options:
-h, --help Show this help.
external/ (vendored trees with their own lifecycles), .opencode/,
.pnpm-store/, bundles/ and docker build-context copies are never stamped.
.pnpm-store/, bundles/, build output (target/) and docker build-context
copies are never stamped.
EOF
}
@ -91,7 +92,7 @@ mapfile -t files < <(
find . \
\( -name .git -o -name node_modules -o -name .pnpm-store \
-o -name external -o -name .opencode -o -name bundles \
-o -name .angular \) -type d -prune \
-o -name target -o -name .angular \) -type d -prune \
-o -path './docker/images/bundle-*' -prune \
-o -name package.json -type f -print | sort
)

View File

@ -134,6 +134,23 @@ class SyncPnpmVersionTests(unittest.TestCase):
self.assertNotEqual(proc.returncode, 0)
self.assertIn("missing/package.json", proc.stdout + proc.stderr)
def test_target_dirs_are_never_stamped(self):
generated = self.tmp / "module" / "target"
generated.mkdir(parents=True)
package = generated / "package.json"
package.write_text(
'{\n'
' "name": "generated",\n'
' "packageManager": "pnpm@10.0.0+sha512.' + "00" * 64 + '"\n'
'}\n'
)
before = package.read_bytes()
self.assertEqual(self.stamp().returncode, 0)
self.assertEqual(package.read_bytes(), before)
# The stale copy must not make --check fail either.
self.assertEqual(self.stamp("--check").returncode, 0)
def test_stamp_is_idempotent(self):
self.assertEqual(self.stamp().returncode, 0)
first = {