diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6b65125..2a29dd7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,6 +60,17 @@ jobs: name: wordpress-plugin path: dist/htmltrust-wordpress-plugin.zip + wordpress-tests: + name: WordPress PHPUnit + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + with: + persist-credentials: false + + - name: Run WordPress test suite + run: ./wordpress/bin/test-docker.sh + hugo: name: Hugo Integration runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 24caed1..3767c7e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,8 @@ Thumbs.db # WordPress / PHP vendor/ +!wordpress/vendor/ +!wordpress/vendor/.gitkeep *.log # Archives diff --git a/README.md b/README.md index 2695524..74095ea 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,16 @@ The WordPress plugin and Hugo build integration are runnable. Drupal, Joomla, an ## WordPress prerequisites - WordPress 5.0+ -- PHP 7.2+ +- PHP 7.2+ at runtime - PHP Intl extension - Composer - A running [HTMLTrust trust directory server](https://github.com/HTMLTrust/htmltrust-server-reference) +The plugin's Composer runtime constraint is PHP `>=7.2`. Development and test +dependencies are newer: the lock file currently resolves PHPUnit 9.6.34, which +requires PHP `>=7.3`. The Docker test image uses PHP 8.3 as the supported test +baseline. + ## Quick start ### WordPress @@ -96,6 +101,38 @@ Then either: ### Running Tests +The reproducible test path needs Docker and Docker Compose v2. From the +repository root, run: + +```sh +./wordpress/bin/test-docker.sh +``` + +This builds a PHP 8.3 test image, starts MariaDB 11.8.2, waits for its health +check, installs the exact Composer lock file, downloads the WordPress 6.9.4 +core and test suite into Docker-managed volumes, then runs PHPUnit. +The image and database tags are pinned by digest. Generated WordPress assets +and Composer dependencies stay in Docker volumes, so the command does not +write build artifacts to `/tmp` or require a host PHP installation. + +Run the coding-standard check separately, or remove the cached test assets: + +```sh +./wordpress/bin/test-docker.sh --lint +./wordpress/bin/test-docker.sh --clean +``` + +The lock file resolves `htmltrust/canonicalization` v0.2.2. That is the +currently supported compatibility release for this plugin and is the version +covered by the Docker test path. + +The current checkout contains existing WordPress Coding Standards violations, +so `--lint` reports a nonzero result after PHPUnit completes. Keeping that check +explicit makes the default test command a reliable pass/fail signal for the +55-test suite. + +### Manual test setup + ```sh cd wordpress/ export TEST_TMP_DIR="${HOME}/tmp/htmltrust-cms-tests" diff --git a/wordpress/bin/run-docker-tests.sh b/wordpress/bin/run-docker-tests.sh new file mode 100755 index 0000000..7a4564f --- /dev/null +++ b/wordpress/bin/run-docker-tests.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +set -euo pipefail + +: "${DB_NAME:=wordpress_test}" +: "${DB_USER:=wordpress}" +: "${DB_PASS:=wordpress}" +: "${DB_HOST:=db}" +: "${WP_VERSION:=6.9.4}" +: "${WP_TESTS_DIR:=/var/lib/wordpress-test-assets/tests}" +: "${WP_CORE_DIR:=/var/lib/wordpress-test-assets/wordpress}" +: "${RUN_PHPCS:=0}" + +export TMPDIR="${TMPDIR:-/var/lib/wordpress-test-assets/tmp}" +export WP_TESTS_DIR WP_CORE_DIR +# A Git worktree stores .git as a pointer to the primary checkout, which is +# outside this container mount. Supplying the root version keeps Composer from +# following that host-only pointer while resolving the local root package. +export COMPOSER_ROOT_VERSION="${COMPOSER_ROOT_VERSION:-dev-main}" + +mkdir -p "$TMPDIR" + +# The repository is mounted read-only and may belong to a different host UID. +# Composer asks Git to trust the mounted checkout before inspecting its root. +( + cd / + git config --global --add safe.directory /workspace + git config --global --add safe.directory /workspace/wordpress +) + +echo "Installing Composer dependencies from composer.lock..." +composer install --no-interaction --prefer-dist --no-progress + +echo "Installing WordPress ${WP_VERSION} test assets..." +bin/install-wp-tests.sh \ + "$DB_NAME" \ + "$DB_USER" \ + "$DB_PASS" \ + "$DB_HOST" \ + "$WP_VERSION" \ + true + +echo "Running PHPUnit..." +vendor/bin/phpunit --do-not-cache-result + +if [[ "$RUN_PHPCS" == "1" ]]; then + echo "Running PHPCS..." + vendor/bin/phpcs --standard=WordPress --report=summary content-signing.php includes admin public +fi diff --git a/wordpress/bin/test-docker.sh b/wordpress/bin/test-docker.sh new file mode 100755 index 0000000..eac85e4 --- /dev/null +++ b/wordpress/bin/test-docker.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +set -euo pipefail + +repo_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd) +compose_file="$repo_root/wordpress/docker-compose.test.yml" +checkout_id=$(printf '%s' "$repo_root" | cksum | awk '{print $1}') +compose_project=${HTMLTRUST_CMS_TEST_PROJECT:-htmltrust-cms-test-$checkout_id} +run_phpcs=0 + +if ! command -v docker >/dev/null 2>&1; then + echo "Docker is required. Install Docker Desktop or Docker Engine first." >&2 + exit 1 +fi + +if ! docker compose version >/dev/null 2>&1; then + echo "Docker Compose v2 is required (run: docker compose version)." >&2 + exit 1 +fi + +case "${1:-}" in + "") ;; + --lint) run_phpcs=1 ;; + --clean) + docker compose -p "$compose_project" -f "$compose_file" down -v --remove-orphans + exit 0 + ;; + *) + echo "usage: $0 [--lint|--clean]" >&2 + exit 2 + ;; +esac + +cleanup() { + docker compose -p "$compose_project" -f "$compose_file" down --remove-orphans >/dev/null +} +trap cleanup EXIT INT TERM + +RUN_PHPCS=$run_phpcs docker compose -p "$compose_project" -f "$compose_file" run --build --rm test diff --git a/wordpress/composer.json b/wordpress/composer.json index aff61c3..5d27b3e 100644 --- a/wordpress/composer.json +++ b/wordpress/composer.json @@ -28,8 +28,8 @@ }, "scripts": { "test": "phpunit", - "phpcs": "phpcs --standard=WordPress", - "phpcbf": "phpcbf --standard=WordPress" + "phpcs": "phpcs --standard=WordPress content-signing.php includes admin public", + "phpcbf": "phpcbf --standard=WordPress content-signing.php includes admin public" }, "config": { "allow-plugins": { diff --git a/wordpress/docker-compose.test.yml b/wordpress/docker-compose.test.yml new file mode 100644 index 0000000..e73fd85 --- /dev/null +++ b/wordpress/docker-compose.test.yml @@ -0,0 +1,40 @@ +services: + db: + image: mariadb:11.8.2@sha256:2bcbaec92bd9d4f6591bc8103d3a8e6d0512ee2235506e47a2e129d190444405 + environment: + MARIADB_DATABASE: wordpress_test + MARIADB_USER: wordpress + MARIADB_PASSWORD: wordpress + MARIADB_ROOT_PASSWORD: root + healthcheck: + test: ["CMD-SHELL", "mariadb-admin ping -h 127.0.0.1 -u root -proot --silent"] + interval: 2s + timeout: 5s + retries: 30 + + test: + build: + context: .. + dockerfile: wordpress/docker/test.Dockerfile + depends_on: + db: + condition: service_healthy + environment: + DB_NAME: wordpress_test + DB_USER: wordpress + DB_PASS: wordpress + DB_HOST: db + WP_VERSION: 6.9.4 + WP_TESTS_DIR: /var/lib/wordpress-test-assets/tests + WP_CORE_DIR: /var/lib/wordpress-test-assets/wordpress + RUN_PHPCS: "${RUN_PHPCS:-0}" + init: true + volumes: + - ..:/workspace:ro + - composer_vendor:/workspace/wordpress/vendor + - wordpress_test_assets:/var/lib/wordpress-test-assets + working_dir: /workspace/wordpress + +volumes: + composer_vendor: + wordpress_test_assets: diff --git a/wordpress/docker/test.Dockerfile b/wordpress/docker/test.Dockerfile new file mode 100644 index 0000000..289629a --- /dev/null +++ b/wordpress/docker/test.Dockerfile @@ -0,0 +1,26 @@ +# The digest pins the multi-platform index for PHP 8.3 on Debian Bookworm. +FROM php:8.3-cli-bookworm@sha256:177529735599a8244b2c903522f029839dce1c2ac4be122fdc00ada4b45a20e4 + +# Composer is copied from its pinned official image. The PHP extensions match +# the plugin's runtime and the tools used by install-wp-tests.sh. +COPY --from=composer:2.8.11@sha256:68e926a477000f12e8645e82a020b84904d49071c895c4951551fe80eed5d103 /usr/bin/composer /usr/local/bin/composer + +RUN apt-get update \ + && apt-get install --no-install-recommends --yes \ + ca-certificates \ + curl \ + git \ + libicu-dev \ + libonig-dev \ + mariadb-client \ + subversion \ + unzip \ + zip \ + && docker-php-ext-install intl mbstring mysqli \ + && rm -rf /var/lib/apt/lists/* + +COPY wordpress/bin/run-docker-tests.sh /usr/local/bin/run-docker-tests +RUN chmod 0755 /usr/local/bin/run-docker-tests + +WORKDIR /workspace/wordpress +ENTRYPOINT ["/usr/local/bin/run-docker-tests"] diff --git a/wordpress/vendor/.gitkeep b/wordpress/vendor/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/wordpress/vendor/.gitkeep @@ -0,0 +1 @@ +