Repository navigation
Update PHPUnit Snapshots #45
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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" |