|
@@ -58,11 +58,30 @@ jobs:
|
|
|
# before it does; both come from playwright.config.ts.
|
|
# before it does; both come from playwright.config.ts.
|
|
|
E2E_DATABASE_URL: postgresql://torqvoice:torqvoice@127.0.0.1:5432/torqvoice_e2e
|
|
E2E_DATABASE_URL: postgresql://torqvoice:torqvoice@127.0.0.1:5432/torqvoice_e2e
|
|
|
E2E_MODE: ${{ matrix.mode }}
|
|
E2E_MODE: ${{ matrix.mode }}
|
|
|
|
|
+ # The cloud job mints a one-day cloud token from it; without the token the
|
|
|
|
|
+ # app ignores TORQVOICE_MODE=cloud. Only the cloud job gets it.
|
|
|
|
|
+ TORQVOICE_COM_LICENSE_SIGNING_PRIVATE_KEY: ${{ matrix.mode == 'cloud' && secrets.TORQVOICE_COM_LICENSE_SIGNING_PRIVATE_KEY || '' }}
|
|
|
|
|
|
|
|
steps:
|
|
steps:
|
|
|
|
|
+ # A pull request from a fork gets no secrets, so the cloud job has no key
|
|
|
|
|
+ # to mint its cloud token with and the app would refuse cloud mode. That
|
|
|
|
|
+ # says nothing about the contribution, so the job skips instead of failing.
|
|
|
|
|
+ # The self-hosted shards need no key and always run.
|
|
|
|
|
+ - name: Check for the cloud signing key
|
|
|
|
|
+ id: gate
|
|
|
|
|
+ run: |
|
|
|
|
|
+ if [ "${{ matrix.mode }}" = "cloud" ] && [ -z "$TORQVOICE_COM_LICENSE_SIGNING_PRIVATE_KEY" ]; then
|
|
|
|
|
+ echo "::notice title=Cloud specs skipped::No TORQVOICE_COM_LICENSE_SIGNING_PRIVATE_KEY here (a fork or Dependabot pull request), so the cloud specs cannot run."
|
|
|
|
|
+ echo "run=false" >> "$GITHUB_OUTPUT"
|
|
|
|
|
+ else
|
|
|
|
|
+ echo "run=true" >> "$GITHUB_OUTPUT"
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
- uses: actions/checkout@v4
|
|
- uses: actions/checkout@v4
|
|
|
|
|
+ if: ${{ steps.gate.outputs.run == 'true' }}
|
|
|
|
|
|
|
|
- uses: actions/setup-node@v4
|
|
- uses: actions/setup-node@v4
|
|
|
|
|
+ if: ${{ steps.gate.outputs.run == 'true' }}
|
|
|
with:
|
|
with:
|
|
|
node-version: 22
|
|
node-version: 22
|
|
|
cache: npm
|
|
cache: npm
|
|
@@ -70,21 +89,26 @@ jobs:
|
|
|
# A fresh one per run: the sessions it signs live as long as the job, and
|
|
# A fresh one per run: the sessions it signs live as long as the job, and
|
|
|
# a short or guessable value makes better-auth warn on every request.
|
|
# a short or guessable value makes better-auth warn on every request.
|
|
|
- name: Make a session secret for this run
|
|
- name: Make a session secret for this run
|
|
|
|
|
+ if: ${{ steps.gate.outputs.run == 'true' }}
|
|
|
run: echo "BETTER_AUTH_SECRET=$(openssl rand -base64 32)" >> "$GITHUB_ENV"
|
|
run: echo "BETTER_AUTH_SECRET=$(openssl rand -base64 32)" >> "$GITHUB_ENV"
|
|
|
|
|
|
|
|
- run: npm ci
|
|
- run: npm ci
|
|
|
|
|
+ if: ${{ steps.gate.outputs.run == 'true' }}
|
|
|
|
|
|
|
|
- run: npx prisma generate
|
|
- run: npx prisma generate
|
|
|
|
|
+ if: ${{ steps.gate.outputs.run == 'true' }}
|
|
|
|
|
|
|
|
# Keyed on the pinned version, because the image tag and this download
|
|
# Keyed on the pinned version, because the image tag and this download
|
|
|
# have to be the same build.
|
|
# have to be the same build.
|
|
|
- name: Cache the browser
|
|
- name: Cache the browser
|
|
|
|
|
+ if: ${{ steps.gate.outputs.run == 'true' }}
|
|
|
uses: actions/cache@v4
|
|
uses: actions/cache@v4
|
|
|
with:
|
|
with:
|
|
|
path: ~/.cache/ms-playwright
|
|
path: ~/.cache/ms-playwright
|
|
|
key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
|
|
key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
|
|
|
|
|
|
|
|
- name: Install the browser
|
|
- name: Install the browser
|
|
|
|
|
+ if: ${{ steps.gate.outputs.run == 'true' }}
|
|
|
run: npx playwright install --with-deps chromium
|
|
run: npx playwright install --with-deps chromium
|
|
|
|
|
|
|
|
# The seed copies bundled vehicle photos when they are in the tree and
|
|
# The seed copies bundled vehicle photos when they are in the tree and
|
|
@@ -92,6 +116,7 @@ jobs:
|
|
|
# another, which is minutes of a cold run and the flakiest thing in it.
|
|
# another, which is minutes of a cold run and the flakiest thing in it.
|
|
|
# Cached, a warm run copies them off disk instead.
|
|
# Cached, a warm run copies them off disk instead.
|
|
|
- name: Cache the seed's photos
|
|
- name: Cache the seed's photos
|
|
|
|
|
+ if: ${{ steps.gate.outputs.run == 'true' }}
|
|
|
uses: actions/cache@v4
|
|
uses: actions/cache@v4
|
|
|
with:
|
|
with:
|
|
|
# Where prepare-db.ts points the seed's DATA_ROOT, so a test run
|
|
# Where prepare-db.ts points the seed's DATA_ROOT, so a test run
|
|
@@ -105,6 +130,7 @@ jobs:
|
|
|
# Every job reads it; only the first shard writes it back, so five jobs
|
|
# Every job reads it; only the first shard writes it back, so five jobs
|
|
|
# do not race to save the same entry.
|
|
# do not race to save the same entry.
|
|
|
- name: Restore the build cache
|
|
- name: Restore the build cache
|
|
|
|
|
+ if: ${{ steps.gate.outputs.run == 'true' }}
|
|
|
uses: actions/cache/restore@v4
|
|
uses: actions/cache/restore@v4
|
|
|
with:
|
|
with:
|
|
|
path: .next/cache
|
|
path: .next/cache
|
|
@@ -117,24 +143,26 @@ jobs:
|
|
|
# refuses a sign-in from an origin the build was not made for, so it has
|
|
# refuses a sign-in from an origin the build was not made for, so it has
|
|
|
# to match the base URL the suite uses.
|
|
# to match the base URL the suite uses.
|
|
|
- name: Build
|
|
- name: Build
|
|
|
|
|
+ if: ${{ steps.gate.outputs.run == 'true' }}
|
|
|
run: npm run build
|
|
run: npm run build
|
|
|
env:
|
|
env:
|
|
|
NEXT_PUBLIC_APP_URL: http://127.0.0.1:3100
|
|
NEXT_PUBLIC_APP_URL: http://127.0.0.1:3100
|
|
|
|
|
|
|
|
- name: Save the build cache
|
|
- name: Save the build cache
|
|
|
- if: ${{ matrix.id == 'shard-1' }}
|
|
|
|
|
|
|
+ if: ${{ steps.gate.outputs.run == 'true' && (matrix.id == 'shard-1') }}
|
|
|
uses: actions/cache/save@v4
|
|
uses: actions/cache/save@v4
|
|
|
with:
|
|
with:
|
|
|
path: .next/cache
|
|
path: .next/cache
|
|
|
key: next-${{ hashFiles('package-lock.json') }}-${{ github.sha }}
|
|
key: next-${{ hashFiles('package-lock.json') }}-${{ github.sha }}
|
|
|
|
|
|
|
|
- name: Run the specs
|
|
- name: Run the specs
|
|
|
|
|
+ if: ${{ steps.gate.outputs.run == 'true' }}
|
|
|
run: npx playwright test ${{ matrix.shard && format('--shard={0}', matrix.shard) || '' }}
|
|
run: npx playwright test ${{ matrix.shard && format('--shard={0}', matrix.shard) || '' }}
|
|
|
|
|
|
|
|
# The blob carries the results with their traces, screenshots and videos;
|
|
# The blob carries the results with their traces, screenshots and videos;
|
|
|
# the report job turns every job's blob into one HTML report.
|
|
# the report job turns every job's blob into one HTML report.
|
|
|
- name: Upload the blob report
|
|
- name: Upload the blob report
|
|
|
- if: ${{ !cancelled() }}
|
|
|
|
|
|
|
+ if: ${{ steps.gate.outputs.run == 'true' && (!cancelled()) }}
|
|
|
uses: actions/upload-artifact@v4
|
|
uses: actions/upload-artifact@v4
|
|
|
with:
|
|
with:
|
|
|
name: blob-report-${{ matrix.id }}
|
|
name: blob-report-${{ matrix.id }}
|