diff --git a/bin/gpm-cache-inject b/bin/gpm-cache-inject deleted file mode 100755 index 01752ccb8..000000000 --- a/bin/gpm-cache-inject +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env php -delete($cacheKey); - echo "Cache cleared. Next GPM call will fetch live data from getgrav.org.\n"; - exit(0); -} - -// ── Inject mode ─────────────────────────────────────────────────────────────── - -if (!$fakeVersion) { - fwrite(STDERR, "ERROR: Provide a version to inject, e.g.:\n php bin/gpm-cache-inject 2.0.0\n"); - exit(1); -} - -$fakeJson = json_encode([ - 'version' => $fakeVersion, - 'date' => date('Y-m-d\TH:i:s\Z'), - 'assets' => [ - 'grav' => [ - 'name' => "grav-v{$fakeVersion}.zip", - 'type' => 'application/zip', - 'size' => 1000000, - 'download' => "https://getgrav.org/download/core/grav/{$fakeVersion}", - ], - 'grav-admin' => [ - 'name' => "grav-admin-v{$fakeVersion}.zip", - 'type' => 'application/zip', - 'size' => 1500000, - 'download' => "https://getgrav.org/download/core/grav-admin/{$fakeVersion}", - ], - ], - 'url' => "https://github.com/getgrav/grav/releases/tag/{$fakeVersion}", - 'min_php' => '8.1.0', - 'changelog' => new stdClass(), -], JSON_PRETTY_PRINT); - -$lifetime = 86400; // match GravCore's lifetime -$saved = $cache->save($cacheKey, $fakeJson, $lifetime); - -if ($saved) { - echo "Injected fake GPM response:\n"; - echo " Fake version : $fakeVersion\n"; - echo " Channel : $channel\n\n"; - echo "Now run:\n"; - echo " bin/gpm selfupgrade\n\n"; - echo "Expected results with the family gate active:\n"; - $localParts = explode('.', $gravVersion); - $remoteParts = explode('.', ltrim($fakeVersion, 'v')); - $localFamily = ($localParts[0] ?? '0') . '.' . ($localParts[1] ?? '0'); - $remoteFamily = ($remoteParts[0] ?? '0') . '.' . ($remoteParts[1] ?? '0'); - if ($localFamily !== $remoteFamily) { - echo " isUpgradable() → FALSE (cross-family: $localFamily → $remoteFamily)\n"; - $localMajor = (int)($localParts[0] ?? 0); - $remoteMajor = (int)($remoteParts[0] ?? 0); - $notice = $remoteMajor > $localMajor ? 'TRUE' : 'false'; - echo " isNextMajorAvailable()→ $notice\n"; - } else { - $upgradable = version_compare($gravVersion, $fakeVersion, '<') ? 'TRUE' : 'false'; - echo " isUpgradable() → $upgradable (same family: $localFamily)\n"; - echo " isNextMajorAvailable()→ false\n"; - } - echo "\nClean up with:\n"; - echo " php bin/gpm-cache-inject --clear\n"; -} else { - fwrite(STDERR, "ERROR: Failed to write cache. Check that $cacheDir is writable.\n"); - exit(1); -} diff --git a/bin/gpm-e2e-test b/bin/gpm-e2e-test deleted file mode 100755 index 7abeb97f2..000000000 --- a/bin/gpm-e2e-test +++ /dev/null @@ -1,162 +0,0 @@ -#!/usr/bin/env bash -# -# E2E test for family-aware GPM upgrade gate. -# Run from the Grav install root: bash bin/gpm-e2e-test -# -# Requires: php (CLI), bin/gpm-test-server.php, updated Upgrader.php - -set -uo pipefail - -GRAV_DIR="$(cd "$(dirname "$0")/.." && pwd)" -PORT=8043 -SERVER_PID="" -MODE_FILE=/tmp/gpm-test-mode - -# ── Colours ─────────────────────────────────────────────────────────────────── -GREEN='\033[0;32m'; RED='\033[0;31m'; YELLOW='\033[1;33m'; RESET='\033[0m' -PASS=0; FAIL=0 - -pass() { echo -e " ${GREEN}PASS${RESET} $1"; PASS=$((PASS + 1)); } -fail() { echo -e " ${RED}FAIL${RESET} $1"; FAIL=$((FAIL + 1)); } -section() { echo -e "\n${YELLOW}── $1 ──${RESET}"; } - -# ── Server lifecycle ────────────────────────────────────────────────────────── -start_server() { - stop_server - - # Kill anything still bound to the port - lsof -ti tcp:$PORT | xargs kill -9 2>/dev/null || true - sleep 0.3 - - php -S "localhost:$PORT" \ - -t "$GRAV_DIR" \ - "$GRAV_DIR/bin/gpm-test-server.php" \ - > /tmp/gpm-test-server.log 2>&1 & - SERVER_PID=$! - sleep 0.5 - - # Sanity check - if ! curl -sf "http://localhost:$PORT/grav.json?v=1.8.0-beta.25&stable=1" > /dev/null; then - echo "ERROR: test server failed to start. Log:" >&2 - cat /tmp/gpm-test-server.log >&2 - exit 1 - fi -} - -stop_server() { - if [ -n "${SERVER_PID:-}" ]; then - kill "$SERVER_PID" 2>/dev/null || true - SERVER_PID="" - fi -} - -set_mode() { echo "$1" > "$MODE_FILE"; } - -trap 'stop_server; rm -f "$MODE_FILE"' EXIT - -# ── Helpers ─────────────────────────────────────────────────────────────────── -clear_gpm_cache() { - rm -rf "$GRAV_DIR/cache/gpm" -} - -# Run selfupgrade non-interactively: pipe two empty lines (defaults both -# changelog and upgrade prompts to "No") so the command exits cleanly -# without trying to download anything. -run_selfupgrade() { - printf '\n\n' | php "$GRAV_DIR/bin/gpm" selfupgrade 2>&1 || true -} - -assert_contains() { - local output="$1" pattern="$2" label="$3" - if echo "$output" | grep -qiE "$pattern"; then - pass "$label" - else - fail "$label" - echo " Expected (regex): $pattern" - echo " Actual output:" - echo "$output" | sed 's/^/ /' - fi -} - -assert_not_contains() { - local output="$1" pattern="$2" label="$3" - if echo "$output" | grep -qiE "$pattern"; then - fail "$label" - echo " Should NOT match (regex): $pattern" - echo " Actual output:" - echo "$output" | sed 's/^/ /' - else - pass "$label" - fi -} - -# ───────────────────────────────────────────────────────────────────────────── -GRAV_VERSION=$(grep -m1 '^# v' "$GRAV_DIR/CHANGELOG.md" | sed 's/^# v//') - -echo "" -echo "Install : $GRAV_DIR" -echo "Version : $GRAV_VERSION" -echo "" - -start_server - -# ═════════════════════════════════════════════════════════════════════════════ -# SCENARIO A — old server behaviour (no family filter, returns 2.0.1 globally) -# Client gate in Upgrader.php must block the cross-family upgrade. -# ═════════════════════════════════════════════════════════════════════════════ -section "Scenario A: Old server returns 2.0.1 — client must block" - -set_mode global -clear_gpm_cache -A=$(run_selfupgrade) - -# Server log so we can see what was actually served -echo " Server: $(cat /tmp/gpm-test-server.log | tail -1)" - -assert_contains "$A" "already running the latest" \ - "selfupgrade reports no upgrade available" -assert_not_contains "$A" "Preparing to upgrade|Downloading" \ - "selfupgrade does not attempt to download" - -# ═════════════════════════════════════════════════════════════════════════════ -# SCENARIO B — new server behaviour (family filter, returns 1.8.0-beta.29) -# selfupgrade should recognise the 1.8 update and offer it. -# ═════════════════════════════════════════════════════════════════════════════ -section "Scenario B: Family server returns 1.8.0-beta.29 — upgrade should be offered" - -set_mode family -clear_gpm_cache -B=$(run_selfupgrade) - -echo " Server: $(cat /tmp/gpm-test-server.log | tail -1)" - -assert_contains "$B" "1\.8\.0-beta\.29.*is now available|is now available.*1\.8\.0-beta\.29" \ - "selfupgrade reports 1.8.0-beta.29 is available" -assert_not_contains "$B" "already running the latest" \ - "selfupgrade does not report 'already up to date'" -assert_not_contains "$B" "2\.0\." \ - "selfupgrade does not mention 2.0.x as a target" - -# ═════════════════════════════════════════════════════════════════════════════ -# SCENARIO C — server returns same version (no upgrade needed) -# ═════════════════════════════════════════════════════════════════════════════ -section "Scenario C: Server returns same version — already up to date" - -set_mode same -clear_gpm_cache -C=$(run_selfupgrade) - -echo " Server: $(cat /tmp/gpm-test-server.log | tail -1)" - -assert_contains "$C" "already running the latest" \ - "selfupgrade reports already up to date" - -# ───────────────────────────────────────────────────────────────────────────── -echo "" -if [ "$FAIL" -eq 0 ]; then - echo -e "${GREEN}All $PASS tests passed.${RESET}" - exit 0 -else - echo -e "${RED}$FAIL test(s) failed, $PASS passed.${RESET}" - exit 1 -fi diff --git a/bin/gpm-test-server.php b/bin/gpm-test-server.php deleted file mode 100755 index 844151ae5..000000000 --- a/bin/gpm-test-server.php +++ /dev/null @@ -1,133 +0,0 @@ - /tmp/gpm-test-mode (default) return latest in client's major.minor family - * echo global > /tmp/gpm-test-mode return globally latest (old server, no family filter) - * echo same > /tmp/gpm-test-mode return same version as client (no upgrade) - */ - -$v = $_GET['v'] ?? ''; -$testing = isset($_GET['testing']); -$mode = trim(@file_get_contents('/tmp/gpm-test-mode') ?: 'family'); - -// Simulated release list — newest first, mirrors a real GitHub releases page -$releases = [ - ['version' => '2.0.1', 'prerelease' => false], - ['version' => '2.0.0', 'prerelease' => false], - ['version' => '1.8.0-beta.29', 'prerelease' => true], - ['version' => '1.8.0-beta.28', 'prerelease' => true], - ['version' => '1.8.0-beta.25', 'prerelease' => true], - ['version' => '1.7.51', 'prerelease' => false], - ['version' => '1.7.50', 'prerelease' => false], -]; - -function extractFamily(string $ver): string -{ - $parts = explode('.', ltrim($ver, 'v')); - return ($parts[0] ?? '0') . '.' . ($parts[1] ?? '0'); -} - -/** - * Find the latest release in $family. - * On stable channel: prefer a stable release, but fall back to latest prerelease if no stable - * exists in that family yet (e.g. 1.8 is still all-beta). - * On testing channel: just return the newest. - */ -function findLatestInFamily(array $releases, string $family, bool $testing): ?string -{ - $stableInFamily = null; - $anyInFamily = null; - - foreach ($releases as $r) { - if (extractFamily($r['version']) !== $family) { - continue; - } - if ($anyInFamily === null) { - $anyInFamily = $r['version']; // newest in family (releases are sorted newest-first) - } - if (!$r['prerelease'] && $stableInFamily === null) { - $stableInFamily = $r['version']; - } - } - - // On stable channel prefer a stable release; fall back to latest prerelease if no stable yet - return ($testing ? $anyInFamily : ($stableInFamily ?? $anyInFamily)); -} - -function findGlobalLatest(array $releases, bool $testing): string -{ - foreach ($releases as $r) { - if ($testing || !$r['prerelease']) { - return $r['version']; - } - } - return $releases[0]['version']; -} - -// ── Resolve version to serve ────────────────────────────────────────────────── -$clientFamily = extractFamily($v); - -switch ($mode) { - case 'global': - // Old server behaviour: always return the globally latest, ignore ?v - $serveVersion = findGlobalLatest($releases, $testing); - break; - case 'same': - // No upgrade scenario: mirror back whatever version the client has - $serveVersion = $v ?: findGlobalLatest($releases, $testing); - break; - case 'family': - default: - // New server behaviour: return latest within the client's major.minor family - $serveVersion = findLatestInFamily($releases, $clientFamily, $testing) - ?? findGlobalLatest($releases, $testing); - break; -} - -// ── Log to stderr (visible in php -S output) ───────────────────────────────── -$log = sprintf( - "[%s] %s v=%s family=%s testing=%s mode=%s → %s\n", - date('H:i:s'), - $_SERVER['REQUEST_URI'], - $v, - $clientFamily, - $testing ? 'yes' : 'no', - $mode, - $serveVersion -); -file_put_contents('php://stderr', $log); - -// ── Respond ─────────────────────────────────────────────────────────────────── -header('Content-Type: application/json'); -echo json_encode([ - 'version' => $serveVersion, - 'date' => '2025-06-01T12:00:00Z', - 'assets' => [ - 'grav-update' => [ - 'name' => "grav-update-v{$serveVersion}.zip", - 'type' => 'application/zip', - 'size' => 3000000, - 'download' => "http://localhost:8043/download/grav-update/{$serveVersion}", - ], - 'grav-admin' => [ - 'name' => "grav-admin-v{$serveVersion}.zip", - 'type' => 'application/zip', - 'size' => 5000000, - 'download' => "http://localhost:8043/download/grav-admin/{$serveVersion}", - ], - 'grav' => [ - 'name' => "grav-v{$serveVersion}.zip", - 'type' => 'application/zip', - 'size' => 4000000, - 'download' => "http://localhost:8043/download/grav/{$serveVersion}", - ], - ], - 'url' => "https://github.com/getgrav/grav/releases/tag/{$serveVersion}", - 'min_php' => '8.1.0', - 'changelog' => new stdClass(), -], JSON_PRETTY_PRINT);