From b0e72ae3c1e646d983b89767cca88f4e7453cc99 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 7 May 2026 06:06:38 -0500 Subject: [PATCH 1/7] Add reusable Playwright E2E workflow --- .github/workflows/ci-e2e-playwright.yml | 91 +++++++++++++++++++++++++ README.md | 41 +++++++++++ 2 files changed, 132 insertions(+) create mode 100644 .github/workflows/ci-e2e-playwright.yml diff --git a/.github/workflows/ci-e2e-playwright.yml b/.github/workflows/ci-e2e-playwright.yml new file mode 100644 index 0000000..d3901d2 --- /dev/null +++ b/.github/workflows/ci-e2e-playwright.yml @@ -0,0 +1,91 @@ +# Reusable workflow for running Playwright E2E tests in a containerized +# environment with browsers pre-installed. Eliminates the ~60s browser +# install step by using Microsoft's official Playwright Docker images. +# +# Usage: +# +# jobs: +# e2e: +# uses: codeflash-ai/github-workflows/.github/workflows/ci-e2e-playwright.yml@main +# with: +# playwright-version: "v1.59.0" +# test-command: "uv run pytest tests/e2e/ --browser $BROWSER -v" +# +# The $BROWSER placeholder in test-command is replaced with the matrix +# browser value (chromium, firefox, or webkit) at runtime. + +name: E2E (Playwright) + +on: + workflow_call: + inputs: + playwright-version: + description: "Playwright version tag, e.g. v1.59.0" + type: string + required: true + base-image: + description: "Ubuntu base for the container image" + type: string + default: "noble" + browsers: + description: "JSON array of browsers to test" + type: string + default: '["chromium", "firefox", "webkit"]' + sync-command: + description: "Dependency install command" + type: string + default: "uv sync" + test-command: + description: "Pytest command template — use $BROWSER placeholder for browser name" + type: string + required: true + test-directory: + description: "Working directory for all commands" + type: string + default: "." + artifact-retention-days: + description: "How long to keep trace artifacts" + type: number + default: 7 + fail-fast: + description: "Stop on first browser failure" + type: boolean + default: false + +jobs: + e2e: + strategy: + fail-fast: ${{ inputs.fail-fast }} + matrix: + browser: ${{ fromJSON(inputs.browsers) }} + runs-on: ubuntu-latest + container: + image: mcr.microsoft.com/playwright/python:${{ inputs.playwright-version }}-${{ inputs.base-image }} + options: --user 1001 + permissions: + contents: read + defaults: + run: + working-directory: ${{ inputs.test-directory }} + steps: + - uses: actions/checkout@v6 + + - uses: astral-sh/setup-uv@v8.1.0 + with: + enable-cache: true + + - run: ${{ inputs.sync-command }} + + - name: Run Playwright tests (${{ matrix.browser }}) + run: | + BROWSER="${{ matrix.browser }}" && ${TEST_CMD/\$BROWSER/$BROWSER} + env: + TEST_CMD: ${{ inputs.test-command }} + + - name: Upload traces + if: failure() + uses: actions/upload-artifact@v4 + with: + name: playwright-traces-${{ matrix.browser }} + path: ${{ inputs.test-directory }}/test-results/ + retention-days: ${{ inputs.artifact-retention-days }} diff --git a/README.md b/README.md index 13cc595..a09a51f 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,47 @@ jobs: CI_BOT_PRIVATE_KEY: ${{ secrets.CI_BOT_PRIVATE_KEY }} ``` +### `ci-e2e-playwright.yml` + +Reusable workflow for running [Playwright](https://playwright.dev/) E2E tests inside a Docker container with browsers pre-installed. Uses Microsoft's official `mcr.microsoft.com/playwright/python` images, eliminating the ~60s browser install step per job. + +**Inputs:** + +| Input | Default | Description | +|---|---|---| +| `playwright-version` | *(required)* | Playwright version tag, e.g. `"v1.59.0"` | +| `base-image` | `"noble"` | Ubuntu base for the container image | +| `browsers` | `'["chromium", "firefox", "webkit"]'` | JSON array of browsers to test | +| `sync-command` | `"uv sync"` | Dependency install command | +| `test-command` | *(required)* | Pytest command template -- use `$BROWSER` placeholder | +| `test-directory` | `"."` | Working directory for all commands | +| `artifact-retention-days` | `7` | How long to keep trace artifacts | +| `fail-fast` | `false` | Stop on first browser failure | + +**Example:** + +```yaml +name: E2E + +on: + pull_request: + push: + branches: [main] + +concurrency: + group: e2e-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + e2e: + uses: codeflash-ai/github-workflows/.github/workflows/ci-e2e-playwright.yml@main + with: + playwright-version: "v1.59.0" + test-command: "uv run pytest tests/e2e/ --browser $BROWSER -v --tracing on" + test-directory: "." + fail-fast: false +``` + --- ## Adding a new workflow From 39ed2888ee56f51012ca85f79f47d833cfd7a1f2 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 7 May 2026 06:23:04 -0500 Subject: [PATCH 2/7] Make playwright-version optional with a default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Callers shouldn't need to pin a version — default to latest stable and let them override only when needed. --- .github/workflows/ci-e2e-playwright.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-e2e-playwright.yml b/.github/workflows/ci-e2e-playwright.yml index d3901d2..c0ef71a 100644 --- a/.github/workflows/ci-e2e-playwright.yml +++ b/.github/workflows/ci-e2e-playwright.yml @@ -8,7 +8,6 @@ # e2e: # uses: codeflash-ai/github-workflows/.github/workflows/ci-e2e-playwright.yml@main # with: -# playwright-version: "v1.59.0" # test-command: "uv run pytest tests/e2e/ --browser $BROWSER -v" # # The $BROWSER placeholder in test-command is replaced with the matrix @@ -20,9 +19,9 @@ on: workflow_call: inputs: playwright-version: - description: "Playwright version tag, e.g. v1.59.0" + description: "Playwright version tag, e.g. v1.59.0 (defaults to latest)" type: string - required: true + default: "v1.59.0" base-image: description: "Ubuntu base for the container image" type: string From edc8dcec104b7a9c0024fb7292e7740abb420234 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 7 May 2026 06:25:30 -0500 Subject: [PATCH 3/7] Fix bad substitution: use bash shell for parameter expansion The Playwright container defaults to sh (dash) which doesn't support ${var/pattern/replacement}. Explicit shell: bash fixes it. --- .github/workflows/ci-e2e-playwright.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci-e2e-playwright.yml b/.github/workflows/ci-e2e-playwright.yml index c0ef71a..6d12d22 100644 --- a/.github/workflows/ci-e2e-playwright.yml +++ b/.github/workflows/ci-e2e-playwright.yml @@ -76,6 +76,7 @@ jobs: - run: ${{ inputs.sync-command }} - name: Run Playwright tests (${{ matrix.browser }}) + shell: bash run: | BROWSER="${{ matrix.browser }}" && ${TEST_CMD/\$BROWSER/$BROWSER} env: From c66e6ade3264bd05139d9f37fd1d83150ca122cc Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 7 May 2026 06:28:57 -0500 Subject: [PATCH 4/7] Set UV_LINK_MODE=copy for container jobs Docker container filesystems don't support hardlinks between the UV cache and workspace. Suppress the warning and avoid the fallback penalty by setting copy mode explicitly. --- .github/workflows/ci-e2e-playwright.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci-e2e-playwright.yml b/.github/workflows/ci-e2e-playwright.yml index 6d12d22..047e265 100644 --- a/.github/workflows/ci-e2e-playwright.yml +++ b/.github/workflows/ci-e2e-playwright.yml @@ -63,6 +63,8 @@ jobs: options: --user 1001 permissions: contents: read + env: + UV_LINK_MODE: copy defaults: run: working-directory: ${{ inputs.test-directory }} From 5be097c9249edf7f9ac50dfdb3a2b7e3f7f2ef91 Mon Sep 17 00:00:00 2001 From: Kevin Turcios <106575910+KRRT7@users.noreply.github.com> Date: Thu, 7 May 2026 06:19:40 -0500 Subject: [PATCH 5/7] =?UTF-8?q?Fix=20prek-lint=20permissions=20=E2=80=94?= =?UTF-8?q?=20use=20read,=20let=20callers=20grant=20write=20for=20auto-fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/prek-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/prek-lint.yml b/.github/workflows/prek-lint.yml index 97f728e..9bf36e0 100644 --- a/.github/workflows/prek-lint.yml +++ b/.github/workflows/prek-lint.yml @@ -29,7 +29,7 @@ jobs: runs-on: ubuntu-latest continue-on-error: ${{ inputs.continue-on-error }} permissions: - contents: write + contents: read steps: - uses: actions/checkout@v6 with: From f71fc9b33139b098101ee86409d5c39c7426f8bf Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 7 May 2026 06:44:13 -0500 Subject: [PATCH 6/7] Add result input to ready-to-merge so callers can gate on CI Callers pass result: success/failure based on their needs. This lets the reusable workflow be used as a terminal gate job. --- .github/workflows/ready-to-merge.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ready-to-merge.yml b/.github/workflows/ready-to-merge.yml index 0ad8646..6fdf256 100644 --- a/.github/workflows/ready-to-merge.yml +++ b/.github/workflows/ready-to-merge.yml @@ -2,9 +2,18 @@ name: Ready to Merge on: workflow_call: + inputs: + result: + description: "Pass 'success' when all upstream jobs passed" + type: string + required: true jobs: ready: runs-on: ubuntu-latest steps: - - run: echo "Branch is up to date" + - run: | + if [ "${{ inputs.result }}" != "success" ]; then + echo "CI failed" + exit 1 + fi From b90f3a457abe5e5ba362ace283ea277d13f34d4a Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 7 May 2026 06:49:23 -0500 Subject: [PATCH 7/7] Add CI workflow to produce ready / ready check for org ruleset --- .github/workflows/ci.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8e35ac8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,12 @@ +name: CI + +on: + pull_request: + push: + branches: [main] + +jobs: + ready: + uses: ./.github/workflows/ready-to-merge.yml + with: + result: success