name: 'Test: E2E CI' on: workflow_call: inputs: branch: description: 'GitHub branch/ref to test' required: false type: string default: '' playwright-only: description: 'Only Playwright files changed — run impacted tests only' required: false type: boolean default: false env: DOCKER_IMAGE: ghcr.io/${{ github.repository }}:ci-${{ github.run_id }} jobs: prepare: name: 'Prepare E2E' if: ${{ !github.event.pull_request.head.repo.fork }} runs-on: blacksmith-4vcpu-ubuntu-2204 permissions: packages: write contents: read outputs: matrix: ${{ steps.generate-matrix.outputs.matrix }} skip-tests: ${{ steps.generate-matrix.outputs.skip-tests }} steps: - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ inputs.branch || github.ref }} fetch-depth: 1 - name: Login to GHCR uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push to GHCR uses: ./.github/actions/setup-nodejs with: build-command: 'pnpm build:docker' enable-docker-cache: true env: INCLUDE_TEST_CONTROLLER: 'true' IMAGE_BASE_NAME: ghcr.io/${{ github.repository }} IMAGE_TAG: ci-${{ github.run_id }} RUNNERS_IMAGE_BASE_NAME: ghcr.io/${{ github.repository_owner }}/runners BUILD_STATS_WEBHOOK_URL: ${{ secrets.BUILD_STATS_WEBHOOK_URL }} BUILD_STATS_WEBHOOK_USER: ${{ secrets.BUILD_STATS_WEBHOOK_USER }} BUILD_STATS_WEBHOOK_PASSWORD: ${{ secrets.BUILD_STATS_WEBHOOK_PASSWORD }} DOCKER_STATS_WEBHOOK_URL: ${{ secrets.DOCKER_STATS_WEBHOOK_URL }} - name: Get changed files for impact analysis if: ${{ inputs.playwright-only }} id: changed-files run: | git fetch --depth=1 origin ${{ github.event.pull_request.base.ref || 'master' }} echo "list=$(git diff --name-only FETCH_HEAD HEAD | tr '\n' ',' | sed 's/,$//')" >> "$GITHUB_OUTPUT" - name: Generate shard matrix id: generate-matrix env: CHANGED_FILES: ${{ steps.changed-files.outputs.list }} run: | ARGS=(--matrix 16 --orchestrate) if [[ "${{ inputs.playwright-only }}" == "true" ]]; then ARGS+=(--impact "--files=$CHANGED_FILES") fi MATRIX=$(node packages/testing/playwright/scripts/distribute-tests.mjs "${ARGS[@]}") echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT" echo "skip-tests=$(node -e "process.stdout.write(JSON.parse(process.argv[1])[0]?.skip === true ? 'true' : 'false')" "$MATRIX")" >> "$GITHUB_OUTPUT" sqlite-sanity: needs: [prepare] name: 'SQLite: Sanity Check' if: ${{ !github.event.pull_request.head.repo.fork }} uses: ./.github/workflows/test-e2e-reusable.yml with: branch: ${{ inputs.branch }} test-mode: docker-pull docker-image: ghcr.io/${{ github.repository }}:ci-${{ github.run_id }} test-command: pnpm --filter=n8n-playwright test:container:sqlite:e2e tests/e2e/building-blocks/workflow-entry-points.spec.ts shards: 1 runner: blacksmith-2vcpu-ubuntu-2204 workers: '1' pre-generated-matrix: '[{"shard":1,"images":""}]' # Multi-main: postgres + redis + caddy + 2 mains + 1 worker # Only runs for internal PRs (not community/fork PRs) # Pulls pre-built Docker image from GHCR multi-main-e2e: needs: [prepare] name: 'Multi-Main: E2E' if: ${{ !github.event.pull_request.head.repo.fork && needs.prepare.outputs.skip-tests != 'true' }} uses: ./.github/workflows/test-e2e-reusable.yml with: branch: ${{ inputs.branch }} test-mode: docker-pull docker-image: ghcr.io/${{ github.repository }}:ci-${{ github.run_id }} test-command: pnpm --filter=n8n-playwright test:container:multi-main:e2e shards: 16 runner: blacksmith-2vcpu-ubuntu-2204 workers: '1' use-custom-orchestration: true pre-generated-matrix: ${{ needs.prepare.outputs.matrix }} secrets: inherit # Community PR tests: Local mode with SQLite (no container building, no secrets required) # Runs on GitHub-hosted runners without Currents reporting community-e2e: name: 'Community: E2E' if: ${{ github.event.pull_request.head.repo.fork }} uses: ./.github/workflows/test-e2e-reusable.yml with: branch: ${{ inputs.branch }} test-mode: local test-command: pnpm --filter=n8n-playwright test:local:e2e-only shards: 7 runner: ubuntu-latest workers: '1' upload-failure-artifacts: true # Cleanup ephemeral Docker image from GHCR after tests complete # Local runner cleanup is handled by each test shard in test-e2e-reusable.yml cleanup-ghcr: name: 'Cleanup GHCR Image' needs: [prepare, multi-main-e2e, sqlite-sanity] if: ${{ !failure() && !cancelled() && !github.event.pull_request.head.repo.fork }} runs-on: blacksmith-2vcpu-ubuntu-2204 permissions: packages: write contents: read steps: - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: sparse-checkout: .github/scripts sparse-checkout-cone-mode: false - name: Delete images from GHCR continue-on-error: true env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GHCR_ORG: ${{ github.repository_owner }} GHCR_REPO: ${{ github.event.repository.name }} run: node .github/scripts/cleanup-ghcr-images.mjs --tag ci-${{ github.run_id }}