Skip to content

Update PHPUnit Snapshots #45

Update PHPUnit Snapshots

Update PHPUnit Snapshots #45

name: Update PHPUnit Snapshots
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * 0' # Every Sunday at midnight UTC
push:
branches:
- main
paths:
- .github/actions/matrix/matrix_includes.yml
- .github/patches/*
- .github/workflows/update-snapshots.yml
permissions:
packages: write
contents: read
jobs:
build-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install PyYAML
run: pip install pyyaml
- name: Extract unique (branch, db) matrix with highest PHP per pair
id: set-matrix
run: |
import yaml, json, os
with open('.github/actions/matrix/matrix_includes.yml') as f:
data = yaml.safe_load(f)
rows = data['include']
# For each (branch, db) pick the row with the highest PHP version.
# Compare as tuples of ints so 8.4 > 8.2 works correctly.
best = {}
for row in rows:
key = (row['moodle-branch'], row['database'])
existing = best.get(key)
if existing is None or \
tuple(int(x) for x in str(row['php']).split('.')) > \
tuple(int(x) for x in str(existing['php']).split('.')):
best[key] = row
def snapshot_image(branch, db):
name = f"snapshot-{branch}-{db}".replace('_', '-').lower()
return f"ghcr.io/catalyst/{name}:latest"
matrix = []
for r in sorted(best.values(), key=lambda x: (x['moodle-branch'], x['database'])):
entry = {
'moodle-branch': r['moodle-branch'],
'database': r['database'],
'php': str(r['php']),
'node': str(r.get('node', 22)),
'snapshot-image': snapshot_image(r['moodle-branch'], r['database']),
}
if r['database'] == 'pgsql':
entry['pgsql-ver'] = str(r['pgsql-ver'])
else:
entry['mariadb-ver'] = str(r['mariadb-ver'])
matrix.append(entry)
with open(os.environ['GITHUB_OUTPUT'], 'a') as fh:
fh.write('matrix=' + json.dumps(matrix) + '\n')
shell: python
build-snapshot:
name: ${{ matrix.moodle-branch }} - ${{ matrix.database }}
needs: build-matrix
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include: ${{ fromJson(needs.build-matrix.outputs.matrix) }}
services:
postgres:
image: ${{ matrix.pgsql-ver && format('postgres:{0}', matrix.pgsql-ver) || '' }}
env:
POSTGRES_USER: 'postgres'
POSTGRES_HOST_AUTH_METHOD: 'trust'
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 3
ports:
- 5432:5432
mariadb:
image: ${{ matrix.mariadb-ver && format('mariadb:{0}', matrix.mariadb-ver) || '' }}
env:
MYSQL_USER: 'root'
MYSQL_ALLOW_EMPTY_PASSWORD: "true"
MYSQL_CHARACTER_SET_SERVER: "utf8mb4"
MYSQL_COLLATION_SERVER: "utf8mb4_unicode_ci"
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping"
--health-interval 10s
--health-timeout 5s
--health-retries 3
steps:
- name: Check out CI repo
uses: actions/checkout@v4
with:
path: ci
- name: Install node ${{ matrix.node }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- name: Setup PHP ${{ matrix.php }}
uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2.32.0
with:
php-version: ${{ matrix.php }}
ini-values: max_input_vars=5000
extensions: pgsql, mysqli, zip, gd, xmlrpc, soap
coverage: none
- name: Install moodle-plugin-ci
shell: bash
run: |
composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci m-ci ^4
echo "$(cd m-ci/bin; pwd)" >> "$GITHUB_PATH"
echo "$(cd m-ci/vendor/bin; pwd)" >> "$GITHUB_PATH"
- name: Clone Moodle for snapshot
shell: bash
run: |
git clone https://github.com/moodle/moodle.git --branch "$MOODLE_BRANCH" "$GITHUB_WORKSPACE/moodle"
env:
MOODLE_BRANCH: ${{ matrix.moodle-branch }}
- name: Apply shared core patches
shell: bash
run: |
git config --global user.email "test@test.com"
git config --global user.name "Test"
MOODLE_BRANCH="${{ matrix.moodle-branch }}"
if [[ "$MOODLE_BRANCH" == "main" ]]; then
BRANCH_NUM=999
elif [[ "$MOODLE_BRANCH" =~ MOODLE_([0-9]+)_STABLE ]]; then
BRANCH_NUM=${BASH_REMATCH[1]}
else
echo "Could not parse branch number from '$MOODLE_BRANCH', skipping shared patches."
exit 0
fi
PATCHES_DIR="${GITHUB_WORKSPACE}/ci/.github/patches"
if [ ! -d "$PATCHES_DIR" ]; then
echo "No shared patches directory found at $PATCHES_DIR, skipping."
exit 0
fi
shopt -s nullglob
PATCH_FILES=( "$PATCHES_DIR"/*.patch )
if [ ${#PATCH_FILES[@]} -eq 0 ]; then
echo "No patch files found in $PATCHES_DIR"
exit 0
fi
for PATCHFILE in "${PATCH_FILES[@]}"; do
BASENAME=$(basename "$PATCHFILE")
if [[ "$BASENAME" =~ ^([0-9]+)-([0-9]+)- ]]; then
MIN_VER=${BASH_REMATCH[1]}
MAX_VER=${BASH_REMATCH[2]}
if (( BRANCH_NUM < MIN_VER || BRANCH_NUM > MAX_VER )); then
echo "Skipping $BASENAME (branch $BRANCH_NUM not in range $MIN_VER-$MAX_VER)"
continue
fi
else
echo "WARNING: patch $BASENAME has no version prefix (expected NNN-NNN-name.patch), skipping."
continue
fi
echo "Applying shared patch $BASENAME to branch $MOODLE_BRANCH..."
cd "$GITHUB_WORKSPACE/moodle"
git am --whitespace=nowarn < "$PATCHFILE"
done
- name: Install Moodle composer dependencies
shell: bash
run: |
composer --working-dir="moodle" install --no-interaction --prefer-dist
- name: Install PHPUnit DB for snapshot (no plugin install)
shell: bash
env:
DB: ${{ matrix.database }}
run: |
if [ "$DB" = "pgsql" ]; then
DBTYPE="pgsql"
psql -h 127.0.0.1 -U postgres -d postgres -c "DROP DATABASE IF EXISTS moodle;"
psql -h 127.0.0.1 -U postgres -d postgres -c "CREATE DATABASE moodle;"
else
DBTYPE="mariadb"
mysql -h 127.0.0.1 -u root -e "DROP DATABASE IF EXISTS moodle; CREATE DATABASE moodle DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
fi
# Render config.php from template — only DBTYPE varies.
sed "s|{{DBTYPE}}|$DBTYPE|g" \
"$GITHUB_WORKSPACE/ci/.github/templates/moodle-config-template.php" > moodle/config.php
# Detect phpunit CLI location (differs between classic and public/ layouts).
if [ -f "moodle/public/admin/tool/phpunit/cli/init.php" ]; then
PHPUNIT_CLI="moodle/public/admin/tool/phpunit/cli"
elif [ -f "moodle/admin/tool/phpunit/cli/init.php" ]; then
PHPUNIT_CLI="moodle/admin/tool/phpunit/cli"
else
echo "Could not locate Moodle phpunit init script in moodle/ or moodle/public/."
exit 1
fi
sudo locale-gen en_AU.UTF-8
mkdir -p "$GITHUB_WORKSPACE/moodledata/phpunit"
php "$PHPUNIT_CLI/init.php"
- name: Archive phpunit-ready Moodle tree
shell: bash
run: |
rm -rf moodle/.git
tar -C "$GITHUB_WORKSPACE" -czf "$GITHUB_WORKSPACE/moodle.tar.gz" moodle
echo "MOODLE_ARCHIVE=$GITHUB_WORKSPACE/moodle.tar.gz" >> "$GITHUB_ENV"
- name: Export phpunit snapshot
shell: bash
run: |
# Detect util.php location (differs between classic and public/ layouts).
if [ -f "$GITHUB_WORKSPACE/moodle/public/admin/tool/phpunit/cli/util.php" ]; then
PHPUNIT_UTIL="$GITHUB_WORKSPACE/moodle/public/admin/tool/phpunit/cli/util.php"
elif [ -f "$GITHUB_WORKSPACE/moodle/admin/tool/phpunit/cli/util.php" ]; then
PHPUNIT_UTIL="$GITHUB_WORKSPACE/moodle/admin/tool/phpunit/cli/util.php"
else
echo "Could not locate phpunit util.php"
exit 1
fi
cd moodle
php "$PHPUNIT_UTIL" --snapshot=ci-phpunit
# phpunit_dataroot is always $GITHUB_WORKSPACE/moodledata/phpunit per the config template.
PHPUNIT_DATAROOT="$GITHUB_WORKSPACE/moodledata/phpunit"
PHPUNIT_SNAPSHOT=$(find "$PHPUNIT_DATAROOT" -maxdepth 1 -type f -name '*-ci-phpunit-*.zip' | head -n1)
if [ -z "$PHPUNIT_SNAPSHOT" ]; then
echo "Could not find phpunit snapshot archive in $PHPUNIT_DATAROOT"
exit 1
fi
cp "$PHPUNIT_SNAPSHOT" "$GITHUB_WORKSPACE/phpunit-snapshot.zip"
echo "PHPUNIT_SNAPSHOT=$GITHUB_WORKSPACE/phpunit-snapshot.zip" >> "$GITHUB_ENV"
- name: Archive moodle-plugin-ci
shell: bash
run: |
tar -C "$GITHUB_WORKSPACE" -czf "$GITHUB_WORKSPACE/m-ci.tar.gz" m-ci
echo "MCI_ARCHIVE=$GITHUB_WORKSPACE/m-ci.tar.gz" >> "$GITHUB_ENV"
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push snapshot Docker image
shell: bash
run: |
IMAGE="${{ matrix.snapshot-image }}"
BUILD_DIR=$(mktemp -d)
cp "$PHPUNIT_SNAPSHOT" "$BUILD_DIR/phpunit-snapshot.zip"
cp "$MOODLE_ARCHIVE" "$BUILD_DIR/moodle.tar.gz"
cp "$MCI_ARCHIVE" "$BUILD_DIR/m-ci.tar.gz"
printf 'FROM alpine:3\nCOPY phpunit-snapshot.zip /phpunit-snapshot.zip\nCOPY moodle.tar.gz /moodle.tar.gz\nCOPY m-ci.tar.gz /m-ci.tar.gz\n' > "$BUILD_DIR/Dockerfile"
docker build -t "$IMAGE" "$BUILD_DIR"
docker push "$IMAGE"
echo "Pushed snapshot image: $IMAGE"
rm -rf "$BUILD_DIR"