diff --git a/.github/workflows/publish-wasm-extension-artifact.yml b/.github/workflows/publish-wasm-extension-artifact.yml index 57560100..69fff8b2 100644 --- a/.github/workflows/publish-wasm-extension-artifact.yml +++ b/.github/workflows/publish-wasm-extension-artifact.yml @@ -26,13 +26,47 @@ concurrency: cancel-in-progress: true jobs: + base-image: + name: Build shared Playground base image + runs-on: ubuntu-latest + timeout-minutes: 20 + + steps: + - name: Check out wordpress-playground + uses: actions/checkout@v4 + with: + repository: WordPress/wordpress-playground + ref: ${{ github.event.inputs.playground-ref || 'trunk' }} + path: wordpress-playground + sparse-checkout: | + packages/php-wasm/compile/base-image + + - name: Build Playground base image + run: | + docker build \ + -f wordpress-playground/packages/php-wasm/compile/base-image/Dockerfile \ + --tag playground-php-wasm:base \ + wordpress-playground/packages/php-wasm/compile/base-image + + - name: Save Playground base image + run: docker save --output "${RUNNER_TEMP}/playground-php-wasm-base.tar" playground-php-wasm:base + + - name: Upload Playground base image + uses: actions/upload-artifact@v4 + with: + name: playground-php-wasm-base-image + path: ${{ runner.temp }}/playground-php-wasm-base.tar + if-no-files-found: error + retention-days: 1 + build: name: Build wp_mysql_parser.so (PHP ${{ matrix.php }}) + needs: base-image runs-on: ubuntu-latest timeout-minutes: 45 strategy: fail-fast: false - max-parallel: 1 + max-parallel: 6 matrix: # The Rust WASM path uses ext-php-rs 0.15, which depends on PHP 8 # Zend APIs. PHP 7.4 cannot be added here by extending the matrix. @@ -83,6 +117,15 @@ jobs: cache: 'npm' cache-dependency-path: wordpress-playground/package-lock.json + - name: Download Playground base image + uses: actions/download-artifact@v4 + with: + name: playground-php-wasm-base-image + path: ${{ runner.temp }}/playground-base-image + + - name: Load Playground base image + run: docker load --input "${RUNNER_TEMP}/playground-base-image/playground-php-wasm-base.tar" + - name: Install Playground deps working-directory: wordpress-playground run: npm ci --ignore-scripts @@ -94,6 +137,7 @@ jobs: ASYNC_MODE: jspi COMPILE_EXTENSION_PACKAGE: '@php-wasm/compile-extension@3.1.27' PLAYGROUND_REPO: ${{ github.workspace }}/wordpress-playground + SKIP_BASE_IMAGE_BUILD: '1' run: bash build-in-docker-rust.sh - name: Verify side module exists diff --git a/.github/workflows/wasm-spike.yml b/.github/workflows/wasm-spike.yml index 39acf065..ffaf6a8f 100644 --- a/.github/workflows/wasm-spike.yml +++ b/.github/workflows/wasm-spike.yml @@ -19,13 +19,47 @@ on: default: 'trunk' jobs: + base-image: + name: Build shared Playground base image + runs-on: ubuntu-latest + timeout-minutes: 20 + + steps: + - name: Check out wordpress-playground + uses: actions/checkout@v4 + with: + repository: WordPress/wordpress-playground + ref: ${{ github.event.inputs.playground-ref || 'trunk' }} + path: wordpress-playground + sparse-checkout: | + packages/php-wasm/compile/base-image + + - name: Build Playground base image + run: | + docker build \ + -f wordpress-playground/packages/php-wasm/compile/base-image/Dockerfile \ + --tag playground-php-wasm:base \ + wordpress-playground/packages/php-wasm/compile/base-image + + - name: Save Playground base image + run: docker save --output "${RUNNER_TEMP}/playground-php-wasm-base.tar" playground-php-wasm:base + + - name: Upload Playground base image + uses: actions/upload-artifact@v4 + with: + name: playground-php-wasm-base-image + path: ${{ runner.temp }}/playground-php-wasm-base.tar + if-no-files-found: error + retention-days: 1 + build-and-load: name: Build wp_mysql_parser.so and load it in Playground (PHP ${{ matrix.php }}) + needs: base-image runs-on: ubuntu-latest timeout-minutes: 45 strategy: fail-fast: false - max-parallel: 1 + max-parallel: 6 matrix: # The Rust WASM path uses ext-php-rs 0.15, which depends on PHP 8 # Zend APIs. PHP 7.4 cannot be added here by extending the matrix. @@ -77,6 +111,15 @@ jobs: cache: 'npm' cache-dependency-path: wordpress-playground/package-lock.json + - name: Download Playground base image + uses: actions/download-artifact@v4 + with: + name: playground-php-wasm-base-image + path: ${{ runner.temp }}/playground-base-image + + - name: Load Playground base image + run: docker load --input "${RUNNER_TEMP}/playground-base-image/playground-php-wasm-base.tar" + - name: Install Playground deps working-directory: wordpress-playground run: npm ci --ignore-scripts @@ -88,6 +131,7 @@ jobs: ASYNC_MODE: ${{ matrix.async-mode }} COMPILE_EXTENSION_PACKAGE: '@php-wasm/compile-extension@3.1.27' PLAYGROUND_REPO: ${{ github.workspace }}/wordpress-playground + SKIP_BASE_IMAGE_BUILD: '1' run: bash build-in-docker-rust.sh - name: Verify build artifacts exist diff --git a/packages/php-ext-wp-mysql-parser/wasm-spike/build-in-docker-rust.sh b/packages/php-ext-wp-mysql-parser/wasm-spike/build-in-docker-rust.sh index e7b13afa..f18d0e39 100755 --- a/packages/php-ext-wp-mysql-parser/wasm-spike/build-in-docker-rust.sh +++ b/packages/php-ext-wp-mysql-parser/wasm-spike/build-in-docker-rust.sh @@ -54,18 +54,66 @@ if [ -z "$PLAYGROUND_REPO" ] || [ ! -f "$PLAYGROUND_REPO/packages/php-wasm/compi exit 1 fi +patch_compile_extension_cli() { + local cli_path="$1" + + # The npm CLI currently rebuilds the Docker images itself. This script has + # already prepared those exact images in Stage 0, so patch the pinned CLI to + # reuse them and fail loudly if the installed package changes shape. + node --input-type=module - "$cli_path" <<'NODE' +import { readFileSync, writeFileSync } from 'node:fs'; + +const cliPath = process.argv[2]; +let source = readFileSync(cliPath, 'utf8'); + +const replacements = [ + [ + 'async function k(e){await p("make",["base-image"],{cwd:e.compileRoot})}', + 'async function k(e){if(process.env.COMPILE_EXTENSION_SKIP_IMAGE_BUILD==="1"){await p("docker",["image","inspect","playground-php-wasm:base"],{stdio:"ignore"});console.log("Skipping compile-extension base image build; using existing playground-php-wasm:base");return}await p("make",["base-image"],{cwd:e.compileRoot})}', + ], + [ + 'async function j(e){const t=$(e);return await p("docker",["build","-f","compile-extension/docker/Dockerfile.ext",".",`--tag=${t}`,"--progress=plain","--build-arg",`PHP_VERSION=${e.phpRelease}`,"--build-arg","JSPI=yes"],{cwd:e.phpWasmRoot}),t}', + 'async function j(e){const t=$(e);if(process.env.COMPILE_EXTENSION_SKIP_IMAGE_BUILD==="1"){await p("docker",["image","inspect",t],{stdio:"ignore"});console.log(`Skipping compile-extension image build; using existing ${t}`);return t}return await p("docker",["build","-f","compile-extension/docker/Dockerfile.ext",".",`--tag=${t}`,"--progress=plain","--build-arg",`PHP_VERSION=${e.phpRelease}`,"--build-arg","JSPI=yes"],{cwd:e.phpWasmRoot}),t}', + ], +]; + +for (const [from, to] of replacements) { + if (!source.includes(from)) { + throw new Error(`Unable to patch @php-wasm/compile-extension CLI. Missing pattern: ${from}`); + } + source = source.replace(from, to); +} + +writeFileSync(cliPath, source); +NODE + + grep -q 'COMPILE_EXTENSION_SKIP_IMAGE_BUILD' "$cli_path" +} + RUST_IMAGE="playground-php-wasm-ext-rust:${PHP_VERSION}-${ASYNC_MODE}" BASE_IMAGE="playground-php-wasm:compile-extension-php${PHP_VERSION//./-}-${ASYNC_MODE}" echo "==> Stage 0: preparing $BASE_IMAGE via Playground compile-extension tooling" -make -C "$PLAYGROUND_REPO/packages/php-wasm/compile" base-image +if [ "${SKIP_BASE_IMAGE_BUILD:-}" = "1" ]; then + if ! docker image inspect playground-php-wasm:base >/dev/null 2>&1; then + echo "SKIP_BASE_IMAGE_BUILD=1 requires a preloaded playground-php-wasm:base image." >&2 + exit 1 + fi + echo "==> Stage 0: using preloaded playground-php-wasm:base" +else + BASE_IMAGE_DIR="$PLAYGROUND_REPO/packages/php-wasm/compile/base-image" + docker build \ + -f "$BASE_IMAGE_DIR/Dockerfile" \ + --tag="playground-php-wasm:base" \ + "$BASE_IMAGE_DIR" +fi docker build \ -f "$PLAYGROUND_REPO/packages/php-wasm/compile-extension/docker/Dockerfile.ext" \ - "$PLAYGROUND_REPO/packages/php-wasm" \ --tag="$BASE_IMAGE" \ --progress=plain \ --build-arg "PHP_VERSION=$PHP_RELEASE" \ - --build-arg "JSPI=yes" + --build-arg "JSPI=yes" \ + "$PLAYGROUND_REPO/packages/php-wasm" echo "==> Stage 0: building $RUST_IMAGE" docker build \ @@ -263,10 +311,11 @@ ARTIFACT="wp_mysql_parser-php${PHP_VERSION}-${ASYNC_MODE}.so" COMPILE_EXTENSION_CLI="$CLI_STAGE/node_modules/@php-wasm/compile-extension/cli.js" npm install --prefix "$CLI_STAGE" --no-audit --no-fund --ignore-scripts "$COMPILE_EXTENSION_PACKAGE" +patch_compile_extension_cli "$COMPILE_EXTENSION_CLI" ( cd "$PLAYGROUND_REPO" - node "$COMPILE_EXTENSION_CLI" \ + COMPILE_EXTENSION_SKIP_IMAGE_BUILD=1 node "$COMPILE_EXTENSION_CLI" \ --source "$SRC_STAGE" \ --name wp_mysql_parser \ --php-versions "$PHP_VERSION" \