mirror of
https://github.com/getgrav/grav.git
synced 2026-05-09 16:07:26 +02:00
chore: remove GPM family-gate dev/test utilities from 1.8
These were development-only tooling for iterating on the family-aware upgrade gate and the next_major migration hint: - bin/gpm-cache-inject — synthetic GPM response injection - bin/gpm-e2e-test — family-gate E2E runner - bin/gpm-test-server.php — local fake grav.json server Not referenced from production code or CI. Preserved in git stash alongside bin/gpm-migration-probe and bin/gpm-migration-e2e for future hint-flow testing.
This commit is contained in:
@@ -1,160 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/**
|
||||
* GPM cache injector for testing family-aware upgrade behavior.
|
||||
*
|
||||
* Writes a fake GPM JSON response into the Grav file cache so you can test
|
||||
* what happens when the server reports a particular version (e.g. 2.0.0)
|
||||
* without actually deploying server-side changes.
|
||||
*
|
||||
* Usage:
|
||||
* php bin/gpm-cache-inject [fake-version] [channel]
|
||||
*
|
||||
* Examples:
|
||||
* php bin/gpm-cache-inject 2.0.0 # fake server returning 2.0.0 (stable channel)
|
||||
* php bin/gpm-cache-inject 1.8.0-beta.29 # fake a specific 1.8 beta
|
||||
* php bin/gpm-cache-inject 2.0.0 testing # fake 2.0.0 on the testing channel
|
||||
* php bin/gpm-cache-inject --clear # delete cached GPM data (forces re-fetch)
|
||||
*
|
||||
* After running this, execute:
|
||||
* bin/gpm selfupgrade
|
||||
*
|
||||
* Then restore real data with:
|
||||
* php bin/gpm-cache-inject --clear
|
||||
*/
|
||||
|
||||
if (!defined('GRAV_ROOT')) {
|
||||
define('GRAV_ROOT', dirname(__DIR__));
|
||||
}
|
||||
define('DS', DIRECTORY_SEPARATOR);
|
||||
|
||||
// We only need the autoloader — no full Grav bootstrap
|
||||
$autoload = GRAV_ROOT . '/vendor/autoload.php';
|
||||
if (!file_exists($autoload)) {
|
||||
fwrite(STDERR, "ERROR: vendor/autoload.php not found. Run: composer install\n");
|
||||
exit(1);
|
||||
}
|
||||
require $autoload;
|
||||
|
||||
use Doctrine\Common\Cache\FilesystemCache;
|
||||
|
||||
// ── Parse arguments ───────────────────────────────────────────────────────────
|
||||
|
||||
$fakeVersion = null;
|
||||
$channel = 'stable';
|
||||
$clear = false;
|
||||
|
||||
foreach (array_slice($argv, 1) as $arg) {
|
||||
if ($arg === '--clear') {
|
||||
$clear = true;
|
||||
} elseif ($arg === 'stable' || $arg === 'testing') {
|
||||
$channel = $arg;
|
||||
} else {
|
||||
$fakeVersion = $arg;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Resolve GRAV_VERSION from this install ────────────────────────────────────
|
||||
|
||||
// Read from the system/src/defines.php or CHANGELOG rather than bootstrapping Grav
|
||||
$changelogFile = GRAV_ROOT . '/CHANGELOG.md';
|
||||
$gravVersion = 'unknown';
|
||||
if (file_exists($changelogFile)) {
|
||||
$first = fopen($changelogFile, 'r');
|
||||
while (($line = fgets($first)) !== false) {
|
||||
if (preg_match('/^#\s+v?([\d]+\.[\d]+\.[\d]+(?:[-\w.]+)?)/', $line, $m)) {
|
||||
$gravVersion = $m[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose($first);
|
||||
}
|
||||
|
||||
if ($gravVersion === 'unknown') {
|
||||
fwrite(STDERR, "ERROR: Could not determine GRAV_VERSION from CHANGELOG.md\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// ── Build the exact repository URL GravCore uses ─────────────────────────────
|
||||
|
||||
$repositoryUrl = 'https://getgrav.org/downloads/grav.json?v=' . $gravVersion . '&' . $channel . '=1';
|
||||
$cacheKey = md5($repositoryUrl);
|
||||
$cacheDir = GRAV_ROOT . '/cache/gpm';
|
||||
|
||||
echo "GRAV_VERSION : $gravVersion\n";
|
||||
echo "Channel : $channel\n";
|
||||
echo "URL (key) : $repositoryUrl\n";
|
||||
echo "Cache key : $cacheKey\n";
|
||||
echo "Cache dir : $cacheDir\n\n";
|
||||
|
||||
$cache = new FilesystemCache($cacheDir);
|
||||
|
||||
// ── Clear mode ────────────────────────────────────────────────────────────────
|
||||
|
||||
if ($clear) {
|
||||
$cache->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);
|
||||
}
|
||||
162
bin/gpm-e2e-test
162
bin/gpm-e2e-test
@@ -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
|
||||
@@ -1,133 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Local GPM test server — simulates getgrav.org/downloads/grav.json
|
||||
*
|
||||
* Start with: php -S localhost:8043 bin/gpm-test-server.php
|
||||
*
|
||||
* Mode is controlled by writing a string to /tmp/gpm-test-mode:
|
||||
* echo family > /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);
|
||||
Reference in New Issue
Block a user