WP Plugin Starter 1.0.0: a fresh start

The parts every wpallstars plugin needs: settings screen with search and an empty General tab, Read Me tab, features as classes, replaced plugins, the shared GitHub updater, release and check scripts, CI and the shared rules. scripts/rename-plugin.sh starts a new plugin; scripts/sync-core.sh keeps plugins' core files in step with this starter. Built with aidevops (https://aidevops.sh).
This commit is contained in:
marcus committed 2026-10-03 03:30:42 +01:00
commit 2f91c3e6af
62 files changed
+10929

No files matched your search

+586
View File
@@ -0,0 +1,586 @@
#!/usr/bin/env bash
# Check a version of the plugin before it is released on GitHub or
# submitted to WordPress.org. Changes nothing: it builds both zips into a
# temporary folder (scripts/build-release.sh) and reads them and the Git ref.
#
# Errors stop a release. Warnings need a look and a decision; most matter only
# for WordPress.org. Notes are for information.
#
# Usage: scripts/preflight-release.sh [--ref REF] [--offline] [--strict] [--no-docker]
# --ref REF Commit, branch or tag to check (default: HEAD).
# --offline Skip checks that ask WordPress.org (latest WordPress version,
# slug, contributor profiles).
# --strict Fail on warnings too (use before a WordPress.org submission).
# --no-docker Lint PHP with the local php instead of PHP 7.4 in Docker.
#
# Exit status: 0 when there are no errors (and, with --strict, no warnings).
# Plugin Check runs separately: scripts/plugin-check.sh.
set -euo pipefail
readonly UPDATER_HEADERS='GitHub Plugin URI|Primary Branch|Release Asset'
# Development files that must never be in a release zip (paths inside the slug folder).
readonly DEV_FILES='^[^/]+/(\.git|\.agents|\.wordpress-org|\.distignore|\.distignore-wporg|\.gitattributes|\.gitignore|\.woodpecker\.yml|\.github|\.editorconfig|\.gitleaks\.toml|\.aidevops\.json|composer\.(json|lock)|phpcs\.xml(\.dist)?|phpstan(-baseline|-plugin)?\.neon(\.dist)?|vendor|AGENTS\.md|CONTRIBUTING\.md|DEVELOPMENT\.md|LAUNCH\.md|SECURITY\.md|STANDARDS\.md|RELEASING\.md|ROADMAP\.md|STABILITY\.md|TESTING\.md|scripts|dist|node_modules|reference-plugins|project-documents)(/|$)|(^|/)(\.DS_Store|__MACOSX|Thumbs\.db)(/|$)|\.(bak|log|orig|swp)$'
readonly README_MAX_BYTES=10240
readonly SHORT_DESC_MAX=150
readonly MAX_TAGS=5
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly SCRIPT_DIR
# shellcheck source=scripts/lib/plugin.sh disable=SC1091 # followed only with -x
. "$SCRIPT_DIR/lib/plugin.sh"
# Set from the main file at the ref (plugin_identity).
SLUG=""
MAIN_FILE=""
VERSION_CONSTANT=""
# Paths only in the GitHub build (.distignore-wporg): the GitHub updater.
UPDATER_FILES=""
ERRORS=0
WARNINGS=0
TMP_DIR=""
OFFLINE=0
USE_DOCKER=1
CHANGELOG_TXT=""
die() {
local message="$1"
printf 'preflight: %s\n' "$message" >&2
exit 2
}
usage() {
sed -n '2,18p' "$0" | sed 's/^# \{0,1\}//'
return 0
}
cleanup() {
if [ -n "$TMP_DIR" ] && [ -d "$TMP_DIR" ]; then
rm -rf "$TMP_DIR"
fi
return 0
}
ok() {
local message="$1"
printf ' ok %s\n' "$message"
return 0
}
err() {
local message="$1"
printf ' ERROR %s\n' "$message"
ERRORS=$((ERRORS + 1))
return 0
}
warn() {
local message="$1"
printf ' warn %s\n' "$message"
WARNINGS=$((WARNINGS + 1))
return 0
}
note() {
local message="$1"
printf ' note %s\n' "$message"
return 0
}
section() {
local title="$1"
printf '\n%s\n' "$title"
return 0
}
# Value of "Key: value" in a header (plugin file comment or readme), case-insensitive.
field() {
local text="$1"
local key="$2"
printf '%s\n' "$text" | awk -v k="$key" '
BEGIN { k = tolower(k) }
{
line = $0
sub(/^[ \t*]*/, "", line)
i = index(line, ":")
if (i > 0 && tolower(substr(line, 1, i - 1)) == k) {
v = substr(line, i + 1)
gsub(/^[ \t]+|[ \t\r]+$/, "", v)
print v
exit
}
}'
return 0
}
# 1 if version a < b (numeric parts), else 0.
version_lt() {
local a="$1"
local b="$2"
awk -v a="$a" -v b="$b" 'BEGIN {
na = split(a, x, "."); nb = split(b, y, "."); n = (na > nb) ? na : nb
for (i = 1; i <= n; i++) { if ((x[i] + 0) < (y[i] + 0)) { print 1; exit } if ((x[i] + 0) > (y[i] + 0)) { print 0; exit } }
print 0 }'
return 0
}
# HTTP status of a URL (000 when offline or unreachable).
http_status() {
local url="$1"
local code
# curl prints 000 itself when it cannot connect, and exits non-zero.
code="$(curl -sL -o /dev/null -m 20 -w '%{http_code}' "$url" || true)"
printf '%s' "${code:-000}"
return 0
}
check_versions() {
local plugin_header="$1"
local readme="$2"
local main_php="$3"
section "Versions and headers"
local version constant stable
version="$(field "$plugin_header" "Version")"
constant="$(printf '%s\n' "$main_php" | sed -nE "/define\([[:space:]]*['\"]${VERSION_CONSTANT}['\"]/{s/.*,[[:space:]]*['\"]([^'\"]+)['\"].*/\1/p;q;}")"
stable="$(field "$readme" "Stable tag")"
if printf '%s' "$version" | grep -Eq '^[0-9]+\.[0-9]+(\.[0-9]+)?$'; then
ok "Version: $version (numbers only, so GitHub updates and WordPress.org treat it as stable)"
else
err "Version: '$version' is not X.Y.Z; pre-release versions on main are offered to sites still using Git Updater"
fi
if [ "$constant" = "$version" ]; then ok "version constant matches ($constant)"; else err "version constant is '$constant', Version: is '$version'"; fi
if [ "$stable" = "$version" ]; then ok "readme.txt Stable tag matches"; else err "readme.txt Stable tag is '$stable', Version: is '$version'"; fi
if [ "$(printf '%s' "$stable" | tr '[:upper:]' '[:lower:]')" = "trunk" ]; then err "Stable tag: trunk is not allowed for new plugins"; fi
local key header_value readme_value
for key in "Requires at least" "Requires PHP"; do
header_value="$(field "$plugin_header" "$key")"
readme_value="$(field "$readme" "$key")"
if [ -z "$header_value" ]; then
err "$MAIN_FILE has no '$key' header (WordPress reads it from the plugin file)"
elif [ -n "$readme_value" ] && [ "$header_value" != "$readme_value" ]; then
err "$key: $header_value in $MAIN_FILE, $readme_value in readme.txt"
else
ok "$key: $header_value"
fi
done
if printf '%s\n' "$main_php" | grep -Eiq '^[[:space:]*]*Update URI:'; then
err "Update URI header found: WordPress.org rejects it and Plugin Check reports an updater"
else
ok "no Update URI header"
fi
local domain license plugin_uri author_uri
domain="$(field "$plugin_header" "Text Domain")"
if [ "$domain" = "$SLUG" ]; then ok "Text Domain: $domain"; else err "Text Domain is '$domain'; it must be the slug ($SLUG) for language packs"; fi
license="$(field "$plugin_header" "License")"
if printf '%s' "$license" | grep -Eiq 'GPL'; then ok "License: $license"; else err "License '$license' is not GPL-compatible as written"; fi
plugin_uri="$(field "$plugin_header" "Plugin URI")"
author_uri="$(field "$plugin_header" "Author URI")"
if [ -n "$plugin_uri" ] && [ "$plugin_uri" = "$author_uri" ]; then
warn "Plugin URI and Author URI are the same ($plugin_uri); WordPress.org asks for a Plugin URI unique to the plugin, or none"
fi
VERSION="$version"
return 0
}
# Changelog text (a readme section or changelog.txt): an entry for the version,
# and no Unreleased section left.
check_changelog() {
local label="$1"
local text="$2"
local version="$3"
if printf '%s\n' "$text" | grep -Eq "^= *v?$version *="; then
ok "$label changelog has $version"
else
warn "$label changelog has no '= $version =' entry"
fi
if printf '%s\n' "$text" | grep -Eiq '^= *unreleased *='; then
warn "$label changelog still has an Unreleased section; name it $version when releasing"
fi
return 0
}
check_readme() {
local readme="$1"
local plugin_header="$2"
local version="$3"
section "readme.txt"
local bytes
bytes="$(printf '%s' "$readme" | wc -c | tr -d ' ')"
if [ "$bytes" -le "$README_MAX_BYTES" ]; then
ok "size ${bytes} bytes ($((README_MAX_BYTES - bytes)) left)"
else
warn "size ${bytes} bytes; WordPress.org says over 10 KB may cause errors (keep the current changelog, move older entries to changelog.txt, trim the description)"
fi
local name readme_name
name="$(field "$plugin_header" "Plugin Name")"
readme_name="$(printf '%s\n' "$readme" | sed -n '1s/^===[[:space:]]*\(.*[^[:space:]]\)[[:space:]]*===.*/\1/p')"
if [ "$readme_name" = "$name" ]; then ok "name matches the plugin header ($name)"; else warn "readme name '$readme_name' differs from Plugin Name '$name'"; fi
local short
short="$(printf '%s\n' "$readme" | awk 'NR == 1 { next } !h && /^[ \t]*$/ { h = 1; next } h && /^==/ { exit } h && !/^[ \t]*$/ { print; exit }')"
if [ -z "$short" ]; then
err "no short description (the line after the header)"
elif [ "${#short}" -le "$SHORT_DESC_MAX" ]; then
ok "short description ${#short} characters"
else
warn "short description ${#short} characters; WordPress.org cuts it at $SHORT_DESC_MAX"
fi
local tags tag_count
tags="$(field "$readme" "Tags")"
tag_count="$(printf '%s\n' "$tags" | awk -F',' '{ print ($0 == "") ? 0 : NF }')"
if [ "$tag_count" -ge 1 ] && [ "$tag_count" -le "$MAX_TAGS" ]; then ok "$tag_count tags"; else warn "$tag_count tags; WordPress.org shows at most $MAX_TAGS"; fi
local tested
tested="$(field "$readme" "Tested up to")"
if printf '%s' "$tested" | grep -Eq '^[0-9]+\.[0-9]+$'; then
ok "Tested up to: $tested"
else
err "Tested up to '$tested' should be a major version such as 6.8"
fi
if [ "$OFFLINE" -eq 0 ]; then
local latest latest_major
# The first offer is the latest release; later ones are older branches.
latest="$(curl -s -m 20 'https://api.wordpress.org/core/version-check/1.7/' | grep -o '"current":"[0-9.]*"' | head -n 1 | cut -d'"' -f4 || true)"
latest_major="$(printf '%s' "$latest" | cut -d. -f1-2)"
if [ -z "$latest_major" ]; then
note "could not read the latest WordPress version"
elif [ "$(version_lt "$tested" "$latest_major")" = "1" ]; then
warn "Tested up to $tested, latest WordPress is $latest; test and raise it"
else
ok "Tested up to is the latest WordPress ($latest)"
fi
fi
check_changelog "readme.txt" "$(printf '%s\n' "$readme" | awk '/^== *[Cc]hangelog *==/ { c = 1; next } c && /^== / { exit } c')" "$version"
if [ -n "$CHANGELOG_TXT" ]; then
check_changelog "changelog.txt" "$CHANGELOG_TXT" "$version"
fi
if printf '%s\n' "$readme" | grep -Eiq '^== *upgrade notice *=='; then
if printf '%s\n' "$readme" | awk '/^== *[Uu]pgrade [Nn]otice *==/ { u = 1; next } u && /^== / { exit } u' | grep -Eq "^= *v?$version *="; then
ok "upgrade notice has $version"
else
note "no upgrade notice for $version (optional)"
fi
fi
return 0
}
check_wporg() {
local readme="$1"
local plugin_header="$2"
section "WordPress.org listing"
local name derived
name="$(field "$plugin_header" "Plugin Name")"
derived="$(printf '%s' "$name" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g; s/^-+|-+$//g')"
if [ "$derived" = "$SLUG" ]; then
ok "the slug WordPress.org makes from '$name' is $SLUG"
else
warn "WordPress.org makes the slug from Plugin Name: '$name' becomes '$derived', not '$SLUG'. Ask for '$SLUG' in the submission notes (it can change only before approval), or the text domain will not match"
fi
if printf '%s' "$name" | grep -Eiq '^(wordpress|wp|woocommerce|woo|gutenberg)([^a-z]|$)'; then
warn "Plugin Name starts with a trademark ('$name'); WordPress.org does not allow that"
fi
if [ "$OFFLINE" -eq 1 ]; then
note "offline: slug and contributor profiles not checked"
return 0
fi
local info
info="$(curl -s -m 20 "https://api.wordpress.org/plugins/info/1.2/?action=plugin_information&request%5Bslug%5D=$SLUG&request%5Bfields%5D%5Bsections%5D=0" || true)"
if printf '%s' "$info" | grep -q '"error"'; then
note "slug $SLUG is not listed on WordPress.org yet"
elif [ -n "$info" ]; then
note "slug $SLUG is already listed on WordPress.org; check it is this plugin"
fi
local contributors user status
contributors="$(field "$readme" "Contributors")"
if [ -z "$contributors" ]; then
err "readme.txt has no Contributors"
fi
for user in $(printf '%s' "$contributors" | tr ',' ' '); do
status="$(http_status "https://profiles.wordpress.org/$user/")"
case "$status" in
200) ok "contributor $user has a WordPress.org profile" ;;
000) note "could not check contributor $user" ;;
*) warn "contributor '$user' has no WordPress.org profile (HTTP $status); Contributors must be WordPress.org usernames, case-sensitive" ;;
esac
done
return 0
}
# Lint PHP (PHP 7.4 in Docker when possible) and JS in an unpacked build.
check_syntax() {
local dir="$1"
local label="$2"
local out php_label
local expected
expected="$(find "$dir" -name '*.php' | wc -l | tr -d ' ')"
if [ "$USE_DOCKER" -eq 1 ] && command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1; then
local image="php:7.4-cli"
if docker image inspect wordpress:php7.4-apache >/dev/null 2>&1; then image="wordpress:php7.4-apache"; fi
out="$(docker run --rm -v "$dir:/src:ro" "$image" sh -c 'find /src -name "*.php" -exec php -l {} \;' 2>&1 || true)"
php_label="PHP 7.4 syntax ($image)"
elif command -v php >/dev/null 2>&1; then
out="$(find "$dir" -name '*.php' -exec php -l {} \; 2>&1 || true)"
php_label="PHP syntax ($(php -r 'echo PHP_VERSION;'); not 7.4)"
else
out=""
php_label=""
warn "$label: no PHP to lint with"
fi
if [ -n "$php_label" ]; then
# Count the files php -l passed, so a lint that never ran cannot pass.
local passed problems
passed="$(printf '%s\n' "$out" | grep -c '^No syntax errors' || true)"
problems="$(printf '%s\n' "$out" | grep -v '^No syntax errors' | grep -v '^[[:space:]]*$' || true)"
if [ -z "$problems" ] && [ "$passed" -eq "$expected" ] && [ "$expected" -gt 0 ]; then
ok "$label: $php_label, $passed files"
elif [ -z "$problems" ]; then
err "$label: PHP lint checked $passed of $expected files"
else
err "$label: $php_label errors:"
printf '%s\n' "$problems" | sed 's/^/ /'
fi
fi
if command -v node >/dev/null 2>&1; then
out="$(find "$dir" -name '*.js' -exec node --check {} \; 2>&1 || true)"
if [ -z "$out" ]; then ok "$label: JS syntax"; else err "$label: JS syntax errors:"; printf '%s\n' "$out" | sed 's/^/ /'; fi
else
warn "$label: node not found, JS not checked"
fi
return 0
}
# Shared checks for a release zip; prints its unpacked folder in UNPACKED.
check_zip() {
local zip_path="$1"
local label="$2"
local dir="$TMP_DIR/unpacked-$label"
local list tops dev size
list="$(unzip -Z1 "$zip_path")"
tops="$(printf '%s\n' "$list" | cut -d/ -f1 | sort -u | tr '\n' ' ')"
if [ "$tops" = "$SLUG " ]; then ok "$label: one $SLUG/ folder"; else err "$label: top level is '$tops', must be only $SLUG/"; fi
if printf '%s\n' "$list" | grep -qx "$SLUG/$MAIN_FILE"; then ok "$label: $SLUG/$MAIN_FILE present"; else err "$label: $SLUG/$MAIN_FILE missing"; fi
dev="$(printf '%s\n' "$list" | grep -E "$DEV_FILES" || true)"
if [ -z "$dev" ]; then ok "$label: no development files"; else err "$label: development files: $(printf '%s' "$dev" | tr '\n' ' ')"; fi
size="$(wc -c <"$zip_path" | tr -d ' ')"
note "$label: $(basename "$zip_path"), $((size / 1024)) KB, $(printf '%s\n' "$list" | grep -cv '/$') files"
mkdir -p "$dir"
unzip -q "$zip_path" -d "$dir"
check_syntax "$dir" "$label"
UNPACKED="$dir/$SLUG"
return 0
}
check_builds() {
local github_zip="$1"
local wporg_zip="$2"
local version="$3"
section "Release zips"
if [ "$(basename "$github_zip")" = "$SLUG-$version.zip" ]; then
ok "GitHub asset name $SLUG-$version.zip (sites pick assets starting with $SLUG)"
else
err "GitHub asset is $(basename "$github_zip"), expected $SLUG-$version.zip"
fi
case "$(basename "$wporg_zip")" in
"$SLUG"*) err "WordPress.org zip name starts with $SLUG; sites could install it from GitHub" ;;
*) ok "WordPress.org zip name does not start with $SLUG" ;;
esac
UNPACKED=""
check_zip "$github_zip" "github"
local github_dir="$UNPACKED" path
if [ -z "$UPDATER_FILES" ]; then
note "no .distignore-wporg: both builds hold the same files"
fi
for path in $UPDATER_FILES; do
if [ -e "$github_dir/$path" ]; then ok "github: has $path"; else err "github: $path missing (listed in .distignore-wporg)"; fi
done
if grep -Eq "^[[:space:]*]*GitHub Plugin URI:" "$github_dir/$MAIN_FILE"; then ok "github: has the GitHub Plugin URI header"; else err "github: no GitHub Plugin URI header, sites cannot update it from GitHub"; fi
check_zip "$wporg_zip" "wporg"
local wporg_dir="$UNPACKED"
for path in $UPDATER_FILES; do
if [ -e "$wporg_dir/$path" ]; then err "wporg: $path must not be in the WordPress.org build"; else ok "wporg: no $path"; fi
done
if grep -Eq "^[[:space:]*]*($UPDATER_HEADERS):" "$wporg_dir/$MAIN_FILE"; then err "wporg: GitHub updater header lines still in $MAIN_FILE"; else ok "wporg: no GitHub updater header lines"; fi
local hits
hits="$(grep -rEl --include='*.php' --include='*.js' 'gu_override_dot_org|api\.github\.com/repos|Plugin_Upgrader|Theme_Upgrader|site_transient_update_plugins|auto_update_(plugin|theme)' "$wporg_dir" 2>/dev/null | sed "s|^$wporg_dir/||" || true)"
if [ -z "$hits" ]; then
ok "wporg: no code that installs or updates plugins from elsewhere"
else
warn "wporg: check these install or update code (guideline 8 allows only WordPress.org sources): $(printf '%s' "$hits" | tr '\n' ' ')"
fi
section "Remote assets and services (WordPress.org build)"
hits="$(grep -rEn "(wp_(enqueue|register)_(script|style)|<script|<link)[^;]*['\"](https?:)?//" "$wporg_dir" --include='*.php' 2>/dev/null | sed "s|^$wporg_dir/||" | cut -c1-160 || true)"
if [ -z "$hits" ]; then ok "no scripts or styles loaded from other sites"; else warn "scripts or styles from other sites (guideline 8: ship them in the plugin unless they are part of a service):"; printf '%s\n' "$hits" | sed 's/^/ /'; fi
local readme_text hosts host missing=""
readme_text="$(cat "$wporg_dir/readme.txt")"
hosts="$(grep -rEoh 'https?://[A-Za-z0-9.-]+\.[a-z]{2,}' "$wporg_dir/includes" "$wporg_dir/blocks" 2>/dev/null | sed -E 's|https?://||; s|^www\.||' | sort -u || true)"
for host in $hosts; do
case "$host" in
w3.org | gnu.org | wordpress.org | *.wordpress.org | w.org | *.w.org | wp.org | *.wp.org | example.com | *.example.com) continue ;;
esac
if ! printf '%s' "$readme_text" | grep -Fqi "$host"; then missing="$missing $host"; fi
done
if [ -z "$missing" ]; then
ok "every host in includes/ and blocks/ is named in readme.txt"
else
note "hosts in code not named in readme.txt (fine if they are only links; services the plugin contacts need an External services entry):$missing"
fi
# Checks for parts only some plugins have; each runs when its files exist.
# A plugin's own checks: scripts/preflight-plugin.sh defines plugin_preflight,
# which gets the unpacked GitHub build and can use section, ok, warn and err.
if [ -f "$SCRIPT_DIR/preflight-plugin.sh" ]; then
# shellcheck source=/dev/null
. "$SCRIPT_DIR/preflight-plugin.sh"
plugin_preflight "$github_dir"
fi
if [ -f "$SCRIPT_DIR/replaced-plugins.php" ]; then
check_replaced_count "$github_dir"
fi
return 0
}
# README.md's "<Plugin Name> replaces **N plugins**" line matches the
# 'replaces' entries in the code (scripts/replaced-plugins.php).
check_replaced_count() {
local dir="$1"
section "Replaced plugins"
if ! command -v php >/dev/null 2>&1; then
warn "php not found, the replaced plugins count in README.md was not checked"
return 0
fi
local out
if out="$(php "$SCRIPT_DIR/replaced-plugins.php" --check "$dir" 2>&1)"; then
ok "$out"
else
err "$out"
fi
return 0
}
# Core files match the starter's (scripts/sync-core.sh --check), when a
# checkout of the starter is at hand. A warning, not an error: the starter's
# checkout may be behind, and only a person can tell which side is right.
check_core_files() {
section "Core files"
local out status=0
out="$(bash "$SCRIPT_DIR/sync-core.sh" --check 2>&1)" || status=$?
case "$status" in
0) ok "$(printf '%s\n' "$out" | tail -n 1)" ;;
1) warn "$(printf '%s\n' "$out" | sed -n '2,$p' | tr '\n' ' ')" ;;
*) note "not compared: ${out#sync-core: }" ;;
esac
return 0
}
check_git() {
local ref="$1"
local sha="$2"
local version="$3"
section "Git"
local tag_sha
if tag_sha="$(git rev-parse --verify --quiet "refs/tags/v$version^{commit}")"; then
if [ "$tag_sha" = "$sha" ]; then ok "tag v$version is this commit"; else warn "tag v$version exists on another commit (${tag_sha:0:12}); bump the version"; fi
else
note "no tag v$version yet"
fi
local main_sha
if main_sha="$(git rev-parse --verify --quiet "refs/remotes/origin/main^{commit}")"; then
if git merge-base --is-ancestor "$sha" "$main_sha"; then ok "$ref is on origin/main"; else note "$ref is not on origin/main yet; release only from main"; fi
fi
if [ "$ref" = "HEAD" ] && [ -n "$(git status --porcelain --untracked-files=no)" ]; then
note "uncommitted changes are not checked (the build comes from HEAD)"
fi
return 0
}
main() {
local ref="HEAD"
local strict=0
local arg
while [ $# -gt 0 ]; do
arg="$1"
case "$arg" in
--ref)
[ $# -ge 2 ] || die "--ref needs a value"
ref="$2"
shift
;;
--offline) OFFLINE=1 ;;
--strict) strict=1 ;;
--no-docker) USE_DOCKER=0 ;;
-h | --help)
usage
return 0
;;
*) die "unknown argument: $arg" ;;
esac
shift
done
local root sha
root="$(git rev-parse --show-toplevel)" || die "run this inside a checkout of the plugin"
cd "$root"
sha="$(git rev-parse --verify --quiet "$ref^{commit}")" || die "not a commit: $ref"
plugin_identity "$sha" || die "cannot tell which plugin this is at $ref"
SLUG="$PLUGIN_SLUG"
MAIN_FILE="$PLUGIN_MAIN_FILE"
VERSION_CONSTANT="${PLUGIN_CONST}_VERSION"
UPDATER_FILES="$(plugin_wporg_only "$sha")"
trap cleanup EXIT
TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/$SLUG-preflight.XXXXXX")"
local main_php readme plugin_header
main_php="$(git show "$sha:$MAIN_FILE")"
readme="$(git show "$sha:readme.txt")" || die "readme.txt missing at $ref"
if git cat-file -e "$sha:changelog.txt" 2>/dev/null; then
CHANGELOG_TXT="$(git show "$sha:changelog.txt")"
fi
plugin_header="$(printf '%s\n' "$main_php" | sed -n '1,/\*\//p')"
printf '%s preflight: %s (%s)\n' "$PLUGIN_NAME" "$ref" "${sha:0:12}"
VERSION=""
check_versions "$plugin_header" "$readme" "$main_php"
check_readme "$readme" "$plugin_header" "$VERSION"
check_wporg "$readme" "$plugin_header"
local zips github_zip wporg_zip
zips="$("$root/scripts/build-release.sh" --ref "$sha" --out "$TMP_DIR/dist" --quiet)" || die "build failed"
github_zip="$(printf '%s\n' "$zips" | sed -n 1p)"
wporg_zip="$(printf '%s\n' "$zips" | sed -n 2p)"
check_builds "$github_zip" "$wporg_zip" "$VERSION"
if [ -f "$SCRIPT_DIR/sync-core.sh" ]; then
check_core_files
fi
check_git "$ref" "$sha" "$VERSION"
printf '\n%s error(s), %s warning(s).\n' "$ERRORS" "$WARNINGS"
if [ "$ERRORS" -gt 0 ]; then
printf 'Not ready: fix the errors.\n'
return 1
fi
if [ "$strict" -eq 1 ] && [ "$WARNINGS" -gt 0 ]; then
printf 'Not ready (--strict): resolve or accept the warnings.\n'
return 1
fi
printf 'Next: scripts/plugin-check.sh (Plugin Check on both zips).\n'
return 0
}
main "$@"