diff --git a/.github/actions/setup-backend/action.yml b/.github/actions/setup-backend/action.yml index d0f6ab825..e53eed46c 100644 --- a/.github/actions/setup-backend/action.yml +++ b/.github/actions/setup-backend/action.yml @@ -14,17 +14,43 @@ inputs: runs: using: composite steps: + # Cached .debs install without touching an Ubuntu mirror, which can stall a job until its time limit. + - name: Restore apt packages + id: apt-debs + uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ${{ runner.temp }}/apt-debs + key: apt-debs-ubuntu24-${{ runner.arch }}-libmariadb-${{ inputs.apt-packages }} + # The mariadb package ships only an sdist on Linux, so uv builds it against these. - name: Install the MariaDB connector shell: bash env: APT_PACKAGES: ${{ inputs.apt-packages }} + DEB_DIR: ${{ runner.temp }}/apt-debs + DEBS_CACHED: ${{ steps.apt-debs.outputs.cache-hit }} run: | read -ra extra <<<"$APT_PACKAGES" - # apt has no network timeout by default, so a stalled mirror hangs until the job limit. - apt_opts=(-o Acquire::Retries=3 -o Acquire::http::Timeout=30 -o Acquire::https::Timeout=30) - sudo apt-get "${apt_opts[@]}" update - sudo apt-get "${apt_opts[@]}" install -y libmariadb3 libmariadb-dev "${extra[@]}" + if [[ "$DEBS_CACHED" != true ]]; then + apt_opts=(-o Acquire::Retries=3 -o Acquire::http::Timeout=30 -o Acquire::https::Timeout=30) + sudo apt-get "${apt_opts[@]}" update + mkdir -p "$DEB_DIR/partial" + sudo apt-get "${apt_opts[@]}" install -y --download-only -o Dir::Cache::archives="$DEB_DIR" \ + libmariadb3 libmariadb-dev "${extra[@]}" + fi + mkdir -p "$DEB_DIR/partial" + # With package lists present, apt prefers the mirror's copy of a local .deb unless it finds it in its archives dir. + sudo apt-get install -y --no-download -o Dir::Cache::archives="$DEB_DIR" "$DEB_DIR"/*.deb + # apt leaves a root-only lock file the cache save can't read. + sudo rm -rf "$DEB_DIR/lock" "$DEB_DIR/partial" + + # Only master writes it, so a PR can't evict or seed it. + - name: Save apt packages + if: steps.apt-debs.outputs.cache-hit != 'true' && github.ref == 'refs/heads/master' + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ${{ runner.temp }}/apt-debs + key: ${{ steps.apt-debs.outputs.cache-primary-key }} - name: Install uv uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0 diff --git a/.github/workflows/api-types.yml b/.github/workflows/api-types.yml index 4bf9eeb97..60809c8bf 100644 --- a/.github/workflows/api-types.yml +++ b/.github/workflows/api-types.yml @@ -36,7 +36,7 @@ permissions: jobs: api-types: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 15 steps: - name: Checkout repository diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f12970f21..6ad289ac7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,7 +37,7 @@ jobs: validate-tag-semver: # Forks have no registry credentials, so their nightly would fail every day. if: github.event_name != 'schedule' || github.repository == 'rommapp/romm' - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 5 permissions: contents: read @@ -204,7 +204,7 @@ jobs: merge: needs: build - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 15 env: DOCKER_METADATA_ANNOTATIONS_LEVELS: index @@ -320,7 +320,7 @@ jobs: fail-fast: false matrix: variant: [slim, full] - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 15 permissions: contents: read diff --git a/.github/workflows/conventional-pr-title.yml b/.github/workflows/conventional-pr-title.yml index bfaca785e..8b94fcf97 100644 --- a/.github/workflows/conventional-pr-title.yml +++ b/.github/workflows/conventional-pr-title.yml @@ -15,7 +15,7 @@ permissions: {} jobs: check-title: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 5 steps: - name: Check the PR title diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index df5546f82..74bf402c7 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -8,7 +8,7 @@ permissions: jobs: copilot-setup-steps: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 30 services: mariadb: diff --git a/.github/workflows/docker-pr.yml b/.github/workflows/docker-pr.yml index 3fa577096..7c09ac574 100644 --- a/.github/workflows/docker-pr.yml +++ b/.github/workflows/docker-pr.yml @@ -23,7 +23,7 @@ permissions: jobs: build-and-boot: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 45 services: mariadb: diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 9102e7568..463f5f7ea 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -34,7 +34,7 @@ permissions: jobs: e2e: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 20 services: mariadb: @@ -89,9 +89,10 @@ jobs: ) & working-directory: frontend - # Headless runs use only the headless shell, so skip the full Chrome build. + # Headless runs use only the headless shell, so skip the full Chrome build. The runner + # image already has its system libraries, and --with-deps can hang on a stalled apt mirror. - name: Install Playwright browser - run: npx playwright install --with-deps --only-shell chromium + run: npx playwright install --only-shell chromium working-directory: frontend # ROMM_BASE_PATH must be writable (the app creates config/, resources/ and diff --git a/.github/workflows/frontend-v1-frozen.yml b/.github/workflows/frontend-v1-frozen.yml index 36b48a360..8324293a3 100644 --- a/.github/workflows/frontend-v1-frozen.yml +++ b/.github/workflows/frontend-v1-frozen.yml @@ -26,7 +26,7 @@ permissions: jobs: check-v1-frozen: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 5 steps: - name: Checkout repository diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index b48568cb7..a1667680c 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -4,12 +4,14 @@ on: pull_request: paths: - "frontend/**" + - ".github/workflows/frontend.yml" - ".github/actions/setup-frontend/**" push: branches: - "master" paths: - "frontend/**" + - ".github/workflows/frontend.yml" - ".github/actions/setup-frontend/**" # A new push cancels a PR's superseded run; each master commit keeps its own. @@ -22,7 +24,7 @@ permissions: jobs: test: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 15 steps: - name: Checkout repository @@ -33,9 +35,10 @@ jobs: - name: Set up the frontend uses: ./.github/actions/setup-frontend - # Stories run in browser mode, which needs only the headless shell. + # Stories run in browser mode, which needs only the headless shell. The runner image + # already has its system libraries, and --with-deps can hang on a stalled apt mirror. - name: Install Playwright browser - run: npx playwright install --with-deps --only-shell chromium + run: npx playwright install --only-shell chromium working-directory: frontend - name: Run tests (vitest, includes Storybook play() and a11y tests) @@ -43,7 +46,7 @@ jobs: working-directory: frontend build: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 15 steps: - name: Checkout repository @@ -59,7 +62,7 @@ jobs: working-directory: frontend typecheck: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 15 steps: - name: Checkout repository diff --git a/.github/workflows/i18n.yml b/.github/workflows/i18n.yml index a7bb37d61..15d8acd22 100644 --- a/.github/workflows/i18n.yml +++ b/.github/workflows/i18n.yml @@ -15,7 +15,7 @@ permissions: jobs: check-translations: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 10 steps: diff --git a/.github/workflows/image-scan.yml b/.github/workflows/image-scan.yml index 59c7e2c57..e93ea858a 100644 --- a/.github/workflows/image-scan.yml +++ b/.github/workflows/image-scan.yml @@ -24,7 +24,7 @@ permissions: jobs: resolve: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 5 outputs: images: ${{ steps.resolve.outputs.images }} @@ -51,7 +51,7 @@ jobs: fail-fast: false matrix: image: ${{ fromJSON(needs.resolve.outputs.images) }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 20 permissions: contents: read @@ -143,7 +143,7 @@ jobs: fail-fast: false matrix: image: ${{ fromJSON(needs.resolve.outputs.images) }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 30 permissions: contents: read diff --git a/.github/workflows/migrations.yml b/.github/workflows/migrations.yml index 22e5549f0..646b087cc 100644 --- a/.github/workflows/migrations.yml +++ b/.github/workflows/migrations.yml @@ -19,7 +19,7 @@ permissions: jobs: migrate-postgres: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 15 services: postgres: @@ -62,7 +62,7 @@ jobs: # and the JSON_TABLE columns utf8mb3, which breaks collation-sensitive # migration SQL that a default utf8mb4 server accepts (issue #4350). name: migrate-mariadb (${{ matrix.mariadb }}, ${{ matrix.collation }}) - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 15 strategy: fail-fast: false diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index 81546dc22..de1026790 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -34,7 +34,7 @@ permissions: jobs: mypy: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 15 steps: - name: Checkout repository diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 2fc11e3a5..14f7e9e2e 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -32,7 +32,7 @@ permissions: jobs: pytest: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 30 strategy: fail-fast: false @@ -115,7 +115,7 @@ jobs: upload-coverage: needs: pytest if: ${{ !cancelled() && needs.pytest.result == 'success' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 10 permissions: contents: read diff --git a/.github/workflows/report-scheduled-failure.yml b/.github/workflows/report-scheduled-failure.yml index 002711065..b94cdab88 100644 --- a/.github/workflows/report-scheduled-failure.yml +++ b/.github/workflows/report-scheduled-failure.yml @@ -10,7 +10,7 @@ permissions: jobs: report: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 5 permissions: issues: write diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index fe0652187..eda3bfba9 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -33,7 +33,7 @@ jobs: if: | github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'build-preview') - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 5 permissions: pull-requests: write @@ -143,7 +143,7 @@ jobs: merge: needs: build - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 15 permissions: contents: read @@ -224,7 +224,7 @@ jobs: !cancelled() && github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'build-preview') - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 5 permissions: pull-requests: write diff --git a/.github/workflows/trunk-check-all.yml b/.github/workflows/trunk-check-all.yml index 140a89226..e7b694070 100644 --- a/.github/workflows/trunk-check-all.yml +++ b/.github/workflows/trunk-check-all.yml @@ -13,7 +13,7 @@ permissions: jobs: trunk-check-all: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 30 steps: - name: Checkout repository diff --git a/.github/workflows/trunk-check.yml b/.github/workflows/trunk-check.yml index 21a1adca0..28283969e 100644 --- a/.github/workflows/trunk-check.yml +++ b/.github/workflows/trunk-check.yml @@ -16,7 +16,7 @@ permissions: jobs: trunk_check: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 20 permissions: checks: write # For trunk to post annotations diff --git a/.github/workflows/trunk-upgrade.yml b/.github/workflows/trunk-upgrade.yml index 450839913..2c4437966 100644 --- a/.github/workflows/trunk-upgrade.yml +++ b/.github/workflows/trunk-upgrade.yml @@ -10,7 +10,7 @@ permissions: jobs: trunk-upgrade: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 20 permissions: contents: write # For create-pull-request to push the branch diff --git a/.github/workflows/update-hltb-api-url.yml b/.github/workflows/update-hltb-api-url.yml index 14dacb6f0..dde6d0067 100644 --- a/.github/workflows/update-hltb-api-url.yml +++ b/.github/workflows/update-hltb-api-url.yml @@ -12,7 +12,7 @@ permissions: jobs: update-hltb-api-url: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 15 permissions: contents: write # For create-pull-request to push the branch