From d2a2cd602e545b54edbb46c77fef2f876e021c3c Mon Sep 17 00:00:00 2001 From: POBrien333 <954979+POBrien333@users.noreply.github.com> Date: Thu, 10 Sep 2026 15:51:25 +0200 Subject: [PATCH] Keep the staging directory out of the release zip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The v0.1.2 zip shipped an empty build/student-activity-masterstudy/ inside it. The workflow created ./build inside the checkout and then ran `rsync -a ./ build/$SLUG/`, so rsync copied ./ while build/ already existed within it — sweeping the staging directory into its own output. Harmless (empty directories, WordPress installs the plugin fine) but wrong, and the sort of thing a plugin reviewer would query. Staging now happens in $RUNNER_TEMP, outside the checkout, which removes the possibility rather than excluding it after the fact. A guard step fails the build if build/, stage/, tests/ or .git/ ever appear in the staged tree, so a future regression breaks the release instead of shipping quietly. Also adds *.zip and /build to .distignore. CI never sees either, because actions/checkout only fetches tracked files and .gitignore already covers them — but a local `wp dist-archive` run would otherwise fold the previous zip into the new one. Verified by simulating both staging strategies against the working tree: the old one reproduces the nested build/ directories, the new one produces only assets/ and includes/. Co-Authored-By: Claude Opus 5 --- .distignore | 5 +++++ .github/workflows/release.yml | 21 ++++++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/.distignore b/.distignore index 9fe2938..6d90744 100644 --- a/.distignore +++ b/.distignore @@ -11,6 +11,11 @@ /.gitignore /.gitattributes /.distignore +# Local build artefacts — CI never sees these (checkout is tracked files +# only), but a local `wp dist-archive` would otherwise sweep them in. +*.zip +/build + /tests /README.md /CHANGELOG.md diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 88e3522..d68c4bb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -40,20 +40,31 @@ jobs: - name: Assemble the plugin folder run: | - mkdir -p build/"$SLUG" + # Staged OUTSIDE the checkout on purpose. Building into ./build meant + # rsync copied ./ while build/ already existed inside it, sweeping the + # staging directory into the zip (shipped empty in 0.1.2). + mkdir -p "$RUNNER_TEMP/stage/$SLUG" # rsync honours .distignore directly: it skips blank lines and # # comments, and a leading / anchors to the transfer root, exactly as # `wp dist-archive` reads it. One source of truth for what ships. - rsync -a --exclude-from=.distignore ./ build/"$SLUG"/ + rsync -a --exclude-from=.distignore ./ "$RUNNER_TEMP/stage/$SLUG/" - name: Show what is being shipped - run: find build -type f | sort + run: find "$RUNNER_TEMP/stage" | sort + + - name: Fail if anything unwanted crept in + run: | + cd "$RUNNER_TEMP/stage" + if find . -type d \( -name build -o -name stage -o -name tests -o -name .git \) | grep -q .; then + echo "::error::Staging directory contains a folder that should not ship." + exit 1 + fi - name: Create the zip run: | VERSION="${GITHUB_REF_NAME#v}" - cd build - zip -r "../$SLUG-$VERSION.zip" "$SLUG" + cd "$RUNNER_TEMP/stage" + zip -r "$GITHUB_WORKSPACE/$SLUG-$VERSION.zip" "$SLUG" - name: Attach it to the release if: startsWith(github.ref, 'refs/tags/v')