Repository navigation
fix(backup): rotate the legacy directory backups too, and stop warning about a normal state #1228
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: E2E Test Suite | |
| on: | |
| pull_request: | |
| branches: [main] | |
| push: | |
| branches: [main] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| e2e: | |
| name: Full E2E suite (Playwright · Apache · MySQL) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| services: | |
| mysql: | |
| image: mysql:8.0@sha256:7dcddc01f13bab2f15cde676d44d01f61fc9f99fe7785e86196dfc07d358ae2b | |
| env: | |
| MYSQL_ROOT_PASSWORD: root | |
| MYSQL_DATABASE: pinakes_test | |
| ports: | |
| - 3306:3306 | |
| options: >- | |
| --health-cmd="mysqladmin ping -h 127.0.0.1" | |
| --health-interval=10s | |
| --health-timeout=5s | |
| --health-retries=10 | |
| env: | |
| E2E_BASE_URL: http://localhost:8081 | |
| E2E_ADMIN_EMAIL: admin@pinakes.test | |
| E2E_ADMIN_PASS: Test1234! | |
| E2E_DB_HOST: 127.0.0.1 | |
| E2E_DB_PORT: 3306 | |
| E2E_DB_USER: root | |
| E2E_DB_PASS: root | |
| E2E_DB_NAME: pinakes_test | |
| E2E_INSTALL_ROOT: ${{ github.workspace }} | |
| steps: | |
| - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 | |
| with: | |
| persist-credentials: false | |
| # ── Apache2 + mod_php ─────────────────────────────────────────────────── | |
| # Install Apache before setup-php adds external package sources; the app | |
| # supports PHP >= 8.1, so the Ubuntu mod_php package is sufficient here. | |
| - name: Install Apache2 + mod_php | |
| run: | | |
| # This job never installs Google Chrome. Remove its hosted-runner | |
| # apt source before the first refresh so mirror syncs cannot break CI. | |
| sudo rm -f /etc/apt/sources.list.d/google-chrome.list | |
| sudo apt-get update -q | |
| # php-apcu: the app's page cache must run on its production backend | |
| # (APCu shared memory) under Apache/mod_php, not the file fallback. | |
| sudo apt-get install -y apache2 libapache2-mod-php php-apcu | |
| sudo a2enmod rewrite headers env | |
| php_module="$(find /etc/apache2/mods-available -maxdepth 1 -name 'php*.load' -printf '%f\n' | sed 's/\.load$//' | sort -V | tail -n1)" | |
| if [ -n "${php_module}" ]; then | |
| sudo a2enmod "${php_module}" | |
| fi | |
| sudo a2dissite 000-default || true | |
| # Enable APCu for every distro-PHP SAPI (Apache mod_php + distro CLI). | |
| while IFS= read -r conf_dir; do | |
| sudo tee "${conf_dir}/99-pinakes-apcu.ini" >/dev/null <<'EOF' | |
| apc.enable=1 | |
| apc.enable_cli=1 | |
| EOF | |
| done < <(find /etc/php -type d -path '*/conf.d' | sort -u) | |
| # ── PHP 8.2 CLI for Composer and tooling ──────────────────────────────── | |
| - name: Setup PHP 8.2 | |
| uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # v2 | |
| with: | |
| php-version: '8.2' | |
| extensions: mysqli, mbstring, json, curl, openssl, zip, gd, intl, xml, apcu | |
| ini-values: apc.enable=1, apc.enable_cli=1 | |
| coverage: none | |
| - name: Configure virtual host on port 8081 | |
| env: | |
| WORKSPACE: ${{ github.workspace }} | |
| run: | | |
| sudo tee /etc/apache2/sites-available/pinakes.conf > /dev/null <<EOF | |
| Listen 8081 | |
| <VirtualHost *:8081> | |
| ServerName localhost | |
| DocumentRoot ${WORKSPACE}/public | |
| SetEnv PINAKES_E2E_BYPASS_RATE_LIMIT 1 | |
| # E2E only — deterministic, network-free bulk-enrich scraper stub. | |
| # Removes external-API latency/flakiness; never set in production. | |
| SetEnv PINAKES_E2E_SCRAPER_STUB 1 | |
| # E2E only — arms GET /_e2e/flush-cache so specs that write to the | |
| # DB directly can invalidate the page cache; 404s when unset. | |
| SetEnv PINAKES_E2E_CACHE_FLUSH 1 | |
| <Directory "${WORKSPACE}/public"> | |
| Options -Indexes +FollowSymLinks | |
| AllowOverride All | |
| Require all granted | |
| </Directory> | |
| ErrorLog \${APACHE_LOG_DIR}/pinakes-error.log | |
| CustomLog \${APACHE_LOG_DIR}/pinakes-access.log combined | |
| </VirtualHost> | |
| EOF | |
| sudo a2ensite pinakes | |
| sudo apachectl configtest | |
| # ── PHP dependencies ──────────────────────────────────────────────────── | |
| - name: Cache Composer packages | |
| uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 | |
| with: | |
| path: vendor | |
| key: composer-${{ hashFiles('composer.lock') }} | |
| restore-keys: composer- | |
| - name: Install Composer dependencies | |
| run: composer install --no-interaction --prefer-dist --no-dev --optimize-autoloader | |
| # ── Node / Playwright ──────────────────────────────────────────────────── | |
| - name: Setup Node 22 | |
| uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5 | |
| with: | |
| node-version: '22' | |
| cache: npm | |
| - name: Install Node dependencies | |
| run: npm ci --silent | |
| - name: Verify CI covers every Playwright spec | |
| run: npm run test:ci-policy | |
| - name: Install Playwright Chromium | |
| run: npx playwright install chromium --with-deps | |
| # ── Permissions: Apache (www-data) must write .env, .installed, storage ─ | |
| - name: Grant write permissions to workspace | |
| env: | |
| WORKSPACE: ${{ github.workspace }} | |
| run: | | |
| path="${WORKSPACE}" | |
| while [ "${path}" != "/" ]; do | |
| sudo chmod o+x "${path}" || true | |
| path="$(dirname "${path}")" | |
| done | |
| sudo chmod 777 "${WORKSPACE}" | |
| sudo chmod -R 777 "${WORKSPACE}/storage" | |
| sudo mkdir -p "${WORKSPACE}/public/uploads" | |
| sudo chmod -R 777 "${WORKSPACE}/public/uploads" | |
| # ── Start Apache ───────────────────────────────────────────────────────── | |
| - name: Start Apache and wait for installer | |
| run: | | |
| sudo systemctl start apache2 | |
| echo "Waiting for Apache on :8081..." | |
| for i in $(seq 1 30); do | |
| if curl -sf -o /dev/null "http://localhost:8081/installer/"; then | |
| echo "ok — Apache up (attempt $i)" | |
| exit 0 | |
| fi | |
| sleep 1 | |
| done | |
| echo "Apache did not respond in 30s" | |
| sudo journalctl -u apache2 --no-pager -n 30 >&2 | |
| sudo cat /var/log/apache2/pinakes-error.log >&2 || true | |
| exit 1 | |
| # ── Test suite ─────────────────────────────────────────────────────────── | |
| - name: "[1/13] full-test.spec.js — complete application lifecycle" | |
| run: | | |
| npx playwright test tests/full-test.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[2/13] schema-integrity.spec.js — post-install table verification" | |
| run: | | |
| npx playwright test tests/schema-integrity.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[3/13] plugin-integrity.spec.js — plugin registration regression" | |
| run: | | |
| npx playwright test tests/plugin-integrity.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[required] mobile-api.spec.js — discovery/auth + private-mode regression (#29)" | |
| run: | | |
| npx playwright test tests/mobile-api.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[4/13] mag-validation.spec.js — OAI-PMH MAG 2.0.1 metadata" | |
| run: | | |
| npx playwright test tests/mag-validation.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[5/13] archives-search.spec.js — ricerca archivi admin + pubblica" | |
| run: | | |
| npx playwright test tests/archives-search.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[6/13] ncip-server.spec.js — NCIP 2.0 endpoints v0.7.4" | |
| run: | | |
| npx playwright test tests/ncip-server.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[7/13] archives-phase5-admin-ui.spec.js — RiC-CM Phase 5 admin UI v0.7.12" | |
| run: | | |
| npx playwright test tests/archives-phase5-admin-ui.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[8/13] archives-phase6-oai-ric-o.spec.js — OAI-PMH metadataPrefix=ric-o v0.7.12" | |
| run: | | |
| npx playwright test tests/archives-phase6-oai-ric-o.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[9/13] archives-ric-jsonld.spec.js — RiC-O JSON-LD endpoints (Phase 1-4)" | |
| run: | | |
| npx playwright test tests/archives-ric-jsonld.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[10/13] archives-crud.spec.js — archival_units CRUD (#103)" | |
| run: | | |
| npx playwright test tests/archives-crud.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[11/13] archives-authorities.spec.js — authority_records CRUD" | |
| run: | | |
| npx playwright test tests/archives-authorities.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[12/13] archives-upload-assets.spec.js — cover/document upload pipeline" | |
| # The upload-assets spec picks 3 archival_units from the | |
| # `E2E_SEED_*` batch — it doesn't seed them itself. The seed | |
| # lives in archives-seed-50.spec.js (50 rows, all 4 levels, | |
| # full option matrix). On a fresh CI install no E2E_SEED_* row | |
| # exists yet, so the upload spec's beforeAll fails with | |
| # "no seeded row available for PDF test". Seed-then-upload | |
| # in the same step keeps the dependency local — no test-order | |
| # coupling with other steps, no separate seed step to renumber. | |
| run: | | |
| npx playwright test tests/archives-seed-50.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| npx playwright test tests/archives-upload-assets.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[13/13] archives-pr-extended.spec.js — extended CRUD + CSRF regression" | |
| # The pr-extended spec creates stub files directly via | |
| # fs.writeFileSync under public/uploads/archives/documents/ to | |
| # drive the IIIF rendering[] assertions. The previous step | |
| # ([12/13] upload-assets) ran real uploads through Apache, | |
| # which created subdirectories owned by www-data — the runner | |
| # process can no longer write into them, so the test EACCES'es | |
| # before the first assertion. Re-chmod the uploads tree right | |
| # before this step (idempotent, no-op when already 777). | |
| run: | | |
| sudo chmod -R 777 "${GITHUB_WORKSPACE}/public/uploads" || true | |
| npx playwright test tests/archives-pr-extended.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[required] issue-237-contributors.spec.js — pseudonym + contributor save contract" | |
| run: | | |
| npx playwright test tests/issue-237-contributors.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[required] issue-255-registration.spec.js — configurable registration fields" | |
| run: | | |
| npx playwright test tests/issue-255-registration.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[required] release-0.7.37-integration.spec.js — merged settings contract" | |
| run: | | |
| npx playwright test tests/release-0.7.37-integration.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| # The legacy facet scenarios assume a populated development catalog and | |
| # are not isolated from the state left by the preceding E2E steps. Run | |
| # the data-independent regression added by #317 as the required gate. | |
| - name: "[required] catalog-facets.spec.js — request ordering regression" | |
| run: | | |
| npx playwright test tests/catalog-facets.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --grep "A newer catalog request aborts and supersedes" \ | |
| --workers=1 | |
| - name: "[required] data-integrity-audit.spec.js — PR #323 roundtrip and consistency matrix" | |
| run: | | |
| npx playwright test tests/data-integrity-audit.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[required] mobile-api-behaviors.spec.js — availability state contract" | |
| run: | | |
| npx playwright test tests/mobile-api-behaviors.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| # Activate linked-data plugins before suites whose routes are registered | |
| # only for active plugins. A missing route is now a hard failure. | |
| - name: "Interop plugin preflight" | |
| run: | | |
| npx playwright test tests/interop-00-activate-plugins.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| # Formerly non-blocking backfill. These are release gates now: no test | |
| # failure is allowed to leave the workflow green. | |
| - name: "[regression/1] book-form-comprehensive.spec.js" | |
| run: | | |
| npx playwright test tests/book-form-comprehensive.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[regression/2] code-quality.spec.js" | |
| run: | | |
| npx playwright test tests/code-quality.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[regression/3] genre-merge-rearrange.spec.js" | |
| run: | | |
| npx playwright test tests/genre-merge-rearrange.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[regression/4] loan-reservation.spec.js" | |
| run: | | |
| npx playwright test tests/loan-reservation.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[regression/5] multisource-scraping.spec.js" | |
| run: | | |
| npx playwright test tests/multisource-scraping.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[regression/6] security-hardening.spec.js" | |
| run: | | |
| npx playwright test tests/security-hardening.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[regression/7] viaf-authority.spec.js" | |
| run: | | |
| npx playwright test tests/viaf-authority.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "[regression/8] interop-specific.spec.js" | |
| run: | | |
| npx playwright test tests/interop-specific.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| - name: "book-club-uwe.spec.js — meeting/member edit + external book proposals (#138)" | |
| run: | | |
| npx playwright test tests/book-club-uwe.spec.js \ | |
| --config=tests/playwright.config.js \ | |
| --workers=1 | |
| # ── Artifacts on failure ───────────────────────────────────────────────── | |
| - name: Upload Playwright report | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 | |
| if: failure() | |
| with: | |
| name: playwright-report-${{ github.run_id }} | |
| path: | | |
| playwright-report/ | |
| test-results/ | |
| retention-days: 14 | |
| - name: Upload Apache error log | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 | |
| if: failure() | |
| with: | |
| name: apache-error-log-${{ github.run_id }} | |
| path: /var/log/apache2/pinakes-error.log | |
| retention-days: 7 |