From d30393b6099e6f9824b6ade8296922d04bfa5508 Mon Sep 17 00:00:00 2001 From: Jeppe Bundgaard Date: Tue, 21 Apr 2026 22:00:03 +0200 Subject: [PATCH] Run PHP suites in php1 on CI --- .github/workflows/tests.yml | 193 ++++++++++-------------------------- scripts/ci/run-php-suite.sh | 163 ++++++++++++++++++++++++++++++ services/php/Dockerfile | 4 +- 3 files changed, 219 insertions(+), 141 deletions(-) create mode 100755 scripts/ci/run-php-suite.sh diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cf8f5361..71286101 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -9,7 +9,6 @@ jobs: name: Unit (required) # Match the labels exposed by the Coolify-managed GitHub runner. runs-on: [self-hosted, Linux, X64, default] - container: shivammathur/node:php-8.2-24.04-amd64 steps: - name: Checkout @@ -23,27 +22,26 @@ jobs: - name: Check AI workflow sync run: node scripts/sync-ai-workflow.mjs --check - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: '8.2' - extensions: mysqli, curl, openssl, json, redis, xdebug - coverage: xdebug - ini-values: variables_order=EGPCS,xdebug.mode=coverage + - name: Materialize compose env files env: - runner: self-hosted + COMPOSE_ENV: ${{ secrets.COMPOSE_ENV }} + COMPOSE_ENV_STAGING: ${{ secrets.COMPOSE_ENV_STAGING }} + run: | + set -euo pipefail + if [ -z "${COMPOSE_ENV}" ]; then + echo "Required GitHub secret COMPOSE_ENV is not configured." >&2 + exit 1 + fi + if [ -z "${COMPOSE_ENV_STAGING}" ]; then + echo "Required GitHub secret COMPOSE_ENV_STAGING is not configured." >&2 + exit 1 + fi + printf '%s\n' "$COMPOSE_ENV" > .env + printf '%s\n' "$COMPOSE_ENV_STAGING" > .env.staging + chmod +x scripts/ci/run-php-suite.sh - - name: Resolve dependencies - working-directory: services/nginx/app - run: composer update --no-interaction --prefer-dist - - - name: Run unit tests - working-directory: services/nginx/app - run: composer test:unit - - - name: Generate coverage report - working-directory: services/nginx/app - run: composer test:coverage + - name: Run unit suite in php1 + run: scripts/ci/run-php-suite.sh unit - name: Upload coverage artifact if: ${{ github.event_name == 'pull_request' }} @@ -126,142 +124,59 @@ jobs: integration: name: Integration (advisory) runs-on: [self-hosted, Linux, X64, default] - container: shivammathur/node:php-8.2-24.04-amd64 continue-on-error: true - services: - redis: - image: redis:7 - ports: - - 6379:6379 - mysql: - image: mysql:8 - env: - MYSQL_DATABASE: app_test - MYSQL_ROOT_PASSWORD: root - ports: - - 3306:3306 - options: >- - --health-cmd="mysqladmin ping -h 127.0.0.1 -proot" - --health-interval=10s - --health-timeout=5s - --health-retries=10 - steps: - name: Checkout uses: actions/checkout@v4 - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: '8.2' - extensions: mysqli, curl, openssl, json, redis - ini-values: variables_order=EGPCS + - name: Materialize compose env files env: - runner: self-hosted + COMPOSE_ENV: ${{ secrets.COMPOSE_ENV }} + COMPOSE_ENV_STAGING: ${{ secrets.COMPOSE_ENV_STAGING }} + run: | + set -euo pipefail + if [ -z "${COMPOSE_ENV}" ]; then + echo "Required GitHub secret COMPOSE_ENV is not configured." >&2 + exit 1 + fi + if [ -z "${COMPOSE_ENV_STAGING}" ]; then + echo "Required GitHub secret COMPOSE_ENV_STAGING is not configured." >&2 + exit 1 + fi + printf '%s\n' "$COMPOSE_ENV" > .env + printf '%s\n' "$COMPOSE_ENV_STAGING" > .env.staging + chmod +x scripts/ci/run-php-suite.sh - - name: Resolve dependencies - working-directory: services/nginx/app - run: composer update --no-interaction --prefer-dist - - - name: Run integration tests - working-directory: services/nginx/app - env: - RUN_INTEGRATION_TESTS: '1' - USE_ENV: 'true' - DEBUG: '0' - ENCRYPTION_KEY: test-key - CORS: '*' - CONFIG_TIMEZONE: Europe/Copenhagen - ECONOMIC_API_APP_ACCESS_GRANT: test - ECONOMIC_API_APP_ACCESS_GRANT2: test - ECONOMIC_API_APP_SECRET_TOKEN: test - WORDPRESS_STATIC_TOKEN: '' - EMAIL_WASH_CERTIFICATE_TOKEN: '' - WORDPRESS_API_URL: http://localhost - MINIO_ENDPOINT: '' - MINIO_ACCESS_KEY: '' - MINIO_SECRET_KEY: '' - SLACK_DEFAULT_WEBHOOK: '' - REDIS_CONFIG_HOST: 127.0.0.1 - REDIS_CONFIG_DATABASE: '0' - REDIS_CONFIG_PASSWORD: '' - REDIS_CONFIG_PORT: '6379' - CONFIG_DB_HOST: 127.0.0.1 - CONFIG_DB_USER: root - CONFIG_DB_PASSWORD: root - CONFIG_DB_DATABASE: app_test - CONFIG_DB_PORT: '3306' - run: composer test:integration + - name: Run integration suite in php1 + run: scripts/ci/run-php-suite.sh integration api: name: API (advisory) runs-on: [self-hosted, Linux, X64, default] - container: shivammathur/node:php-8.2-24.04-amd64 continue-on-error: true - services: - redis: - image: redis:7 - ports: - - 6379:6379 - mysql: - image: mysql:8 - env: - MYSQL_DATABASE: app_test - MYSQL_ROOT_PASSWORD: root - ports: - - 3306:3306 - options: >- - --health-cmd="mysqladmin ping -h 127.0.0.1 -proot" - --health-interval=10s - --health-timeout=5s - --health-retries=10 - steps: - name: Checkout uses: actions/checkout@v4 - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: '8.2' - extensions: mysqli, curl, openssl, json, redis - ini-values: variables_order=EGPCS + - name: Materialize compose env files env: - runner: self-hosted + COMPOSE_ENV: ${{ secrets.COMPOSE_ENV }} + COMPOSE_ENV_STAGING: ${{ secrets.COMPOSE_ENV_STAGING }} + run: | + set -euo pipefail + if [ -z "${COMPOSE_ENV}" ]; then + echo "Required GitHub secret COMPOSE_ENV is not configured." >&2 + exit 1 + fi + if [ -z "${COMPOSE_ENV_STAGING}" ]; then + echo "Required GitHub secret COMPOSE_ENV_STAGING is not configured." >&2 + exit 1 + fi + printf '%s\n' "$COMPOSE_ENV" > .env + printf '%s\n' "$COMPOSE_ENV_STAGING" > .env.staging + chmod +x scripts/ci/run-php-suite.sh - - name: Resolve dependencies - working-directory: services/nginx/app - run: composer update --no-interaction --prefer-dist - - - name: Run API tests - working-directory: services/nginx/app - env: - RUN_API_TESTS: '1' - API_TEST_BOOTSTRAP_SCHEMA: '1' - USE_ENV: 'true' - DEBUG: '0' - ENCRYPTION_KEY: test-key - CORS: '*' - CONFIG_TIMEZONE: Europe/Copenhagen - ECONOMIC_API_APP_ACCESS_GRANT: test - ECONOMIC_API_APP_ACCESS_GRANT2: test - ECONOMIC_API_APP_SECRET_TOKEN: test - WORDPRESS_STATIC_TOKEN: '' - EMAIL_WASH_CERTIFICATE_TOKEN: '' - WORDPRESS_API_URL: http://localhost - MINIO_ENDPOINT: '' - MINIO_ACCESS_KEY: '' - MINIO_SECRET_KEY: '' - SLACK_DEFAULT_WEBHOOK: '' - REDIS_CONFIG_HOST: 127.0.0.1 - REDIS_CONFIG_DATABASE: '0' - REDIS_CONFIG_PASSWORD: '' - REDIS_CONFIG_PORT: '6379' - CONFIG_DB_HOST: 127.0.0.1 - CONFIG_DB_USER: root - CONFIG_DB_PASSWORD: root - CONFIG_DB_DATABASE: app_test - CONFIG_DB_PORT: '3306' - run: composer test:api + - name: Run API suite in php1 + run: scripts/ci/run-php-suite.sh api diff --git a/scripts/ci/run-php-suite.sh b/scripts/ci/run-php-suite.sh new file mode 100755 index 00000000..2015f790 --- /dev/null +++ b/scripts/ci/run-php-suite.sh @@ -0,0 +1,163 @@ +#!/usr/bin/env bash +set -euo pipefail + +suite="${1:-}" + +if [[ -z "$suite" ]]; then + echo "Usage: $0 " >&2 + exit 1 +fi + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +cd "$repo_root" + +if [[ -f .env ]]; then + set -a + # shellcheck disable=SC1091 + . ./.env + set +a +fi + +cleanup() { + docker compose down -v --remove-orphans || true +} + +wait_for_container_running() { + local name="$1" + local status="" + + for _ in $(seq 1 90); do + status="$(docker inspect -f '{{.State.Status}}' "$name" 2>/dev/null || true)" + if [[ "$status" == "running" ]]; then + return 0 + fi + sleep 1 + done + + docker logs "$name" || true + echo "Container $name did not reach running state." >&2 + exit 1 +} + +wait_for_container_healthy() { + local name="$1" + local status="" + + for _ in $(seq 1 90); do + status="$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$name" 2>/dev/null || true)" + if [[ "$status" == "healthy" || "$status" == "running" ]]; then + return 0 + fi + sleep 2 + done + + docker logs "$name" || true + echo "Container $name did not reach a healthy state." >&2 + exit 1 +} + +docker_exec_php1() { + docker exec "$@" php1 sh -lc "cd /var/www/html && ${PHP_COMMAND}" +} + +run_php_command() { + local -a env_args=() + while [[ $# -gt 0 ]]; do + env_args+=(-e "$1") + shift + done + + docker exec "${env_args[@]}" php1 sh -lc "cd /var/www/html && ${PHP_COMMAND}" +} + +docker compose down -v --remove-orphans || true +trap cleanup EXIT + +services=(redis edge-broker php1) +if [[ "$suite" != "unit" ]]; then + services+=(mysql-debug) +fi + +docker compose up -d --build "${services[@]}" +wait_for_container_running php1 +wait_for_container_healthy redis +if [[ "$suite" != "unit" ]]; then + wait_for_container_healthy mysql-debug +fi + +PHP_COMMAND="composer install --no-interaction --prefer-dist" +docker_exec_php1 + +case "$suite" in + unit) + PHP_COMMAND="composer test:unit" + docker_exec_php1 + PHP_COMMAND="composer test:coverage" + docker_exec_php1 + ;; + integration) + PHP_COMMAND="composer test:integration" + run_php_command \ + "RUN_INTEGRATION_TESTS=1" \ + "USE_ENV=true" \ + "DEBUG=0" \ + "ENCRYPTION_KEY=test-key" \ + "CORS=*" \ + "CONFIG_TIMEZONE=Europe/Copenhagen" \ + "ECONOMIC_API_APP_ACCESS_GRANT=test" \ + "ECONOMIC_API_APP_ACCESS_GRANT2=test" \ + "ECONOMIC_API_APP_SECRET_TOKEN=test" \ + "WORDPRESS_STATIC_TOKEN=" \ + "EMAIL_WASH_CERTIFICATE_TOKEN=" \ + "WORDPRESS_API_URL=http://localhost" \ + "MINIO_ENDPOINT=" \ + "MINIO_ACCESS_KEY=" \ + "MINIO_SECRET_KEY=" \ + "SLACK_DEFAULT_WEBHOOK=" \ + "REDIS_CONFIG_HOST=redis" \ + "REDIS_CONFIG_DATABASE=0" \ + "REDIS_CONFIG_PASSWORD=" \ + "REDIS_CONFIG_PORT=6379" \ + "CONFIG_DB_TARGET=debug" \ + "CONFIG_DB_DEBUG_HOST=mysql-debug" \ + "CONFIG_DB_DEBUG_USER=root" \ + "CONFIG_DB_DEBUG_PASSWORD=${CONFIG_DB_DEBUG_PASSWORD:-debug_root_password}" \ + "CONFIG_DB_DEBUG_DATABASE=${CONFIG_DB_DEBUG_DATABASE:-nnks_db_debug}" \ + "CONFIG_DB_DEBUG_PORT=3306" + ;; + api) + PHP_COMMAND="composer test:api" + run_php_command \ + "RUN_API_TESTS=1" \ + "API_TEST_BOOTSTRAP_SCHEMA=1" \ + "USE_ENV=true" \ + "DEBUG=0" \ + "ENCRYPTION_KEY=test-key" \ + "CORS=*" \ + "CONFIG_TIMEZONE=Europe/Copenhagen" \ + "ECONOMIC_API_APP_ACCESS_GRANT=test" \ + "ECONOMIC_API_APP_ACCESS_GRANT2=test" \ + "ECONOMIC_API_APP_SECRET_TOKEN=test" \ + "WORDPRESS_STATIC_TOKEN=" \ + "EMAIL_WASH_CERTIFICATE_TOKEN=" \ + "WORDPRESS_API_URL=http://localhost" \ + "MINIO_ENDPOINT=" \ + "MINIO_ACCESS_KEY=" \ + "MINIO_SECRET_KEY=" \ + "SLACK_DEFAULT_WEBHOOK=" \ + "REDIS_CONFIG_HOST=redis" \ + "REDIS_CONFIG_DATABASE=0" \ + "REDIS_CONFIG_PASSWORD=" \ + "REDIS_CONFIG_PORT=6379" \ + "CONFIG_DB_TARGET=debug" \ + "CONFIG_DB_DEBUG_HOST=mysql-debug" \ + "CONFIG_DB_DEBUG_USER=root" \ + "CONFIG_DB_DEBUG_PASSWORD=${CONFIG_DB_DEBUG_PASSWORD:-debug_root_password}" \ + "CONFIG_DB_DEBUG_DATABASE=${CONFIG_DB_DEBUG_DATABASE:-nnks_db_debug}" \ + "CONFIG_DB_DEBUG_PORT=3306" + ;; + *) + echo "Unsupported suite: $suite" >&2 + exit 1 + ;; +esac diff --git a/services/php/Dockerfile b/services/php/Dockerfile index 2ad44be7..9d02d90c 100644 --- a/services/php/Dockerfile +++ b/services/php/Dockerfile @@ -43,8 +43,8 @@ RUN set -eux; \ pdo_mysql \ mysqli \ zip; \ - pecl install imagick-3.7.0; \ - docker-php-ext-enable imagick; \ + pecl install imagick-3.7.0 redis xdebug; \ + docker-php-ext-enable imagick redis xdebug; \ apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $PHPIZE_DEPS; \ rm -rf /var/lib/apt/lists/*