Skip to content

Make .distignore the single source of truth for the release ZIP - #86

Merged
erseco merged 3 commits into
mainfrom
chore/distignore-single-source-of-truth
Aug 3, 2026
Merged

Make .distignore the single source of truth for the release ZIP#86
erseco merged 3 commits into
mainfrom
chore/distignore-single-source-of-truth

Conversation

@erseco

@erseco erseco commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Why

.distignore and .gitattributes listed roughly the same paths — 41 rules in common, and two duplicated verbatim inside .gitattributes (README.md, phpunit.xml.dist) — even though they have different jobs:

  • .distignore is the only list wp dist-archive reads (vendor/wp-cli/dist-archive-command/src/Dist_Archive_Command.php:77-84), so it alone decides what ships.
  • .gitattributes export-ignore only shapes the source ZIP GitHub serves at archive/refs/heads/*.zip — the URL blueprint.json installs in Playground.

Maintaining them as mirrors is wrong in both directions and hid two bugs.

Bugs fixed

1. Unanchored rules were eating the bundled editor. wp dist-archive delegates matching to inmarelibero/gitignore-checker, which compiles every rule with the regex i flag and matches at any depth. So the bare build, README.md, CHANGELOG.md and package.json rules reached inside dist/static/ and silently stripped 16 files from the packaged editor. The LICENSE.txt rule already carried a comment about this exact trap; now every root-only rule is anchored.

2. test-results/ was shipping — Playwright output, gitignored, but dist-archive reads the working tree.

Verification

Built the ZIP before and after and diffed the file lists (3910 → 3926 entries):

> exelearning/LICENSE.txt
> exelearning/dist/static/libs/yjs/build/            (7 files)
> exelearning/dist/static/CHANGELOG.md
> exelearning/dist/static/libs/README.md
> exelearning/dist/static/libs/tinymce_5/CHANGELOG.md
> exelearning/dist/static/libs/tinymce_5/js/tinymce/langs/README.md
> exelearning/dist/static/app/common/mindmaps/README.md
> exelearning/dist/static/app/common/edicuatex/README.md
> exelearning/dist/static/app/common/fix_webm_duration/README.md
> exelearning/dist/static/app/common/fix_webm_duration/package.json
> exelearning/dist/static/files/perm/idevices/base/lomloe/README.md
< exelearning/test-results/
< exelearning/test-results/.last-run.json

Nothing else changed. make package itself is untouched.

Also in this PR

  • .distignore loses ~35 rules inherited from WordPress/plugin-check that match nothing here (plugin-check.iml, behat.yml, .gherkin-lintrc, phpstan.neon, /phpcs-sniffs/…), and keeps a deliberate block of rules that must match at any depth (.git, node_modules, .DS_Store, .idea, sftp-config.json).
  • LICENSE.txt now ships; it did not before.
  • .gitattributes goes from 45 rules to 6. Rules for untracked paths (node_modules/, vendor/, dist/, artifacts/) were noise — git archive never sees them.
  • Both files now state their scope in a header comment, so nobody re-syncs them by hand.

Context

wp-decker, wp-documentate and wp-autofirma carry the same two drifting files, and two of them ship a ZIP with no top-level directory (WordPress then installs them as decker-1.2.3/). ADR-0003 records the decision and SDD-0002 the cross-repository design; this is the first of four PRs and the only one that does not change the packaging command.

Follow-up (not here)

ci.yml:127-128 uses git checkout-index instead of git archive only because the blanket .* rule hid .phpcs.xml.dist. That rule is gone, so the workaround can be revisited — left out to keep this PR to packaging.


Añadido tras revisar la CI

check-editor-releases.yml no instalaba PHP ni Composer y sin embargo llama a make package, que necesita el comando i18n de WP-CLI para las traducciones de runtime y dist-archive para el ZIP, ambos en require-dev. El paso Create package fallaba en cuanto salía una versión nueva del editor. Es un fallo preexistente, no lo introduce esta PR; los pasos son los mismos que ya usa release.yml.

Comentario obsoleto en el guard de PHPCS. Decía que se usaba checkout-index porque .gitattributes excluía los dotfiles, incluido .phpcs.xml.dist — dejó de ser cierto al desaparecer la regla .*. checkout-index sigue siendo lo correcto, pero por una razón mejor: escribe el índice tal cual, sin filtrar por export-ignore, así que el guard no depende de lo que .gitattributes excluya en cada momento.

rm -f antes de archivar, porque --force no vacía el ZIP anterior (ver el commit correspondiente).

.distignore and .gitattributes listed roughly the same paths (41 rules in
common, two duplicated verbatim in .gitattributes) even though only the first
one feeds the release ZIP: `wp dist-archive` reads .distignore and nothing else,
while `export-ignore` shapes the source ZIP GitHub serves at
archive/refs/heads/*.zip, the URL blueprint.json installs in Playground.

Keeping them as mirrors hid two bugs, both found by diffing the built ZIP:

- Unanchored rules match at any depth and case-insensitively, so `build`,
  `README.md`, `CHANGELOG.md` and `package.json` were stripping 16 files out of
  the bundled editor, among them dist/static/libs/yjs/build/ and
  dist/static/CHANGELOG.md. Root-only rules now carry a leading slash, the same
  fix the LICENSE.txt rule already documented.
- test-results/ (Playwright output, gitignored) was shipping.

.distignore also loses ~35 rules inherited from WordPress/plugin-check that
match nothing here (plugin-check.iml, behat.yml, .gherkin-lintrc, phpstan.neon,
/phpcs-sniffs/ and friends), keeping a deliberate block for the ones that must
match at any depth. LICENSE.txt now ships.

.gitattributes drops from 45 rules to 6 and states in its header that it does
not feed the release: rules for untracked paths (node_modules/, vendor/, dist/,
artifacts/) were noise, because git archive never sees them.

Net effect on the package: +16 files inside dist/static/, +LICENSE.txt,
-test-results/.

ADR-0003 records the decision and SDD-0002 the cross-repository design, since
wp-decker, wp-documentate and wp-autofirma carry the same two drifting files.
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Test in WordPress Playground

Test the plugin with the code from this branch:

Preview in WordPress Playground

ℹ️ The eXeLearning editor is fetched from the shared release and unpacked into the plugin when the playground boots, so the first load may take a few extra seconds. ELP upload, shortcode, Gutenberg block and preview work normally.

@codecov-commenter

codecov-commenter commented Aug 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 73.47%. Comparing base (2d9fcb7) to head (87b13bd).

Additional details and impacted files
@@            Coverage Diff            @@
##               main      #86   +/-   ##
=========================================
  Coverage     73.47%   73.47%           
  Complexity      848      848           
=========================================
  Files            42       42           
  Lines          4339     4339           
=========================================
  Hits           3188     3188           
  Misses         1151     1151           
Flag Coverage Δ
javascript 37.81% <ø> (ø)
php 85.39% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

erseco added 2 commits August 3, 2026 16:23
`wp dist-archive --force` does not truncate an existing archive. Version 3.1
shells out to the `zip` binary, which ADDS to one, so `--force` only bypasses
the "file already exists" check.

Proved with a controlled run: built with a rule excluding includes/, removed the
rule and rebuilt over the same file (the 31 files appeared, as expected), then
put the rule back and rebuilt over it again — the 31 files were still inside.

A repeated `make package` at the same VERSION therefore keeps files that a new
.distignore rule already excludes. CI starts from a clean checkout so releases
were never affected, but it silently undermines any local verification of a
packaging change.
check-editor-releases.yml calls `make package` but set up neither PHP nor
Composer. That target needs the WP-CLI i18n command to build the runtime
translations and the dist-archive command to build the ZIP, both of them in
require-dev, so the Create package step failed outright whenever a new editor
release appeared. Pre-existing; the steps mirror release.yml.

Also corrects a stale comment on the PHPCS regression guard. It said
checkout-index was used because .gitattributes export-ignored dotfiles including
.phpcs.xml.dist, which stopped being true when the blanket `.*` rule went away.
checkout-index is still the right tool, for a better reason: it writes the index
verbatim with no export-ignore filtering, so the guard does not depend on
whatever .gitattributes happens to exclude.
@erseco
erseco merged commit a1b875f into main Aug 3, 2026
4 checks passed
@erseco
erseco deleted the chore/distignore-single-source-of-truth branch August 3, 2026 15:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants