2026-09-16 10:34:38 +02:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
# Build the installable plugin zip and check it is actually installable.
|
|
|
|
|
#
|
|
|
|
|
# Writes build/<slug>.zip, containing a single top-level <slug>/ directory —
|
|
|
|
|
# WordPress identifies an installed plugin by that folder name, so a zip that
|
|
|
|
|
# unpacks to anything else installs a second copy alongside the first instead
|
|
|
|
|
# of updating it.
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
|
|
cd "$(dirname "$0")/.."
|
|
|
|
|
. ci/lib.sh
|
|
|
|
|
ci_load_conf
|
|
|
|
|
|
|
|
|
|
version=$(ci_plugin_version)
|
|
|
|
|
[ -n "$version" ] || { echo "Could not read Version: from $PLUGIN_MAIN." >&2; exit 1; }
|
|
|
|
|
|
|
|
|
|
rm -rf build
|
|
|
|
|
mkdir -p "build/$PLUGIN_SLUG"
|
|
|
|
|
|
|
|
|
|
# One list, shared with the hygiene checks and the test site, so a file cannot
|
|
|
|
|
# be excluded from the tests and included in the release.
|
|
|
|
|
./ci/dist-files.sh | while IFS= read -r f; do
|
|
|
|
|
mkdir -p "build/$PLUGIN_SLUG/$(dirname "$f")"
|
|
|
|
|
cp "$f" "build/$PLUGIN_SLUG/$f"
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
# `zip` is on GitHub's runners but not in every Gitea runner image, and a
|
|
|
|
|
# release that fails on the packaging step is the most annoying possible place
|
|
|
|
|
# to discover a missing tool. python3 is present in both.
|
|
|
|
|
(
|
|
|
|
|
cd build
|
|
|
|
|
if command -v zip >/dev/null 2>&1; then
|
|
|
|
|
zip -rq "$PLUGIN_SLUG.zip" "$PLUGIN_SLUG"
|
|
|
|
|
elif command -v python3 >/dev/null 2>&1; then
|
|
|
|
|
python3 -m zipfile -c "$PLUGIN_SLUG.zip" "$PLUGIN_SLUG"
|
|
|
|
|
else
|
|
|
|
|
echo "Neither zip nor python3 is available to build the archive." >&2
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Listing entries by name rather than parsing `unzip -l` output, with the same
|
|
|
|
|
# python3 fallback as above because unzip is not guaranteed on a runner either.
|
|
|
|
|
zip_entries() {
|
|
|
|
|
if command -v unzip >/dev/null 2>&1; then
|
|
|
|
|
unzip -Z1 "build/$PLUGIN_SLUG.zip"
|
|
|
|
|
else
|
|
|
|
|
python3 -c 'import sys,zipfile;print("\n".join(zipfile.ZipFile(sys.argv[1]).namelist()))' \
|
|
|
|
|
"build/$PLUGIN_SLUG.zip"
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ci_step "what the zip contains"
|
|
|
|
|
zip_entries | sed 's/^/ /'
|
|
|
|
|
|
2026-09-20 10:20:17 +02:00
|
|
|
# 🔴 A failed build must not leave a zip behind. Every exit below this point
|
|
|
|
|
# happens AFTER the archive is written, so without this the tree keeps a
|
|
|
|
|
# half-built artefact that looks exactly like a good one — and the release step
|
|
|
|
|
# takes `build/<slug>.zip` by name, as does anyone publishing by hand. The
|
|
|
|
|
# check that caught it: stubbing ci/dist-files.sh empty makes this script exit
|
|
|
|
|
# 1 with "The main plugin file is not in the zip", and the zip was still there
|
|
|
|
|
# afterwards.
|
|
|
|
|
trap 'code=$?; [ "$code" = 0 ] || { rm -f "build/$PLUGIN_SLUG.zip"; echo "Removed the incomplete build/$PLUGIN_SLUG.zip." >&2; }; exit $code' EXIT
|
|
|
|
|
|
2026-09-16 10:34:38 +02:00
|
|
|
ci_step "checks"
|
|
|
|
|
zip_entries | grep -qx "$PLUGIN_SLUG/$PLUGIN_MAIN" \
|
|
|
|
|
|| { echo "The main plugin file is not in the zip." >&2; exit 1; }
|
|
|
|
|
echo " the main file is present"
|
|
|
|
|
|
|
|
|
|
# A leaked ci/ or tests/ directory is not merely untidy: everything under
|
|
|
|
|
# wp-content/plugins/ can in principle be fetched over HTTP from a live shop.
|
|
|
|
|
for unwanted in ci tests docs .git .github .gitea; do
|
|
|
|
|
if zip_entries | grep -q "^$PLUGIN_SLUG/$unwanted/"; then
|
|
|
|
|
echo "The zip contains $unwanted/, which must never reach a shop." >&2
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
echo " no tooling, tests or git files leaked in"
|
|
|
|
|
|
|
|
|
|
# Every entry sits under exactly one top-level directory named for the slug.
|
|
|
|
|
strays=$(zip_entries | grep -v "^$PLUGIN_SLUG/" || true)
|
|
|
|
|
[ -z "$strays" ] || { echo "Files outside $PLUGIN_SLUG/ in the zip:" >&2; echo "$strays" >&2; exit 1; }
|
|
|
|
|
echo " everything unpacks into $PLUGIN_SLUG/"
|
|
|
|
|
|
|
|
|
|
size=$(du -h "build/$PLUGIN_SLUG.zip" | cut -f1)
|
|
|
|
|
echo
|
|
|
|
|
echo "build/$PLUGIN_SLUG.zip — version $version, $size"
|