name: ci on: pull_request: types: - opened - reopened - synchronize push: branches: - main concurrency: # -- group: ${{ github.workflow }}-${{ github.ref }}-${{ github.ref_protected && github.sha || ''}} cancel-in-progress: true env: DO_NOT_TRACK: 1 # Disable Turbopack telemetry NEXT_TELEMETRY_DISABLED: 1 # Disable Next telemetry jobs: changes: runs-on: ubuntu-24.04 permissions: pull-requests: read outputs: needs_build: ${{ steps.filter.outputs.needs_build }} needs_tests: ${{ steps.filter.outputs.needs_tests }} templates: ${{ steps.filter.outputs.templates }} steps: # https://github.com/actions/virtual-environments/issues/1187 - name: tune linux network run: sudo ethtool -K eth0 tx off rx off - uses: actions/checkout@v4 - uses: dorny/paths-filter@v3 id: filter with: filters: | needs_build: - '.github/workflows/main.yml' - 'packages/**' - 'test/**' - 'pnpm-lock.yaml' - 'package.json' - 'templates/**' needs_tests: - '.github/workflows/main.yml' - 'packages/**' - 'test/**' - 'pnpm-lock.yaml' - 'package.json' templates: - 'templates/**' - name: Log all filter results run: | echo "needs_build: ${{ steps.filter.outputs.needs_build }}" echo "needs_tests: ${{ steps.filter.outputs.needs_tests }}" echo "templates: ${{ steps.filter.outputs.templates }}" lint: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Node setup uses: ./.github/actions/setup - name: Lint run: pnpm lint -- --quiet build: needs: changes if: ${{ needs.changes.outputs.needs_build == 'true' }} runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - name: Node setup uses: ./.github/actions/setup - run: pnpm run build:all env: DO_NOT_TRACK: 1 # Disable Turbopack telemetry - name: Cache build uses: actions/cache@v4 with: path: ./* key: ${{ github.sha }}-${{ github.run_number }} tests-unit: runs-on: ubuntu-24.04 needs: [changes, build] if: ${{ needs.changes.outputs.needs_tests == 'true' }} steps: - uses: actions/checkout@v4 - name: Node setup uses: ./.github/actions/setup with: pnpm-run-install: false pnpm-restore-cache: false # Full build is restored below - name: Restore build uses: actions/cache@v4 with: path: ./* key: ${{ github.sha }}-${{ github.run_number }} - name: Unit Tests run: pnpm test:unit env: NODE_OPTIONS: --max-old-space-size=8096 tests-types: runs-on: ubuntu-24.04 needs: [changes, build] if: ${{ needs.changes.outputs.needs_tests == 'true' }} steps: - uses: actions/checkout@v4 - name: Node setup uses: ./.github/actions/setup with: pnpm-run-install: false pnpm-restore-cache: false # Full build is restored below - name: Restore build uses: actions/cache@v4 with: path: ./* key: ${{ github.sha }}-${{ github.run_number }} - name: Types Tests run: pnpm test:types --target '>=5.7' env: NODE_OPTIONS: --max-old-space-size=8096 tests-int: runs-on: ubuntu-24.04 needs: [changes, build] if: ${{ needs.changes.outputs.needs_tests == 'true' }} name: int-${{ matrix.database }} timeout-minutes: 45 strategy: fail-fast: false matrix: database: - mongodb - firestore - postgres - postgres-custom-schema - postgres-uuid - supabase - sqlite - sqlite-uuid env: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: payloadtests AWS_ENDPOINT_URL: http://127.0.0.1:4566 AWS_ACCESS_KEY_ID: localstack AWS_SECRET_ACCESS_KEY: localstack AWS_REGION: us-east-1 services: postgres: # Custom postgres 17 docker image that supports both pg-vector and postgis: https://github.com/payloadcms/postgis-vector image: ${{ (startsWith(matrix.database, 'postgres') ) && 'ghcr.io/payloadcms/postgis-vector:latest' || '' }} env: # must specify password for PG Docker container image, see: https://registry.hub.docker.com/_/postgres?tab=description&page=1&name=10 POSTGRES_USER: ${{ env.POSTGRES_USER }} POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }} POSTGRES_DB: ${{ env.POSTGRES_DB }} ports: - 5432:5432 # needed because the postgres container does not provide a healthcheck options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - uses: actions/checkout@v4 - name: Node setup uses: ./.github/actions/setup with: pnpm-run-install: false pnpm-restore-cache: false # Full build is restored below - name: Restore build uses: actions/cache@v4 with: path: ./* key: ${{ github.sha }}-${{ github.run_number }} - name: Start LocalStack run: pnpm docker:start - name: Install Supabase CLI uses: supabase/setup-cli@v1 with: version: latest if: matrix.database == 'supabase' - name: Initialize Supabase run: | supabase init supabase start if: matrix.database == 'supabase' - name: Configure PostgreSQL run: | psql "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" -c "CREATE ROLE runner SUPERUSER LOGIN;" psql "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" -c "SELECT version();" echo "POSTGRES_URL=postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" >> $GITHUB_ENV if: startsWith(matrix.database, 'postgres') - name: Configure PostgreSQL with custom schema run: | psql "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" -c "CREATE SCHEMA custom;" if: matrix.database == 'postgres-custom-schema' - name: Configure Supabase run: | echo "POSTGRES_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres" >> $GITHUB_ENV if: matrix.database == 'supabase' - name: Integration Tests run: pnpm test:int env: NODE_OPTIONS: --max-old-space-size=8096 PAYLOAD_DATABASE: ${{ matrix.database }} POSTGRES_URL: ${{ env.POSTGRES_URL }} tests-e2e: runs-on: ubuntu-24.04 needs: [changes, build] if: ${{ needs.changes.outputs.needs_tests == 'true' }} name: e2e-${{ matrix.suite }} timeout-minutes: 45 strategy: fail-fast: false matrix: # find test -type f -name 'e2e.spec.ts' | sort | xargs dirname | xargs -I {} basename {} suite: - _community - access-control - admin__e2e__general - admin__e2e__list-view - admin__e2e__document-view - admin-bar - admin-root - auth - auth-basic - bulk-edit - joins - field-error-states - fields-relationship - fields__collections__Array - fields__collections__Blocks - fields__collections__Blocks#config.blockreferences.ts - fields__collections__Checkbox - fields__collections__Collapsible - fields__collections__ConditionalLogic - fields__collections__CustomID - fields__collections__Date - fields__collections__Email - fields__collections__Indexed - fields__collections__JSON - fields__collections__Number - fields__collections__Point - fields__collections__Radio - fields__collections__Relationship - fields__collections__Row - fields__collections__Select - fields__collections__Tabs - fields__collections__Tabs2 - fields__collections__Text - fields__collections__UI - fields__collections__Upload - group-by - folders - hooks - lexical__collections__Lexical__e2e__main - lexical__collections__Lexical__e2e__blocks - lexical__collections__Lexical__e2e__blocks#config.blockreferences.ts - lexical__collections__RichText - query-presets - form-state - live-preview - localization - locked-documents - i18n - plugin-cloud-storage - plugin-form-builder - plugin-import-export - plugin-multi-tenant - plugin-nested-docs - plugin-seo - sort - trash - versions - uploads env: SUITE_NAME: ${{ matrix.suite }} steps: - uses: actions/checkout@v4 - name: Node setup uses: ./.github/actions/setup with: pnpm-run-install: false pnpm-restore-cache: false # Full build is restored below - name: Restore build uses: actions/cache@v4 with: path: ./* key: ${{ github.sha }}-${{ github.run_number }} - name: Start LocalStack run: pnpm docker:start if: ${{ matrix.suite == 'plugin-cloud-storage' }} - name: Store Playwright's Version run: | # Extract the version number using a more targeted regex pattern with awk PLAYWRIGHT_VERSION=$(pnpm ls @playwright/test --depth=0 | awk '/@playwright\/test/ {print $2}') echo "Playwright's Version: $PLAYWRIGHT_VERSION" echo "PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION" >> $GITHUB_ENV - name: Cache Playwright Browsers for Playwright's Version id: cache-playwright-browsers uses: actions/cache@v4 with: path: ~/.cache/ms-playwright key: playwright-browsers-${{ env.PLAYWRIGHT_VERSION }} - name: Setup Playwright - Browsers and Dependencies if: steps.cache-playwright-browsers.outputs.cache-hit != 'true' run: pnpm exec playwright install --with-deps chromium - name: Setup Playwright - Dependencies-only if: steps.cache-playwright-browsers.outputs.cache-hit == 'true' run: pnpm exec playwright install-deps chromium - name: E2E Tests run: PLAYWRIGHT_JSON_OUTPUT_NAME=results_${{ matrix.suite }}.json pnpm test:e2e:prod:ci:noturbo ${{ matrix.suite }} env: PLAYWRIGHT_JSON_OUTPUT_NAME: results_${{ matrix.suite }}.json NEXT_TELEMETRY_DISABLED: 1 - uses: actions/upload-artifact@v4 if: always() with: name: test-results-${{ matrix.suite }} path: test/test-results/ if-no-files-found: ignore retention-days: 1 # Disabled until this is fixed: https://github.com/daun/playwright-report-summary/issues/156 # - uses: daun/playwright-report-summary@v3 # with: # report-file: results_${{ matrix.suite }}.json # report-tag: ${{ matrix.suite }} # job-summary: true # This is unused, keeping it here for reference and possibly enabling in the future tests-e2e-turbo: runs-on: ubuntu-24.04 needs: [changes, build] if: >- needs.changes.outputs.needs_tests == 'true' && ( contains(github.event.pull_request.labels.*.name, 'run-e2e-turbo') || github.event.label.name == 'run-e2e-turbo' ) name: e2e-turbo-${{ matrix.suite }} strategy: fail-fast: false matrix: # find test -type f -name 'e2e.spec.ts' | sort | xargs dirname | xargs -I {} basename {} suite: - _community - access-control - admin__e2e__general - admin__e2e__list-view - admin__e2e__document-view - admin-bar - admin-root - auth - auth-basic - bulk-edit - joins - field-error-states - fields-relationship - fields__collections__Array - fields__collections__Blocks - fields__collections__Blocks#config.blockreferences.ts - fields__collections__Checkbox - fields__collections__Collapsible - fields__collections__ConditionalLogic - fields__collections__CustomID - fields__collections__Date - fields__collections__Email - fields__collections__Indexed - fields__collections__JSON - fields__collections__Number - fields__collections__Point - fields__collections__Radio - fields__collections__Relationship - fields__collections__Row - fields__collections__Select - fields__collections__Tabs - fields__collections__Tabs2 - fields__collections__Text - fields__collections__UI - fields__collections__Upload - group-by - folders - hooks - lexical__collections__Lexical__e2e__main - lexical__collections__Lexical__e2e__blocks - lexical__collections__Lexical__e2e__blocks#config.blockreferences.ts - lexical__collections__RichText - query-presets - form-state - live-preview - localization - locked-documents - i18n - plugin-cloud-storage - plugin-form-builder - plugin-import-export - plugin-multi-tenant - plugin-nested-docs - plugin-seo - sort - trash - versions - uploads env: SUITE_NAME: ${{ matrix.suite }} steps: - uses: actions/checkout@v4 - name: Node setup uses: ./.github/actions/setup with: pnpm-run-install: false pnpm-restore-cache: false # Full build is restored below - name: Restore build uses: actions/cache@v4 with: path: ./* key: ${{ github.sha }}-${{ github.run_number }} - name: Start LocalStack run: pnpm docker:start if: ${{ matrix.suite == 'plugin-cloud-storage' }} - name: Store Playwright's Version run: | # Extract the version number using a more targeted regex pattern with awk PLAYWRIGHT_VERSION=$(pnpm ls @playwright/test --depth=0 | awk '/@playwright\/test/ {print $2}') echo "Playwright's Version: $PLAYWRIGHT_VERSION" echo "PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION" >> $GITHUB_ENV - name: Cache Playwright Browsers for Playwright's Version id: cache-playwright-browsers uses: actions/cache@v4 with: path: ~/.cache/ms-playwright key: playwright-browsers-${{ env.PLAYWRIGHT_VERSION }} - name: Setup Playwright - Browsers and Dependencies if: steps.cache-playwright-browsers.outputs.cache-hit != 'true' run: pnpm exec playwright install --with-deps chromium - name: Setup Playwright - Dependencies-only if: steps.cache-playwright-browsers.outputs.cache-hit == 'true' run: pnpm exec playwright install-deps chromium - name: E2E Tests run: PLAYWRIGHT_JSON_OUTPUT_NAME=results_${{ matrix.suite }}.json pnpm test:e2e:prod:ci ${{ matrix.suite }} env: PLAYWRIGHT_JSON_OUTPUT_NAME: results_${{ matrix.suite }}.json NEXT_TELEMETRY_DISABLED: 1 - uses: actions/upload-artifact@v4 if: always() with: name: test-results-turbo${{ matrix.suite }} path: test/test-results/ if-no-files-found: ignore retention-days: 1 # Disabled until this is fixed: https://github.com/daun/playwright-report-summary/issues/156 # - uses: daun/playwright-report-summary@v3 # with: # report-file: results_${{ matrix.suite }}.json # report-tag: ${{ matrix.suite }} # job-summary: true # Build listed templates with packed local packages and then runs their int and e2e tests build-and-test-templates: runs-on: ubuntu-24.04 needs: [changes, build] if: ${{ needs.changes.outputs.needs_build == 'true' }} name: build-template-${{ matrix.template }}-${{ matrix.database }} strategy: fail-fast: false matrix: include: - template: blank database: mongodb - template: website database: mongodb - template: with-payload-cloud database: mongodb - template: with-vercel-mongodb database: mongodb # Postgres - template: with-postgres database: postgres - template: with-vercel-postgres database: postgres - template: plugin # Re-enable once PG conncection is figured out # - template: with-vercel-website # database: postgres env: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: payloadtests MONGODB_VERSION: 6.0 steps: - uses: actions/checkout@v4 - name: Node setup uses: ./.github/actions/setup with: pnpm-run-install: false pnpm-restore-cache: false # Full build is restored below - name: Restore build uses: actions/cache@v4 with: path: ./* key: ${{ github.sha }}-${{ github.run_number }} - name: Start PostgreSQL uses: CasperWA/postgresql-action@v1.2 with: postgresql version: '14' # See https://hub.docker.com/_/postgres for available versions postgresql db: ${{ env.POSTGRES_DB }} postgresql user: ${{ env.POSTGRES_USER }} postgresql password: ${{ env.POSTGRES_PASSWORD }} if: matrix.database == 'postgres' - name: Wait for PostgreSQL run: sleep 30 if: matrix.database == 'postgres' - name: Configure PostgreSQL run: | psql "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" -c "CREATE ROLE runner SUPERUSER LOGIN;" psql "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" -c "SELECT version();" echo "POSTGRES_URL=postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" >> $GITHUB_ENV if: matrix.database == 'postgres' # Avoid dockerhub rate-limiting - name: Cache Docker images uses: ScribeMD/docker-cache@0.5.0 with: key: docker-${{ runner.os }}-mongo-${{ env.MONGODB_VERSION }} - name: Start MongoDB uses: supercharge/mongodb-github-action@1.12.0 with: mongodb-version: 6.0 if: matrix.database == 'mongodb' - name: Build Template run: | pnpm run script:pack --dest templates/${{ matrix.template }} pnpm run script:build-template-with-local-pkgs ${{ matrix.template }} $POSTGRES_URL env: NODE_OPTIONS: --max-old-space-size=8096 - name: Store Playwright's Version run: | # Extract the version number using a more targeted regex pattern with awk PLAYWRIGHT_VERSION=$(pnpm ls @playwright/test --depth=0 | awk '/@playwright\/test/ {print $2}') echo "Playwright's Version: $PLAYWRIGHT_VERSION" echo "PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION" >> $GITHUB_ENV - name: Cache Playwright Browsers for Playwright's Version id: cache-playwright-browsers uses: actions/cache@v4 with: path: ~/.cache/ms-playwright key: playwright-browsers-${{ env.PLAYWRIGHT_VERSION }} - name: Setup Playwright - Browsers and Dependencies if: steps.cache-playwright-browsers.outputs.cache-hit != 'true' run: pnpm exec playwright install --with-deps chromium - name: Setup Playwright - Dependencies-only if: steps.cache-playwright-browsers.outputs.cache-hit == 'true' run: pnpm exec playwright install-deps chromium - name: Runs Template Int Tests run: pnpm --filter ${{ matrix.template }} run test:int env: NODE_OPTIONS: --max-old-space-size=8096 PAYLOAD_DATABASE: ${{ matrix.database }} POSTGRES_URL: ${{ env.POSTGRES_URL }} MONGODB_URL: mongodb://localhost:27017/payloadtests - name: Runs Template E2E Tests run: PLAYWRIGHT_JSON_OUTPUT_NAME=results_${{ matrix.template }}.json pnpm --filter ${{ matrix.template }} test:e2e env: NODE_OPTIONS: --max-old-space-size=8096 PAYLOAD_DATABASE: ${{ matrix.database }} POSTGRES_URL: ${{ env.POSTGRES_URL }} MONGODB_URL: mongodb://localhost:27017/payloadtests NEXT_TELEMETRY_DISABLED: 1 tests-type-generation: runs-on: ubuntu-24.04 needs: [changes, build] if: ${{ needs.changes.outputs.needs_tests == 'true' }} steps: - uses: actions/checkout@v4 - name: Node setup uses: ./.github/actions/setup with: pnpm-run-install: false pnpm-restore-cache: false # Full build is restored below - name: Restore build uses: actions/cache@v4 with: path: ./* key: ${{ github.sha }}-${{ github.run_number }} - name: Generate Payload Types run: pnpm dev:generate-types fields - name: Generate GraphQL schema file run: pnpm dev:generate-graphql-schema graphql-schema-gen all-green: name: All Green if: always() runs-on: ubuntu-24.04 needs: - lint - build - build-and-test-templates - tests-unit - tests-int - tests-e2e - tests-types - tests-type-generation steps: - if: ${{ always() && (contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')) }} run: exit 1 publish-canary: name: Publish Canary runs-on: ubuntu-24.04 if: ${{ needs.all-green.result == 'success' && github.ref_name == 'main' }} needs: - all-green steps: # debug github.ref output - run: | echo github.ref: ${{ github.ref }} echo isV3: ${{ github.ref == 'refs/heads/main' }} analyze: runs-on: ubuntu-latest needs: [changes, build] timeout-minutes: 5 permissions: contents: read # for checkout repository actions: read # for fetching base branch bundle stats pull-requests: write # for comments steps: - uses: actions/checkout@v4 - name: Node setup uses: ./.github/actions/setup with: pnpm-run-install: false pnpm-restore-cache: false # Full build is restored below - name: Restore build uses: actions/cache@v4 with: path: ./* key: ${{ github.sha }}-${{ github.run_number }} - run: pnpm run build:bundle-for-analysis # Esbuild packages that haven't already been built in the build step for the purpose of analyzing bundle size env: DO_NOT_TRACK: 1 # Disable Turbopack telemetry - name: Analyze esbuild bundle size # Temporarily disable this for community PRs until this can be implemented in a separate workflow if: github.event.pull_request.head.repo.fork == false uses: exoego/esbuild-bundle-analyzer@v1 with: metafiles: 'packages/payload/meta_index.json,packages/payload/meta_shared.json,packages/ui/meta_client.json,packages/ui/meta_shared.json,packages/next/meta_index.json,packages/richtext-lexical/meta_client.json'