Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion phpbb-test-board/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ They build a board on SQLite and run an extension on it with PHP error logging o
- `git`, `php` (with the `sqlite3` extension), `composer`, `curl`, `jq` and `openssl`
- Python 3 with `venv`
- ImageMagick's `convert`, for the reassignthumbs feature check
- Docker, for `php-lint.sh`
- Docker, for `php-lint.sh` and `enable-on-php.sh`

The Python scripts create their own virtualenv (`.venv` in this folder) on first run and install `requirements.txt` into it; nothing needs installing or activating by hand. `screenshots.py` also downloads Playwright's Chromium on its first run.

Expand Down Expand Up @@ -69,6 +69,16 @@ Runs `php -l` on every PHP file under each PHP version (default 7.4 and 8.4), in

Exit status: 0 when every file passes on every version, 1 when a file fails or Docker fails, 2 for bad arguments. The first run of a version pulls its image.

### `enable-on-php.sh`: enable on another PHP version

```bash
phpbb-test-board/enable-on-php.sh [-p 8.1] [--disable] BOARD_ROOT path/to/extension...
```

Enables each extension on a SQLite board built with [seed-forum](https://github.com/phpbbmodders/seed-forum) (`database: sqlite`, no extensions), running phpBB's `extension:enable` in a throwaway `php:VERSION-cli` container. That command calls `is_enableable()` and then runs the migrations, so it shows whether an extension installs on that PHP, or the refusal message when it should not (for example one version below its minimum). The board is mounted read-write at its own path, because `config.php` names the database by its absolute path; each extension is mounted read-only under `ext/` from its `composer.json` name, so nothing is copied into the board. Extensions that fail are retried once after the others, for ones that need another extension. `--disable` disables and purges them again afterwards.

Exit status: 0 when every extension enabled, 1 when one failed or Docker fails, 2 for bad arguments. Needs Docker and `jq`.

### `run-epv.sh`: EPV the way CI fails on it

```bash
Expand Down
161 changes: 161 additions & 0 deletions phpbb-test-board/enable-on-php.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
#!/usr/bin/bash
# enable-on-php.sh
#
# Enables phpBB extensions on an existing SQLite test board under a chosen PHP
# version, without that PHP being installed on this machine. phpBB's CLI
# (bin/phpbbcli.php extension:enable) runs in a throwaway Docker container
# from the official php:VERSION-cli image. That command calls the extension's
# is_enableable() and then runs its migrations, so it proves the extension
# installs on that PHP, or shows the refusal message when it does not.
#
# Build the board with seed-forum first (database: sqlite, no extensions).
# The board folder is mounted read-write at its own path, because config.php
# names the SQLite database by its absolute path; each extension checkout is mounted read-only at
# ext/VENDOR/NAME, taken from its composer.json name, so nothing is copied
# into the board. The container has no network, runs as the calling user, and
# is removed when it exits.
#
# Extensions are enabled in the order given; any that fail are retried once
# after the others, so one that depends on another still enables when the
# dependency comes later on the command line. With --disable, every
# extension that enabled is disabled and purged again afterwards, leaving the
# board as it was.
#
# Usage: enable-on-php.sh [-p VERSION] [-d] BOARD_ROOT EXT_DIR...
# Outputs: the PHP version that ran, then one line per extension (ENABLED or
# FAILED, with phpBB's message for a failure) on stdout
# Exit status: 0 when every extension enabled, 1 when one failed or Docker
# failed, 2 for bad arguments.

set -Eeuo pipefail

usage() {
cat <<'EOF'
Usage: enable-on-php.sh [options] BOARD_ROOT EXT_DIR...

Enable each extension in EXT_DIR... on the SQLite phpBB board at BOARD_ROOT,
running phpBB's CLI under PHP VERSION in a throwaway Docker container
(official php:VERSION-cli image, no network). Extensions are mounted
read-only at ext/VENDOR/NAME from their composer.json name.

Arguments:
BOARD_ROOT a seed-forum board using database: sqlite
EXT_DIR... extension checkouts (each with a composer.json)

Options:
-p, --php VERSION PHP version, as a php:VERSION-cli image tag (default: 8.1)
-d, --disable disable and purge every enabled extension afterwards
-h, --help show this help and exit

Examples:
enable-on-php.sh -p 8.1 ~/seeded-board/php81 ~/repos/contactadmin
enable-on-php.sh -p 8.0 -d ~/seeded-board/php81 ~/repos/zodiacs
EOF
}

usage_error() {
echo "Error: $*" >&2
echo "Run with --help for usage." >&2
exit 2
}

php_version="8.1"
disable_after=0
positional=()

while [ "$#" -gt 0 ]; do
case "$1" in
-p|--php)
[ "$#" -ge 2 ] || usage_error "$1 needs a version"
php_version="$2"
shift 2
;;
-d|--disable)
disable_after=1
shift
;;
-h|--help)
usage
exit 0
;;
-*)
usage_error "unknown option: $1"
;;
*)
positional+=("$1")
shift
;;
esac
done

[ "${#positional[@]}" -ge 2 ] || { usage; exit 2; }
[[ "$php_version" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?$ ]] || usage_error "PHP version must look like 8.1 or 8.1.34"

board_root=$(realpath -- "${positional[0]}")
if [ ! -f "$board_root/config.php" ] || [ ! -f "$board_root/bin/phpbbcli.php" ]; then
usage_error "$board_root is not an installed phpBB board"
fi
grep -q "sqlite3" "$board_root/config.php" \
|| usage_error "$board_root does not use SQLite; only SQLite boards work without a database container"

command -v docker >/dev/null || { echo "Error: docker is not installed" >&2; exit 1; }
command -v jq >/dev/null || { echo "Error: jq is not installed" >&2; exit 1; }

# One read-only mount and one package name per extension.
mounts=()
names=()
for dir in "${positional[@]:1}"; do
dir=$(realpath -- "$dir")
[ -f "$dir/composer.json" ] || usage_error "$dir has no composer.json"
name=$(jq -r '.name // empty' "$dir/composer.json")
[[ "$name" =~ ^[a-z0-9_-]+/[a-z0-9_-]+$ ]] || usage_error "$dir/composer.json has no valid vendor/name"
if [ -e "$board_root/ext/$name" ] && [ -n "$(ls -A "$board_root/ext/$name" 2>/dev/null)" ]; then
usage_error "$board_root/ext/$name already holds files; use a board without that extension"
fi
mounts+=(-v "$dir:$board_root/ext/$name:ro")
names+=("$name")
done

# Runs inside the container: enable each name, retry failures once, report.
read -r -d '' inner <<'EOF' || true
cd "$BOARD_ROOT"
printf 'PHP %s\n' "$(php -r 'echo PHP_VERSION;')"
php bin/phpbbcli.php cache:purge >/dev/null 2>&1 || true
pending=("$@")
for pass in 1 2; do
failed=()
for name in "${pending[@]}"; do
if out=$(php bin/phpbbcli.php --no-ansi extension:enable "$name" 2>&1); then
echo "ENABLED $name"
else
failed+=("$name")
[ "$pass" = 2 ] && echo "FAILED $name: $(echo "$out" | tr -s ' \n' ' ' | sed 's/^ *//')"
fi
done
pending=("${failed[@]}")
[ "${#pending[@]}" -eq 0 ] && break
done
if [ "$DISABLE_AFTER" = 1 ]; then
for name in "$@"; do
php bin/phpbbcli.php extension:disable "$name" >/dev/null 2>&1 || true
php bin/phpbbcli.php extension:purge "$name" >/dev/null 2>&1 || true
done
php bin/phpbbcli.php cache:purge >/dev/null 2>&1 || true
fi
[ "${#pending[@]}" -eq 0 ]
EOF

# Mount points for the extensions are created inside the read-write board
# mount; remove the empty folders Docker leaves behind afterwards.
cleanup() {
for name in "${names[@]}"; do
rmdir "$board_root/ext/$name" 2>/dev/null || true
rmdir "$board_root/ext/${name%%/*}" 2>/dev/null || true
done
}
trap cleanup EXIT

docker run --rm --network none --user "$(id -u):$(id -g)" \
-e DISABLE_AFTER="$disable_after" \
-e BOARD_ROOT="$board_root" -v "$board_root:$board_root" "${mounts[@]}" \
"php:$php_version-cli" bash -c "$inner" enable-on-php "${names[@]}"
Loading