name: E2E on: push: branches: - "master" - "[0-9].[0-9]*" pull_request: types: [synchronize, opened, reopened, ready_for_review] workflow_dispatch: inputs: use_dashboard: description: "Use Cypress Dashboard (true/false) [paid service - trigger manually when needed]. You MUST provide a branch and/or PR number below for this to work." required: false default: "false" ref: description: "The branch or tag to checkout" required: false default: "" pr_id: description: "The pull request ID to checkout" required: false default: "" concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: changes: runs-on: ubuntu-24.04 timeout-minutes: 10 permissions: contents: read pull-requests: read outputs: python: ${{ steps.check.outputs.python }} frontend: ${{ steps.check.outputs.frontend }} steps: - name: Checkout uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false - name: Check for file changes id: check uses: ./.github/actions/change-detector/ with: token: ${{ secrets.GITHUB_TOKEN }} cypress-matrix: needs: changes if: needs.changes.outputs.python == 'true' || needs.changes.outputs.frontend == 'true' # Somehow one test flakes on 24.04 for unknown reasons, this is the only GHA left on 22.04 runs-on: ubuntu-22.04 timeout-minutes: 30 permissions: contents: read pull-requests: read strategy: # when one test fails, DO NOT cancel the other # parallel_id, because this will kill Cypress processes # leaving the Dashboard hanging ... # https://github.com/cypress-io/github-action/issues/48 fail-fast: false matrix: parallel_id: [0, 1] browser: ["chrome"] app_root: ${{ github.event_name == 'push' && fromJSON('["", "/app/prefix"]') || fromJSON('[""]') }} # The /app/prefix variant (push events only) is smoke-tested on a single # shard rather than the full matrix, so exclude it from the other shards. exclude: - parallel_id: 1 app_root: "/app/prefix" env: SUPERSET_ENV: development SUPERSET_CONFIG: tests.integration_tests.superset_test_config SUPERSET__SQLALCHEMY_DATABASE_URI: postgresql+psycopg2://superset:superset@127.0.0.1:15432/superset PYTHONPATH: ${{ github.workspace }} REDIS_PORT: 16379 GITHUB_TOKEN: ${{ github.token }} # Only use dashboard when explicitly requested via workflow_dispatch USE_DASHBOARD: ${{ github.event.inputs.use_dashboard == 'true' || 'false' }} services: postgres: image: postgres:17-alpine env: POSTGRES_USER: superset POSTGRES_PASSWORD: superset ports: - 15432:5432 redis: image: redis:7-alpine ports: - 16379:6379 steps: # ------------------------------------------------------- # Conditional checkout based on context - name: Checkout for push or pull_request event if: github.event_name == 'push' || github.event_name == 'pull_request' uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false submodules: recursive ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} - name: Checkout using ref (workflow_dispatch) if: github.event_name == 'workflow_dispatch' && github.event.inputs.ref != '' uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false ref: ${{ github.event.inputs.ref }} submodules: recursive - name: Checkout using PR ID (workflow_dispatch) if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_id != '' uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false ref: refs/pull/${{ github.event.inputs.pr_id }}/merge submodules: recursive # ------------------------------------------------------- - name: Setup Python uses: ./.github/actions/setup-backend/ - name: Setup postgres uses: ./.github/actions/cached-dependencies with: run: setup-postgres - name: Import test data uses: ./.github/actions/cached-dependencies with: run: testdata - name: Setup Node.js uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version-file: "./superset-frontend/.nvmrc" cache: "npm" cache-dependency-path: "superset-frontend/package-lock.json" - name: Install npm dependencies uses: ./.github/actions/cached-dependencies with: run: npm-install - name: Build javascript packages uses: ./.github/actions/cached-dependencies with: run: build-instrumented-assets - name: Install cypress uses: ./.github/actions/cached-dependencies with: run: cypress-install - name: Run Cypress uses: ./.github/actions/cached-dependencies env: CYPRESS_BROWSER: ${{ matrix.browser }} PARALLEL_ID: ${{ matrix.parallel_id }} PARALLELISM: 2 CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} NODE_OPTIONS: "--max-old-space-size=4096" with: run: cypress-run-all ${{ env.USE_DASHBOARD }} ${{ matrix.app_root }} - name: Set safe app root if: failure() id: set-safe-app-root env: APP_ROOT: ${{ matrix.app_root }} run: | SAFE_APP_ROOT=${APP_ROOT//\//_} echo "safe_app_root=$SAFE_APP_ROOT" >> $GITHUB_OUTPUT - name: Upload Artifacts uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 if: failure() with: path: ${{ github.workspace }}/superset-frontend/cypress-base/cypress/screenshots name: cypress-artifact-${{ github.run_id }}-${{ github.job }}-${{ matrix.browser }}-${{ matrix.parallel_id }}--${{ steps.set-safe-app-root.outputs.safe_app_root }} playwright-tests: needs: changes if: needs.changes.outputs.python == 'true' || needs.changes.outputs.frontend == 'true' runs-on: ubuntu-22.04 timeout-minutes: 30 permissions: contents: read pull-requests: read strategy: fail-fast: false matrix: browser: ["chromium"] app_root: ${{ github.event_name == 'push' && fromJSON('["", "/app/prefix"]') || fromJSON('[""]') }} env: SUPERSET_ENV: development SUPERSET_CONFIG: tests.integration_tests.superset_test_config SUPERSET__SQLALCHEMY_DATABASE_URI: postgresql+psycopg2://superset:superset@127.0.0.1:15432/superset PYTHONPATH: ${{ github.workspace }} REDIS_PORT: 16379 GITHUB_TOKEN: ${{ github.token }} services: postgres: image: postgres:17-alpine env: POSTGRES_USER: superset POSTGRES_PASSWORD: superset ports: - 15432:5432 redis: image: redis:7-alpine ports: - 16379:6379 steps: # ------------------------------------------------------- # Conditional checkout based on context (same as Cypress workflow) - name: Checkout for push or pull_request event if: github.event_name == 'push' || github.event_name == 'pull_request' uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false submodules: recursive ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} - name: Checkout using ref (workflow_dispatch) if: github.event_name == 'workflow_dispatch' && github.event.inputs.ref != '' uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false ref: ${{ github.event.inputs.ref }} submodules: recursive - name: Checkout using PR ID (workflow_dispatch) if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_id != '' uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false ref: refs/pull/${{ github.event.inputs.pr_id }}/merge submodules: recursive # ------------------------------------------------------- - name: Setup Python uses: ./.github/actions/setup-backend/ - name: Setup postgres uses: ./.github/actions/cached-dependencies with: run: setup-postgres - name: Import test data uses: ./.github/actions/cached-dependencies with: run: playwright_testdata - name: Setup Node.js uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version-file: "./superset-frontend/.nvmrc" cache: "npm" cache-dependency-path: "superset-frontend/package-lock.json" - name: Install npm dependencies uses: ./.github/actions/cached-dependencies with: run: npm-install - name: Build javascript packages uses: ./.github/actions/cached-dependencies with: run: build-instrumented-assets - name: Build embedded SDK uses: ./.github/actions/cached-dependencies with: run: build-embedded-sdk - name: Install Playwright uses: ./.github/actions/cached-dependencies with: run: playwright-install - name: Run Playwright (Required Tests) uses: ./.github/actions/cached-dependencies env: NODE_OPTIONS: "--max-old-space-size=4096" with: run: playwright-run "${{ matrix.app_root }}" - name: Set safe app root if: failure() id: set-safe-app-root env: APP_ROOT: ${{ matrix.app_root }} run: | SAFE_APP_ROOT=${APP_ROOT//\//_} echo "safe_app_root=$SAFE_APP_ROOT" >> $GITHUB_OUTPUT - name: Upload Playwright Artifacts uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 if: failure() with: path: | ${{ github.workspace }}/superset-frontend/playwright-results/ ${{ github.workspace }}/superset-frontend/test-results/ name: playwright-artifact-${{ github.run_id }}-${{ github.job }}-${{ matrix.browser }}--${{ steps.set-safe-app-root.outputs.safe_app_root }} # Stable required-status-check anchors. cypress-matrix and playwright-tests # are matrix jobs gated on change detection (python || frontend). On a PR # that touches neither — e.g. a docs-only PR — they are skipped at the job # level, which happens before matrix expansion, so the per-combination # contexts (`cypress-matrix (0, chrome)`, `playwright-tests (chromium)`) are # never produced and branch protection waits on them forever. These # always-running jobs report a single stable context that passes when the # underlying matrix job succeeded or was skipped, and fails only on a real # failure. Require these in .asf.yaml instead of the matrix-expanded names. # # A matrix job reads as "skipped" in two distinct cases, and only the first # is a legitimate pass: (a) change detection succeeded and gated the job off # (docs-only PR); (b) the `changes` job itself failed or was cancelled, in # which case GHA skips its dependents too. Accepting (b) would let a broken # change-detector report a false green, so each anchor first requires # `changes` to have succeeded before honouring a skip. cypress-matrix-required: needs: [changes, cypress-matrix] if: always() runs-on: ubuntu-24.04 timeout-minutes: 5 permissions: {} steps: - name: Check cypress-matrix result env: CHANGES: ${{ needs.changes.result }} RESULT: ${{ needs.cypress-matrix.result }} run: | if [ "$CHANGES" != "success" ]; then echo "change detection did not succeed (result: $CHANGES); refusing to pass on a skipped matrix" exit 1 fi if [ "$RESULT" != "success" ] && [ "$RESULT" != "skipped" ]; then echo "cypress-matrix did not pass (result: $RESULT)" exit 1 fi echo "cypress-matrix result: $RESULT (changes: $CHANGES)" playwright-tests-required: needs: [changes, playwright-tests] if: always() runs-on: ubuntu-24.04 timeout-minutes: 5 permissions: {} steps: - name: Check playwright-tests result env: CHANGES: ${{ needs.changes.result }} RESULT: ${{ needs.playwright-tests.result }} run: | if [ "$CHANGES" != "success" ]; then echo "change detection did not succeed (result: $CHANGES); refusing to pass on a skipped matrix" exit 1 fi if [ "$RESULT" != "success" ] && [ "$RESULT" != "skipped" ]; then echo "playwright-tests did not pass (result: $RESULT)" exit 1 fi echo "playwright-tests result: $RESULT (changes: $CHANGES)"