Skip to content

Build: Preserve plugin ZIP modified time when contents are unchanged - #2566

Merged
westonruter merged 1 commit into
trunkfrom
fix/preserve-zip-mtime-when-unchanged
Jul 7, 2026
Merged

Build: Preserve plugin ZIP modified time when contents are unchanged#2566
westonruter merged 1 commit into
trunkfrom
fix/preserve-zip-mtime-when-unchanged

Conversation

@westonruter

@westonruter westonruter commented Jul 3, 2026

Copy link
Copy Markdown
Member

Summary

Make build-plugins:zip leave an existing plugin ZIP file — and its modified time — untouched when a rebuild produces identical contents. The modified time now only changes when the ZIP's contents actually change.

Personal note: This will help a lot with obtaining ZIP builds to share with others during pre-release testing. When sorting files in a directory by modified date, running npm run build-plugins:zip will always cause the actually modified plugins' ZIP files to appear at the top of the list. They can then be easily attached to a PR as a comment, for example in #2565 (comment).

Relevant technical choices

build-plugins:zip rebuilds each plugin archive from a freshly re-copied build directory, so the zip command embeds new entry timestamps on every run. As a result the resulting archive bytes always differ even when the file contents are byte-for-byte identical, and every build bumped the ZIP's modified time regardless of whether anything actually changed. Comparing the raw archive bytes therefore can't detect "no change."

Instead, createPluginZip() now:

  1. Builds the archive into a temporary file (<plugin>.zip.tmp) rather than directly over the existing ZIP.
  2. Compares the new archive against the existing one via a new getZipContentFingerprint() helper, which runs unzip -v and keeps each entry's uncompressed size + CRC-32 + name, deliberately dropping the date/time columns — a timestamp-independent content fingerprint.
  3. If the fingerprints match, discards the temporary file and leaves the existing ZIP (and its modified time) untouched. Otherwise it renames the temporary file over the existing one.

A side benefit: because each build now starts from a fresh temporary archive rather than updating the existing ZIP in place, files removed from a plugin no longer linger as stale entries (the previous zip -r over an existing archive only added/updated entries, never removed them).

Verified manually:

  • Identical rebuild → modified time preserved, temporary file cleaned up.
  • Source change → modified time updated to the new build.
  • No leftover .tmp files; zip failures still throw (with temp cleanup).

Use of AI Tools

This PR was authored with the assistance of Claude Code (Opus 4.8). The approach, implementation, and commit/PR text were AI-generated based on my direction, and I reviewed and verified the changes (including the manual build tests above).

🤖 Generated with Claude Code

`build-plugins:zip` rebuilds each plugin archive from a freshly re-copied
build directory, so the `zip` command embeds new entry timestamps every run
and the resulting bytes always differ even when the file contents are
identical. This bumped the ZIP's modified time on every build regardless of
whether anything actually changed.

Build the archive into a temporary file and compare it against the existing
ZIP using a timestamp-independent content fingerprint (each entry's
uncompressed size, CRC-32, and name via `unzip -v`). The existing ZIP is only
replaced when its contents actually change; otherwise the temporary file is
discarded and the existing file — including its modified time — is left
untouched.

Building fresh into a temporary file each time also ensures files removed from
a plugin no longer linger in an updated-in-place archive.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: westonruter <westonruter@git.wordpress.org>
Co-authored-by: b1ink0 <b1ink0@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@westonruter westonruter added [Type] Enhancement A suggestion for improvement of an existing feature Infrastructure Issues for the overall performance plugin infrastructure no milestone PRs that do not have a defined milestone for release skip changelog PRs that should not be mentioned in changelogs labels Jul 3, 2026
@westonruter
westonruter requested a review from b1ink0 July 3, 2026 20:10

@b1ink0 b1ink0 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@westonruter
westonruter merged commit 05fa5ad into trunk Jul 7, 2026
23 of 25 checks passed
@westonruter
westonruter deleted the fix/preserve-zip-mtime-when-unchanged branch July 7, 2026 23:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Infrastructure Issues for the overall performance plugin infrastructure no milestone PRs that do not have a defined milestone for release skip changelog PRs that should not be mentioned in changelogs [Type] Enhancement A suggestion for improvement of an existing feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants