111 lines
4.2 KiB
Bash
111 lines
4.2 KiB
Bash
|
|
#!/usr/bin/env bash
|
||
|
|
#
|
||
|
|
# Build an installable WordPress plugin ZIP for Reservair.
|
||
|
|
#
|
||
|
|
# Produces dist/reservair-<version>.zip containing a single top-level
|
||
|
|
# `reservair/` directory with ONLY the runtime files: the compiled Gutenberg
|
||
|
|
# block assets and production-only Composer dependencies.
|
||
|
|
#
|
||
|
|
# The build runs in an isolated temp directory, so it never touches your
|
||
|
|
# working-tree vendor/ or node_modules/ — safe to run locally or in CI.
|
||
|
|
#
|
||
|
|
# Usage:
|
||
|
|
# ./bin/build-zip.sh
|
||
|
|
#
|
||
|
|
# Environment overrides:
|
||
|
|
# OUTPUT_DIR directory the final zip is written to (default: <repo>/dist)
|
||
|
|
# SKIP_JS "1" to reuse the existing build/ dir (default: build fresh)
|
||
|
|
# KEEP_TMP "1" to keep the temp build dir for debug (default: removed)
|
||
|
|
#
|
||
|
|
set -euo pipefail
|
||
|
|
|
||
|
|
# --- locate repo root (this script lives in <root>/bin) ----------------------
|
||
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
|
|
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||
|
|
cd "$ROOT_DIR"
|
||
|
|
|
||
|
|
SLUG="reservair"
|
||
|
|
OUTPUT_DIR="${OUTPUT_DIR:-$ROOT_DIR/dist}"
|
||
|
|
|
||
|
|
log() { printf '\033[1;34m==>\033[0m %s\n' "$*"; }
|
||
|
|
die() { printf '\033[1;31mERROR:\033[0m %s\n' "$*" >&2; exit 1; }
|
||
|
|
|
||
|
|
# --- prerequisites -----------------------------------------------------------
|
||
|
|
need() { command -v "$1" >/dev/null 2>&1 || die "'$1' is required but not installed"; }
|
||
|
|
need composer
|
||
|
|
need zip
|
||
|
|
need rsync
|
||
|
|
[ "${SKIP_JS:-0}" = "1" ] || need npm
|
||
|
|
|
||
|
|
# --- read version from the plugin header (single source of truth) ------------
|
||
|
|
# `read` consumes only the first match and avoids a `| head` pipe (which would
|
||
|
|
# SIGPIPE the upstream sed under `pipefail` and abort the script with code 141).
|
||
|
|
VERSION=""
|
||
|
|
read -r VERSION < <(sed -n 's/^[[:space:]]*\*\{0,1\}[[:space:]]*Version:[[:space:]]*\([^[:space:]]*\).*/\1/p' "$ROOT_DIR/$SLUG.php") || true
|
||
|
|
[ -n "$VERSION" ] || die "could not read 'Version:' header from $SLUG.php"
|
||
|
|
log "Packaging $SLUG version $VERSION"
|
||
|
|
|
||
|
|
# --- isolated build dir (never touches your working vendor/ or node_modules) -
|
||
|
|
TMP_DIR="$(mktemp -d)"
|
||
|
|
BUILD_DIR="$TMP_DIR/src"
|
||
|
|
STAGE_DIR="$TMP_DIR/stage/$SLUG"
|
||
|
|
cleanup() { [ "${KEEP_TMP:-0}" = "1" ] || rm -rf "$TMP_DIR"; }
|
||
|
|
trap cleanup EXIT
|
||
|
|
mkdir -p "$BUILD_DIR" "$STAGE_DIR"
|
||
|
|
|
||
|
|
# --- copy the source tree into the isolated build dir ------------------------
|
||
|
|
log "Copying source into isolated build dir"
|
||
|
|
rsync -a \
|
||
|
|
--exclude='.git/' \
|
||
|
|
--exclude='node_modules/' \
|
||
|
|
--exclude='vendor/' \
|
||
|
|
--exclude='build/' \
|
||
|
|
--exclude='dist/' \
|
||
|
|
--exclude='.wp-env.json' \
|
||
|
|
./ "$BUILD_DIR/"
|
||
|
|
|
||
|
|
# --- compile the Gutenberg block (src/ -> build/) ----------------------------
|
||
|
|
if [ "${SKIP_JS:-0}" = "1" ]; then
|
||
|
|
[ -d "$ROOT_DIR/build" ] || die "SKIP_JS=1 but no build/ exists — run 'npm run build' first"
|
||
|
|
log "SKIP_JS=1 — reusing existing build/"
|
||
|
|
cp -R "$ROOT_DIR/build" "$BUILD_DIR/build"
|
||
|
|
else
|
||
|
|
log "Installing JS deps and building block assets"
|
||
|
|
( cd "$BUILD_DIR" && npm ci && npm run build )
|
||
|
|
fi
|
||
|
|
|
||
|
|
# --- install production-only PHP deps + regenerate autoloader ----------------
|
||
|
|
# This strips psalm/phpstan/wordpress-core etc. and rebuilds the classmap that
|
||
|
|
# loads the plugin's own includes/ classes — vendor/ is required at runtime.
|
||
|
|
log "Installing production Composer dependencies"
|
||
|
|
( cd "$BUILD_DIR" && composer install \
|
||
|
|
--no-dev --optimize-autoloader --classmap-authoritative \
|
||
|
|
--no-interaction --no-progress )
|
||
|
|
|
||
|
|
# --- stage only the runtime files -------------------------------------------
|
||
|
|
log "Staging runtime files"
|
||
|
|
RUNTIME=( "$SLUG.php" admin.php uninstall.php readme.txt includes modules build assets vendor )
|
||
|
|
for item in "${RUNTIME[@]}"; do
|
||
|
|
if [ -e "$BUILD_DIR/$item" ]; then
|
||
|
|
cp -R "$BUILD_DIR/$item" "$STAGE_DIR/"
|
||
|
|
else
|
||
|
|
log " (skipping missing $item)"
|
||
|
|
fi
|
||
|
|
done
|
||
|
|
|
||
|
|
# --- fail loudly if anything essential is missing ----------------------------
|
||
|
|
for required in "$SLUG.php" vendor/autoload.php build/block.json; do
|
||
|
|
[ -e "$STAGE_DIR/$required" ] || die "packaging incomplete: missing $required"
|
||
|
|
done
|
||
|
|
|
||
|
|
# --- zip it ------------------------------------------------------------------
|
||
|
|
mkdir -p "$OUTPUT_DIR"
|
||
|
|
ZIP_PATH="$OUTPUT_DIR/${SLUG}-${VERSION}.zip"
|
||
|
|
rm -f "$ZIP_PATH"
|
||
|
|
log "Creating $ZIP_PATH"
|
||
|
|
( cd "$TMP_DIR/stage" && zip -rq "$ZIP_PATH" "$SLUG" -x '*.DS_Store' )
|
||
|
|
|
||
|
|
log "Done → $ZIP_PATH"
|
||
|
|
# `|| true` keeps an early-closing `head` (SIGPIPE) from failing the script.
|
||
|
|
unzip -l "$ZIP_PATH" | tail -n +2 | head -n 12 || true
|