Repository navigation
feat(storage): show browser usage and safely clear resource caches #349
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: ci | |
| on: | |
| pull_request: | |
| branches: ["**"] | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ci-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| changes: | |
| name: change-scope | |
| runs-on: ubuntu-latest | |
| outputs: | |
| product: ${{ steps.scope.outputs.product }} | |
| steps: | |
| - name: Check out the merge commit and its base parent | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 2 | |
| - name: Classify whether product files changed | |
| id: scope | |
| run: python3 scripts/ci_scope.py HEAD^1 HEAD >> "$GITHUB_OUTPUT" | |
| contracts: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| steps: | |
| - name: Check out the repository | |
| uses: actions/checkout@v6 | |
| - name: Set up Go | |
| uses: actions/setup-go@v7 | |
| with: | |
| go-version-file: go.mod | |
| cache: true | |
| cache-dependency-path: go.sum | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: .node-version | |
| cache: npm | |
| cache-dependency-path: web/package-lock.json | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.13" | |
| - name: Enforce REPEATABLE READ isolation ceiling | |
| run: make database-isolation-check | |
| - name: Cache the repository Node.js toolchain | |
| uses: actions/cache@v5 | |
| with: | |
| path: .cache/tools/node-v24.22.1-linux-x64 | |
| key: retrom-node-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.node-version', 'scripts/prepare-node.sh') }} | |
| - name: Prepare native PostgreSQL build prerequisites | |
| run: sudo apt-get update && sudo apt-get install -y bison flex zlib1g-dev | |
| - name: Cache native PostgreSQL tools | |
| uses: actions/cache@v5 | |
| with: | |
| path: .cache/tools/postgresql-18.3 | |
| key: retrom-postgresql-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('scripts/prepare-postgres.sh') }} | |
| - name: Check workspace, structure, API and data contracts | |
| run: make ci-contracts | |
| - name: Check migrations against the latest published stable release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: make migration-check-released | |
| backend: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| env: | |
| RETROM_TEST_DATABASE_URL: postgres://retrom:retrom-test@127.0.0.1:5432/postgres?sslmode=disable | |
| services: | |
| postgres: | |
| image: postgres:18.3-bookworm@sha256:80630f83606d8db77d30b3851b16a9f78be2d0d4dda6f7b82a1fdca5ebe3acba | |
| env: | |
| POSTGRES_USER: retrom | |
| POSTGRES_PASSWORD: retrom-test | |
| POSTGRES_INITDB_ARGS: "-c max_connections=200" | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd "pg_isready -U retrom -d postgres" | |
| --health-interval 2s --health-timeout 3s --health-retries 30 | |
| steps: | |
| - name: Use runner disk for upload temporary storage | |
| run: | | |
| # Upload fixtures retain 10 GiB; avoid the size-limited /tmp tmpfs. | |
| echo "TMPDIR=$RUNNER_TEMP" >> "$GITHUB_ENV" | |
| df -h /tmp "$RUNNER_TEMP" | |
| - name: Check out the repository | |
| uses: actions/checkout@v6 | |
| - name: Set up Go | |
| uses: actions/setup-go@v7 | |
| with: | |
| go-version-file: go.mod | |
| cache: true | |
| cache-dependency-path: go.sum | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.13" | |
| - name: Cache materialized runtime dependencies | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| data/runtime | |
| data/dat/emulatorjs/*/fbneo | |
| data/dat/emulatorjs/*/mame2003 | |
| data/dat/emulatorjs/*/mame2003_plus | |
| data/dat/emulatorjs/*/fbalpha2012_cps1 | |
| data/dat/emulatorjs/*/fbalpha2012_cps2 | |
| data/auth/password-blocklists/*/payload | |
| key: retrom-dependencies-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('data/dat/**', 'data/auth/**', 'scripts/dependencies.py', 'scripts/fbalpha2012_dat.py', 'scripts/fbalpha2012-dat-enumerator.cpp') }} | |
| - name: Prepare pinned runtime dependencies | |
| run: make prepare-deps | |
| - name: Check Go formatting, build, tests and lint | |
| run: make backend-check | |
| integration: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| env: | |
| RETROM_TEST_DATABASE_URL: postgres://retrom:retrom-test@127.0.0.1:5432/postgres?sslmode=disable | |
| services: | |
| postgres: | |
| image: postgres:18.3-bookworm@sha256:80630f83606d8db77d30b3851b16a9f78be2d0d4dda6f7b82a1fdca5ebe3acba | |
| env: | |
| POSTGRES_USER: retrom | |
| POSTGRES_PASSWORD: retrom-test | |
| POSTGRES_INITDB_ARGS: "-c max_connections=200" | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd "pg_isready -U retrom -d postgres" | |
| --health-interval 2s --health-timeout 3s --health-retries 30 | |
| steps: | |
| - name: Use runner disk for upload temporary storage | |
| run: | | |
| # Upload fixtures retain 10 GiB; avoid the size-limited /tmp tmpfs. | |
| echo "TMPDIR=$RUNNER_TEMP" >> "$GITHUB_ENV" | |
| df -h /tmp "$RUNNER_TEMP" | |
| - name: Check out the repository | |
| uses: actions/checkout@v6 | |
| - name: Set up Go | |
| uses: actions/setup-go@v7 | |
| with: | |
| go-version-file: go.mod | |
| cache: true | |
| cache-dependency-path: go.sum | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.13" | |
| - name: Restore materialized runtime dependencies | |
| uses: actions/cache/restore@v5 | |
| with: | |
| path: | | |
| data/runtime | |
| data/dat/emulatorjs/*/fbneo | |
| data/dat/emulatorjs/*/mame2003 | |
| data/dat/emulatorjs/*/mame2003_plus | |
| data/dat/emulatorjs/*/fbalpha2012_cps1 | |
| data/dat/emulatorjs/*/fbalpha2012_cps2 | |
| data/auth/password-blocklists/*/payload | |
| key: retrom-dependencies-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('data/dat/**', 'data/auth/**', 'scripts/dependencies.py', 'scripts/fbalpha2012_dat.py', 'scripts/fbalpha2012-dat-enumerator.cpp') }} | |
| - name: Prepare pinned runtime dependencies | |
| run: make prepare-deps | |
| - name: Set up Node.js for runtime integration tests | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: .node-version | |
| package-manager-cache: false | |
| - name: Restore verified Provider chunks | |
| uses: actions/cache/restore@v5 | |
| with: | |
| path: .cache/runtime-providers | |
| key: retrom-provider-chunks-${{ runner.os }}-${{ hashFiles('data/runtime-inputs.json') }} | |
| restore-keys: retrom-provider-chunks-${{ runner.os }}- | |
| - name: Materialize repository-pinned runtime inputs | |
| env: | |
| RETROM_RUNTIME_INPUT_BASE_URL: ${{ vars.RETROM_RUNTIME_INPUT_BASE_URL }} | |
| run: python3 scripts/prepare_image_inputs.py | |
| - name: Run Go integration tests | |
| run: make integration-test | |
| web: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| steps: | |
| - name: Check out the repository | |
| uses: actions/checkout@v6 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: .node-version | |
| cache: npm | |
| cache-dependency-path: web/package-lock.json | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.13" | |
| - name: Restore the repository Node.js toolchain | |
| uses: actions/cache/restore@v5 | |
| with: | |
| path: .cache/tools/node-v24.22.1-linux-x64 | |
| key: retrom-node-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.node-version', 'scripts/prepare-node.sh') }} | |
| - name: Check Web styles, lint, types, tests and build | |
| run: make web-check | |
| - name: Upload Web duplication report | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: web-duplication | |
| path: .artifacts/duplicates/web/ | |
| include-hidden-files: true | |
| if-no-files-found: ignore | |
| browser_ui: | |
| name: browser-ui (${{ matrix.project }}) | |
| needs: changes | |
| if: ${{ needs.changes.outputs.product == 'true' }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 90 | |
| # Every Playwright viewport project runs completely in its own isolated job. | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| project: [chrome-1280, chrome-1440p, chrome-4k-150, chrome-mobile] | |
| env: | |
| RETROM_TEST_DATABASE_URL: postgres://retrom:retrom-test@127.0.0.1:5432/postgres?sslmode=disable | |
| RETROM_E2E_PROJECT: ${{ matrix.project }} | |
| services: | |
| postgres: | |
| image: postgres:18.3-bookworm@sha256:80630f83606d8db77d30b3851b16a9f78be2d0d4dda6f7b82a1fdca5ebe3acba | |
| env: | |
| POSTGRES_USER: retrom | |
| POSTGRES_PASSWORD: retrom-test | |
| POSTGRES_INITDB_ARGS: "-c max_connections=200" | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd "pg_isready -U retrom -d postgres" | |
| --health-interval 2s --health-timeout 3s --health-retries 30 | |
| steps: | |
| - name: Use runner disk for upload temporary storage | |
| run: | | |
| # Upload fixtures retain 10 GiB; avoid the size-limited /tmp tmpfs. | |
| echo "TMPDIR=$RUNNER_TEMP" >> "$GITHUB_ENV" | |
| df -h /tmp "$RUNNER_TEMP" | |
| - name: Check out the repository | |
| uses: actions/checkout@v6 | |
| - name: Set up Go | |
| uses: actions/setup-go@v7 | |
| with: | |
| go-version-file: go.mod | |
| cache: true | |
| cache-dependency-path: go.sum | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: .node-version | |
| cache: npm | |
| cache-dependency-path: web/package-lock.json | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.13" | |
| - name: Restore the repository Node.js toolchain | |
| uses: actions/cache/restore@v5 | |
| with: | |
| path: .cache/tools/node-v24.22.1-linux-x64 | |
| key: retrom-node-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.node-version', 'scripts/prepare-node.sh') }} | |
| - name: Restore materialized runtime dependencies | |
| uses: actions/cache/restore@v5 | |
| with: | |
| path: | | |
| data/runtime | |
| data/dat/emulatorjs/*/fbneo | |
| data/dat/emulatorjs/*/mame2003 | |
| data/dat/emulatorjs/*/mame2003_plus | |
| data/dat/emulatorjs/*/fbalpha2012_cps1 | |
| data/dat/emulatorjs/*/fbalpha2012_cps2 | |
| data/auth/password-blocklists/*/payload | |
| key: retrom-dependencies-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('data/dat/**', 'data/auth/**', 'scripts/dependencies.py', 'scripts/fbalpha2012_dat.py', 'scripts/fbalpha2012-dat-enumerator.cpp') }} | |
| - name: Prepare pinned runtime dependencies | |
| run: make prepare-deps | |
| - name: Prepare fixed Latin and CJK fonts for browser checks | |
| run: | | |
| scripts/prepare-e2e-fonts.sh | |
| echo "FONTCONFIG_FILE=$PWD/.cache/tools/e2e-fonts/fonts.conf" >> "$GITHUB_ENV" | |
| - name: Restore verified Provider chunks | |
| uses: actions/cache/restore@v5 | |
| with: | |
| path: .cache/runtime-providers | |
| key: retrom-provider-chunks-${{ runner.os }}-${{ hashFiles('data/runtime-inputs.json') }} | |
| restore-keys: retrom-provider-chunks-${{ runner.os }}- | |
| - name: Materialize repository-pinned runtime inputs | |
| env: | |
| RETROM_RUNTIME_INPUT_BASE_URL: ${{ vars.RETROM_RUNTIME_INPUT_BASE_URL }} | |
| run: python3 scripts/prepare_image_inputs.py | |
| - name: Prepare the development application before acceptance timing | |
| # prepare-e2e-browser below installs the Web dependencies exactly once. | |
| run: make build | |
| - name: Verify UI consistency in the product browser | |
| run: | | |
| make prepare-e2e-browser | |
| make acceptance-prepare | |
| make acceptance-case CASE=ACC-RF-BROWSER | |
| - name: Upload UI review evidence | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ui-consistency-evidence-${{ matrix.project }} | |
| path: .artifacts/acceptance/*/cases/acc-rf-browser/ | |
| include-hidden-files: true | |
| if-no-files-found: ignore | |
| retention-days: 14 | |
| pfb_gateway: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.13" | |
| - name: Verify isolated PFB gateway routing | |
| run: make pfb-gateway-test | |
| quality: | |
| runs-on: ubuntu-latest | |
| needs: [changes, contracts, backend, integration, web, browser_ui, pfb_gateway] | |
| if: ${{ always() }} | |
| steps: | |
| - name: Require every quality check to pass | |
| env: | |
| CHANGES_RESULT: ${{ needs.changes.result }} | |
| PRODUCT_CHANGED: ${{ needs.changes.outputs.product }} | |
| CONTRACTS_RESULT: ${{ needs.contracts.result }} | |
| BACKEND_RESULT: ${{ needs.backend.result }} | |
| INTEGRATION_RESULT: ${{ needs.integration.result }} | |
| WEB_RESULT: ${{ needs.web.result }} | |
| BROWSER_UI_RESULT: ${{ needs.browser_ui.result }} | |
| PFB_GATEWAY_RESULT: ${{ needs.pfb_gateway.result }} | |
| run: | | |
| # Only a documentation-only change may skip the product browser. | |
| if [[ "$PRODUCT_CHANGED" == false && "$BROWSER_UI_RESULT" == skipped ]]; then | |
| BROWSER_UI_RESULT=success | |
| fi | |
| for result in "$CHANGES_RESULT" "$CONTRACTS_RESULT" "$BACKEND_RESULT" "$INTEGRATION_RESULT" "$WEB_RESULT" "$BROWSER_UI_RESULT" "$PFB_GATEWAY_RESULT"; do | |
| if [[ "$result" != success ]]; then | |
| echo "Quality check did not pass: $result" >&2 | |
| exit 1 | |
| fi | |
| done |