e2e: extract Playwright report via docker cp instead of bind mount

When the runner job runs inside a container, compose's relative
`./playwright/playwright-report` resolves to a path that exists
only inside the runner container, so the host's docker daemon
silently bind-mounts an empty dir and the report never lands
anywhere we can read.

Drop the bind mounts; keep the playwright container around
(--name e2e-pw, no --rm); after the test, `docker cp` the
report and traces out into the runner's workspace volume so
upload-artifact has something real to upload. The new test-results
directory (Playwright traces, screenshots, videos) is also
included so failure post-mortem doesn't need a re-run.
This commit is contained in:
2026-05-08 21:36:09 +01:00
parent a9c6a060d4
commit e8804922b5
2 changed files with 28 additions and 12 deletions
+19 -8
View File
@@ -79,15 +79,22 @@ jobs:
- name: Start the agent
run: docker compose -f e2e/compose.e2e.yml up -d agent
- name: Prepare report mounts
run: |
mkdir -p e2e/playwright/playwright-report e2e/playwright/test-results
chmod -R a+rwX e2e/playwright/playwright-report e2e/playwright/test-results
- name: Run Playwright tests
id: playwright
env:
RM_BOOTSTRAP_TOKEN: ${{ env.RM_BOOTSTRAP_TOKEN }}
run: docker compose -f e2e/compose.e2e.yml run --rm playwright
# --name pins a stable container ID so the next step can
# docker cp out of it before tear-down. We deliberately
# drop --rm so the container survives the test exit; the
# tear-down step removes it.
run: docker compose -f e2e/compose.e2e.yml run --name e2e-pw playwright
- name: Extract Playwright report
if: always() && steps.playwright.outcome != 'skipped'
run: |
mkdir -p e2e/playwright/playwright-report e2e/playwright/test-results
docker cp e2e-pw:/work/playwright-report/. e2e/playwright/playwright-report/ || true
docker cp e2e-pw:/work/test-results/. e2e/playwright/test-results/ || true
- name: Compose logs (on failure)
if: failure()
@@ -101,9 +108,13 @@ jobs:
uses: actions/upload-artifact@v3
with:
name: playwright-report
path: e2e/playwright/playwright-report
path: |
e2e/playwright/playwright-report
e2e/playwright/test-results
retention-days: 7
- name: Tear down
if: always()
run: docker compose -f e2e/compose.e2e.yml down -v
run: |
docker rm -f e2e-pw 2>/dev/null || true
docker compose -f e2e/compose.e2e.yml down -v
+9 -4
View File
@@ -64,10 +64,18 @@ services:
networks: [rmnet]
# Playwright test runner. Profile-gated so `compose up` doesn't
# start it; CI runs it via `compose run --rm playwright`. Lives on
# start it; CI invokes it via `compose run` and `docker cp`s the
# report+traces out (see .gitea/workflows/e2e.yml). Lives on
# rmnet so it can reach the server via its compose-network DNS
# name rather than depending on host port-publish (which doesn't
# work on Gitea's container-based runners).
#
# Reports are NOT bind-mounted: when the runner job itself runs
# inside a container, `./playwright/...` resolves to a path that
# only exists inside the runner container, so the host docker
# daemon would silently mount an empty dir. Instead the report
# stays inside the playwright container and the workflow extracts
# it via `docker cp` before tearing down.
playwright:
profiles: [test]
build:
@@ -76,9 +84,6 @@ services:
environment:
RM_BASE_URL: "http://server:8080"
RM_BOOTSTRAP_TOKEN: "${RM_BOOTSTRAP_TOKEN:-}"
volumes:
- ./playwright/playwright-report:/work/playwright-report
- ./playwright/test-results:/work/test-results
depends_on:
- server
- agent