Skip to content

The 7.0 font subsystem: remove the core installer, add language packs and the new Font Manager #297

The 7.0 font subsystem: remove the core installer, add language packs and the new Font Manager

The 7.0 font subsystem: remove the core installer, add language packs and the new Font Manager #297

Workflow file for this run

name: Tests
on:
workflow_dispatch:
pull_request:
types: [ opened, reopened, synchronize, labeled ]
schedule:
- cron: "0 20 * * 0,2,4" # Mon/Wed/Fri 6am Sydney AEST (7am during AEDT)
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }}
cancel-in-progress: true
env:
GF_LICENSE: ${{ secrets.GF_LICENSE }}
jobs:
check_for_run_tests_label_in_pr:
name: Should workflow run?
runs-on: ubuntu-latest
steps:
# pull_request:opened can fire before labels are applied (empty webhook payload labels[]) —
# read live labels via gh-api; runner spin-up absorbs the propagation window.
- name: Check for run-tests label
if: ${{ github.event_name == 'pull_request' }}
env:
GH_TOKEN: ${{ github.token }}
PR: ${{ github.event.pull_request.number }}
run: gh pr view "$PR" --repo "$GITHUB_REPOSITORY" --json labels --jq '.labels[].name' | grep -qx 'run-tests'
# composer.json's post-install-cmd chains `composer prefix` + `yarn install && yarn build`, so one composer install
# here primes vendor/, vendor_prefixed/, node_modules/, and build/assets/ for every downstream matrix.
prebuild:
name: Prebuild shared caches
needs: check_for_run_tests_label_in_pr
runs-on: ubuntu-latest
outputs:
chromatic-enabled: ${{ steps.chromatic-gate.outputs.enabled }}
steps:
- name: Decide whether Chromatic runs this push
id: chromatic-gate
env:
EVENT_NAME: ${{ github.event_name }}
PR_DRAFT: ${{ github.event.pull_request.draft }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_BODY: ${{ github.event.pull_request.body }}
run: |
enabled=true
reason=enabled
if [ "$EVENT_NAME" = "pull_request" ]; then
if [ "$PR_DRAFT" = "true" ]; then
enabled=false; reason=draft
elif printf '%s' "$PR_TITLE" | grep -qiwE 'wip'; then
enabled=false; reason='WIP in title'
elif printf '%s' "$PR_BODY" | grep -qiwE 'wip'; then
enabled=false; reason='WIP in body'
fi
fi
echo "[chromatic-gate] enabled=$enabled ($reason)"
echo "enabled=$enabled" >> "$GITHUB_OUTPUT"
- name: Checkout repository
uses: actions/checkout@v6
# Bundled — composer install + the php-scoper post step produce them together; they must invalidate together.
- name: Check Composer vendor cache
id: vendor-cache
uses: actions/cache/restore@v5
with:
path: |
vendor
vendor_prefixed
key: vendor-${{ runner.os }}-${{ hashFiles('composer.lock', 'tools/php-scoper/**') }}
lookup-only: true
- name: Check node_modules cache
id: nm-cache
uses: actions/cache/restore@v5
with:
path: node_modules
key: nm-${{ runner.os }}-${{ hashFiles('yarn.lock', '.nvmrc') }}
lookup-only: true
# Lets Playwright shards skip the webpack rebuild.
- name: Check build assets cache
id: build-cache
uses: actions/cache/restore@v5
with:
path: build/assets
key: build-${{ runner.os }}-${{ hashFiles('src/assets/**', 'yarn.lock', '.nvmrc', 'package.json', 'babel.config.js', '.browserslistrc') }}
lookup-only: true
# 8.3 because this job runs php-scoper, which requires PHP 8.2+. composer.json pins the
# platform to 7.4, so the resolved dependencies are unaffected by the runtime version.
- name: Setup PHP
if: ${{ steps.vendor-cache.outputs.cache-hit != 'true' || steps.nm-cache.outputs.cache-hit != 'true' || steps.build-cache.outputs.cache-hit != 'true' }}
uses: shivammathur/setup-php@v2
with:
php-version: 8.3
- name: Setup Node JS
if: ${{ steps.vendor-cache.outputs.cache-hit != 'true' || steps.nm-cache.outputs.cache-hit != 'true' || steps.build-cache.outputs.cache-hit != 'true' }}
uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- name: Add auth details for private composer packages
if: ${{ steps.vendor-cache.outputs.cache-hit != 'true' || steps.nm-cache.outputs.cache-hit != 'true' || steps.build-cache.outputs.cache-hit != 'true' }}
run: composer config http-basic.composer.gravity.io ${{ secrets.GF_LICENSE }} http://localhost
- name: Install Composer dependencies (post-install-cmd also runs php-scoper + yarn install + yarn build)
if: ${{ steps.vendor-cache.outputs.cache-hit != 'true' || steps.nm-cache.outputs.cache-hit != 'true' || steps.build-cache.outputs.cache-hit != 'true' }}
run: composer install --no-progress --no-ansi --no-interaction
# Save only on success() — one composer install produces all three artifacts, so a partway failure
# could cache incomplete state.
- name: Save Composer vendor
if: ${{ steps.vendor-cache.outputs.cache-hit != 'true' }}
uses: actions/cache/save@v5
with:
path: |
vendor
vendor_prefixed
key: ${{ steps.vendor-cache.outputs.cache-primary-key }}
- name: Save node_modules
if: ${{ steps.nm-cache.outputs.cache-hit != 'true' }}
uses: actions/cache/save@v5
with:
path: node_modules
key: ${{ steps.nm-cache.outputs.cache-primary-key }}
- name: Save build assets
if: ${{ steps.build-cache.outputs.cache-hit != 'true' }}
uses: actions/cache/save@v5
with:
path: build/assets
key: ${{ steps.build-cache.outputs.cache-primary-key }}
test-js:
name: JavaScript Tests
needs: prebuild
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Setup Node JS
uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
- name: Log debug information
run: |
node --version
yarn --version
# Primed by prebuild — a miss here means prebuild itself broke, so fail loudly rather than silently re-installing.
- name: Restore node_modules
uses: actions/cache/restore@v5
with:
path: node_modules
key: nm-${{ runner.os }}-${{ hashFiles('yarn.lock', '.nvmrc') }}
fail-on-cache-miss: true
- name: Run Jest tests
run: yarn test:js:coverage
- name: Post coverage PR comment
if: ${{ github.event_name == 'pull_request' }}
uses: lucassabreu/comment-coverage-clover@v0.17.0
with:
file: ./tmp/jest-coverage/clover.xml
signature: ":robot: Jest coverage report"
test-php:
name: PHPUnit ${{ matrix.php }}${{ matrix.report && ' coverage' || '' }} on ${{ matrix.os }}
needs: prebuild
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# PRs run a tightened floor/ceiling matrix for fast feedback; cron runs the full matrix down to the
# composer.json floor. The run-tests-php-all label forces the full matrix on a PR — applied post-open,
# so the labeled event re-runs this workflow with a payload that carries the label.
php: ${{ fromJSON((github.event_name == 'pull_request' && ! contains(github.event.pull_request.labels.*.name, 'run-tests-php-all')) && '["7.4","8.5"]' || '["7.4","8.0","8.1","8.2","8.3","8.4","8.5"]') }}
os: [ ubuntu-latest ]
include:
# These flags merge into the matching base cells (no extra cells spawned) and drive the
# conditional steps below: coverage runs once on 8.3, multisite on the floor + ceiling.
- php: '8.3'
os: ubuntu-latest
report: true
- php: '7.4'
os: ubuntu-latest
multisite: true
- php: '8.5'
os: ubuntu-latest
multisite: true
env:
WP_ENV_PHP_VERSION: ${{ matrix.php }}
steps:
- name: Configure environment variables
run: |
echo "PHP_FPM_UID=$(id -u)" >> $GITHUB_ENV
echo "PHP_FPM_GID=$(id -g)" >> $GITHUB_ENV
# Route Docker Hub pulls through Google's unauthenticated mirror — parallel matrix cells got silently
# rate-limited on docker.io (manifested as wp-env "Done in 13s" with no containers actually running).
- name: Use Google's Docker Hub mirror to avoid rate limits
run: |
echo '{"registry-mirrors": ["https://mirror.gcr.io"]}' | sudo tee /etc/docker/daemon.json
sudo systemctl restart docker
- name: Checkout repository
uses: actions/checkout@v6
# Locks in the static::load_fixtures() contract — the shared $GLOBALS['GFPDF_Test'] global
# and direct GFAPI form/entry creates have been removed; this gate stops them returning.
- name: Fail on banned fixture patterns
run: |
if grep -rnE "\\\$GLOBALS\\[['\\\"]GFPDF_Test['\\\"]\\]|GFAPI::add_(form|entry)\\b" tests/phpunit/integration/ --include="*.php"; then
echo "::error::Banned fixture pattern found in tests/phpunit/integration/. Use static::load_fixtures() instead."
exit 1
fi
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
- name: Setup Node JS
uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
- name: Log debug information
run: |
npm --version
yarn --version
node --version
curl --version
git --version
php --version
php -i
locale -a
# Primed by prebuild — a miss here means prebuild itself broke, so fail loudly rather than silently
# re-installing per matrix cell.
- name: Restore Composer vendor
uses: actions/cache/restore@v5
with:
path: |
vendor
vendor_prefixed
key: vendor-${{ runner.os }}-${{ hashFiles('composer.lock', 'tools/php-scoper/**') }}
fail-on-cache-miss: true
- name: Restore node_modules
uses: actions/cache/restore@v5
with:
path: node_modules
key: nm-${{ runner.os }}-${{ hashFiles('yarn.lock', '.nvmrc') }}
fail-on-cache-miss: true
# No restore-keys: the work-dir embeds the downloaded WordPress core, so restoring it across a
# core-version bump (the key hashes the config) leaves wp-env with a stale WP that silently fails
# to start. A clean miss re-downloads the pinned version instead.
- name: Cache wp-env work directory
uses: actions/cache@v5
with:
path: |
~/wp-env
~/.wp-env
key: wp-env-integration-v2-${{ runner.os }}-php${{ matrix.php }}-${{ hashFiles('tools/wp-env/integration.json', 'composer.lock') }}
# Pre-fetch the pinned WordPress core so wp-env's start has nothing to download. Its in-start core
# fetch silently aborts provisioning on the CI runners (only the DB container comes up); pointing
# WP_ENV_CORE at a local directory sidesteps that. URL is derived from the config's pin to stay single-source.
- name: Pre-download WordPress core
run: |
url=$(node tools/wp-env/wp-version.mjs download-url tools/wp-env/integration.json)
curl -fsSL "$url" -o "$RUNNER_TEMP/wp-core.zip"
unzip -q "$RUNNER_TEMP/wp-core.zip" -d "$RUNNER_TEMP/wp-core"
echo "WP_ENV_CORE=$RUNNER_TEMP/wp-core/wordpress" >> "$GITHUB_ENV"
- name: Install / Setup Gravity PDF + WordPress
if: ${{ ! matrix.report }}
run: yarn wp-env:integration start
- name: Install / Setup Gravity PDF + WordPress
if: ${{ matrix.report }}
run: yarn wp-env:integration start --xdebug=coverage
# retry.sh re-runs failed tests once (--filter built from the JUnit XML) so a single transient flake
# doesn't burn a matrix rerun; retries log as ::warning:: so flakes stay visible.
- name: Run PHPUnit tests
if: ${{ ! matrix.report }}
run: |
tools/phpunit/retry.sh test:php \
/var/www/html/wp-content/plugins/gravity-pdf/tmp/junit/phpunit-integration-php${{ matrix.php }}.xml \
--do-not-cache-result --verbose
# Multisite-tagged cells (floor + ceiling) reuse their already-running single-site wp-env rather than
# spinning a dedicated cell. The 8.3 coverage cell runs multisite separately, for the merged report.
- name: Run Multisite PHPUnit tests
if: ${{ matrix.multisite }}
run: |
tools/phpunit/retry.sh test:php:multisite \
/var/www/html/wp-content/plugins/gravity-pdf/tmp/junit/phpunit-multisite-php${{ matrix.php }}.xml \
--verbose
- name: Generate Code Coverage Report for PHP (single-site)
if: ${{ matrix.report }}
run: |
tools/phpunit/retry.sh test:php \
/var/www/html/wp-content/plugins/gravity-pdf/tmp/junit/phpunit-coverage-php${{ matrix.php }}.xml \
--do-not-cache-result --verbose \
--coverage-clover=/var/www/html/wp-content/plugins/gravity-pdf/tmp/coverage/report-xml/php-coverage1.xml
- name: Generate Code Coverage Report for PHP (multisite)
if: ${{ matrix.report }}
run: |
tools/phpunit/retry.sh test:php:multisite \
/var/www/html/wp-content/plugins/gravity-pdf/tmp/junit/phpunit-coverage-multisite-php${{ matrix.php }}.xml \
--do-not-cache-result --verbose \
--coverage-clover=/var/www/html/wp-content/plugins/gravity-pdf/tmp/coverage/report-xml/php-coverage-multisite.xml
- name: Upload PHPUnit JUnit timings
uses: actions/upload-artifact@v6
if: always()
with:
name: phpunit-junit-php${{ matrix.php }}${{ matrix.report && '-coverage' || '' }}
path: tmp/junit/*.xml
- name: Merge single-site + multisite Clover
if: ${{ matrix.report && github.event_name == 'pull_request' }}
run: |
php tools/phpunit/coverage-merge.php \
tmp/coverage/report-xml/merged.xml \
tmp/coverage/report-xml/php-coverage1.xml \
tmp/coverage/report-xml/php-coverage-multisite.xml
# Custom signature so this comment doesn't collide with test-js' coverage comment — the action keys
# de-duplication off the signature string, so identical defaults would overwrite each other.
- name: Post coverage PR comment
if: ${{ matrix.report && github.event_name == 'pull_request' }}
uses: lucassabreu/comment-coverage-clover@v0.17.0
with:
file: tmp/coverage/report-xml/merged.xml
signature: ":robot: PHPUnit coverage report"
e2e-playwright:
name: Playwright E2E Tests (shard ${{ matrix.shard }}/${{ strategy.job-total }})
needs: prebuild
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shard: [ 1, 2, 3, 4 ]
steps:
- name: Configure environment variables
run: |
echo "PHP_FPM_UID=$(id -u)" >> $GITHUB_ENV
echo "PHP_FPM_GID=$(id -g)" >> $GITHUB_ENV
# Route Docker Hub pulls through Google's unauthenticated mirror — the 4 parallel shards got silently
# rate-limited on docker.io (manifested as wp-env "Done in 13s" with no containers actually running).
- name: Use Google's Docker Hub mirror to avoid rate limits
run: |
echo '{"registry-mirrors": ["https://mirror.gcr.io"]}' | sudo tee /etc/docker/daemon.json
sudo systemctl restart docker
- name: Checkout repository
uses: actions/checkout@v6
env:
CHROMATIC_BRANCH: ${{ github.event.pull_request.head.ref || github.ref_name }}
CHROMATIC_SHA: ${{ github.event.pull_request.head.sha || github.ref }}
CHROMATIC_SLUG: ${{ github.repository }}
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 7.4
- name: Setup Node JS
uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
- name: Log debug information
run: |
npm --version
yarn --version
node --version
curl --version
git --version
php --version
php -i
locale -a
# Primed by prebuild — a miss here means prebuild itself broke, so fail loudly rather than silently
# re-installing per shard.
- name: Restore Composer vendor
uses: actions/cache/restore@v5
with:
path: |
vendor
vendor_prefixed
key: vendor-${{ runner.os }}-${{ hashFiles('composer.lock', 'tools/php-scoper/**') }}
fail-on-cache-miss: true
- name: Restore node_modules
uses: actions/cache/restore@v5
with:
path: node_modules
key: nm-${{ runner.os }}-${{ hashFiles('yarn.lock', '.nvmrc') }}
fail-on-cache-miss: true
- name: Restore build assets
uses: actions/cache/restore@v5
with:
path: build/assets
key: build-${{ runner.os }}-${{ hashFiles('src/assets/**', 'yarn.lock', '.nvmrc', 'package.json', 'babel.config.js', '.browserslistrc') }}
fail-on-cache-miss: true
- name: Cache Playwright browsers
id: playwright-cache
uses: actions/cache@v5
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
restore-keys: |
playwright-${{ runner.os }}-
- name: Install playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: npx playwright install --with-deps chromium
- name: Install playwright system deps (cache hit)
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: npx playwright install-deps chromium
# No restore-keys: the work-dir embeds the downloaded WordPress core, so restoring it across a
# core-version bump (the key hashes the config) leaves wp-env with a stale WP that silently fails
# to start. A clean miss re-downloads the pinned version instead.
- name: Cache wp-env work directory
uses: actions/cache@v5
with:
path: |
~/wp-env
~/.wp-env
key: wp-env-e2e-v2-${{ runner.os }}-${{ hashFiles('tools/wp-env/e2e.json', 'composer.lock') }}
# See the integration job: pre-fetch core so wp-env's start has nothing to download.
- name: Pre-download WordPress core
run: |
url=$(node tools/wp-env/wp-version.mjs download-url tools/wp-env/e2e.json)
curl -fsSL "$url" -o "$RUNNER_TEMP/wp-core.zip"
unzip -q "$RUNNER_TEMP/wp-core.zip" -d "$RUNNER_TEMP/wp-core"
echo "WP_ENV_CORE=$RUNNER_TEMP/wp-core/wordpress" >> "$GITHUB_ENV"
- name: Install / Setup Gravity PDF + WordPress
run: yarn wp-env:e2e start
# wp-env's work-dir is cached but its MySQL volume isn't, so a restored work-dir can pair with a fresh empty DB.
# A bare `wp core install` leaves the env half-configured (GF REST never enables), so run wp-env's full reset.
- name: Ensure WordPress is installed (wp-env cache fallback)
run: |
if yarn wp-env:e2e run cli wp core is-installed >/dev/null 2>&1; then
echo "WordPress already installed."
else
echo "wp-env work-dir cache hit a fresh DB volume — running wp-env reset for a full install."
yarn wp-env:e2e reset
fi
- name: Run the tests
run: yarn test:e2e -- --shard=${{ matrix.shard }}/${{ strategy.job-total }}
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: true
# '0' no-ops @chromatic-com/playwright's takeSnapshot — saves ~20–40% wall-clock when Chromatic is off.
CHROMATIC: ${{ needs.prebuild.outputs.chromatic-enabled == 'true' && '1' || '0' }}
- uses: actions/upload-artifact@v6
if: success() && needs.prebuild.outputs.chromatic-enabled == 'true'
with:
name: test-results-shard-${{ matrix.shard }}
path: ./tmp/artifacts/test-results
- name: Dump log files on failure
if: failure()
run: yarn wp-env:e2e run wordpress "cp" "-r" "/var/www/html/wp-content/uploads/gravity_forms/logs/" "/var/www/html/wp-content/plugins/gravity-pdf/tmp/artifacts/logs"
- name: Upload artifacts on failure
uses: actions/upload-artifact@v6
if: failure()
with:
name: failure-artifacts-shard-${{ matrix.shard }}
path: tmp/artifacts
notify:
name: Notify on weekly run
needs: [ test-js, test-php, e2e-playwright ]
if: ${{ always() && github.event_name != 'pull_request' }}
runs-on: ubuntu-latest
env:
HEADLINE: ${{ (needs.test-js.result == 'success' && needs.test-php.result == 'success' && needs.e2e-playwright.result == 'success') && 'Gravity PDF Tests Completed' || 'Gravity PDF Tests Failed' }}
steps:
- name: Post Slack notification for weekly run
uses: slackapi/slack-github-action@v3
with:
webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
webhook-type: incoming-webhook
errors: true
payload: |
text: "${{ env.HEADLINE }}"
blocks:
- type: section
text:
type: mrkdwn
text: |
*${{ env.HEADLINE }}*
JavaScript: ${{ needs.test-js.result }}
PHPUnit: ${{ needs.test-php.result }}
E2E (Playwright): ${{ needs.e2e-playwright.result }}
<https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|View run>
chromatic:
name: Run Chromatic
needs: [ prebuild, e2e-playwright ]
if: needs.prebuild.outputs.chromatic-enabled == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- name: Restore node_modules
id: nm-cache
uses: actions/cache/restore@v5
with:
path: node_modules
key: nm-${{ runner.os }}-${{ hashFiles('yarn.lock', '.nvmrc') }}
- name: Install JS Dependencies
if: steps.nm-cache.outputs.cache-hit != 'true'
run: yarn install --frozen-lockfile
# Every shard writes the same chromatic-archives/** filenames, so `merge-multiple: true` races parallel writes
# and Chromatic fails with "Unexpected non-whitespace character after JSON…". Per-shard subdirs + serial merge.
- name: Download Playwright test results from all shards
uses: actions/download-artifact@v8
with:
pattern: test-results-shard-*
path: ./shard-artifacts
- name: Merge shard artifacts serially
run: |
mkdir -p ./test-results
for shard_dir in ./shard-artifacts/test-results-shard-*/; do
cp -R "${shard_dir}." ./test-results/
done
- name: Run Chromatic
uses: chromaui/action@latest
with:
playwright: true
autoAcceptChanges: "development"
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}