#!/usr/bin/env bash set -euo pipefail die() { printf 'Error: %s\n' "$*" >&2 exit 1 } require_command() { command -v "$1" >/dev/null 2>&1 || die "Required command not found: $1" } is_excluded_path() { case "$1" in .gitignore|config.php|data|data/*|update-server|update-server/*|.codex|.codex/*|build|build/*|scripts|scripts/*) return 0 ;; esac return 1 } read_current_version() { sed -nE 's/.*define\(["'\'']APP_VERSION["'\''],[[:space:]]*["'\'']([^"'\'']+)["'\'']\).*/\1/p' "$version_file" | head -n 1 } write_current_version() { local version="$1" NEW_APP_VERSION="$version" perl -0pi -e ' BEGIN { $version = $ENV{"NEW_APP_VERSION"}; $updated = 0; } $updated += s/define\(["'\'']APP_VERSION["'\''],\s*["'\''][^"'\'']+["'\'']\);/define("APP_VERSION", "$version");/g; END { exit($updated > 0 ? 0 : 2); } ' "$version_file" || die "Version string could not be updated in $version_file" } sha256_file() { local file="$1" if command -v shasum >/dev/null 2>&1; then shasum -a 256 "$file" | awk '{print $1}' elif command -v sha256sum >/dev/null 2>&1; then sha256sum "$file" | awk '{print $1}' else die "Required command not found: shasum or sha256sum" fi } file_size() { local file="$1" if stat -f '%z' "$file" >/dev/null 2>&1; then stat -f '%z' "$file" else stat -c '%s' "$file" fi } require_command git require_command zip require_command sed require_command awk require_command perl repo_root="$(git rev-parse --show-toplevel 2>/dev/null)" || die "Not inside a git repository." current_dir="$(pwd -P)" repo_root_real="$(cd "$repo_root" && pwd -P)" [[ "$current_dir" == "$repo_root_real" ]] || die "Run this script from the repository root: $repo_root_real" [[ "$#" -le 1 ]] || die "Usage: $0 [vX.Y.Z]" version_file='includes/version.php' [[ -f "$version_file" ]] || die "Version file not found: $version_file" current_version="$(read_current_version)" [[ -n "$current_version" ]] || die "Current version could not be read from $version_file" if [[ "$#" -eq 1 ]]; then version="$1" else printf 'Current version: %s\n' "$current_version" printf 'New version (vX.Y.Z): ' IFS= read -r version || die "No version provided." fi [[ -n "$version" ]] || die "No version provided." [[ "$version" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || die "Version must use the format vX.Y.Z." write_current_version "$version" output_dir='build/updates' output_file="${output_dir}/psa-orderform-${version}.zip" tmp_file_list="$(mktemp)" cleanup() { rm -f "$tmp_file_list" } trap cleanup EXIT while IFS= read -r path; do [[ -n "$path" ]] || continue if is_excluded_path "$path"; then continue fi [[ -f "$path" ]] || continue printf '%s\n' "$path" >> "$tmp_file_list" done < <(git ls-files) file_count="$(wc -l < "$tmp_file_list" | tr -d '[:space:]')" [[ "$file_count" -gt 0 ]] || die "No files selected for the update archive." mkdir -p "$output_dir" rm -f "$output_file" zip -q -@ "$output_file" < "$tmp_file_list" [[ -f "$output_file" ]] || die "ZIP archive was not created." checksum="$(sha256_file "$output_file")" size="$(file_size "$output_file")" printf 'Update ZIP created\n' printf 'Version: %s\n' "$version" printf 'Version file: %s\n' "$version_file" printf 'Path: %s\n' "$output_file" printf 'Files: %s\n' "$file_count" printf 'SHA-256: %s\n' "$checksum" printf 'Size: %s bytes\n' "$size"