[pull] main from facebook:main #955
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Lexical Tests (Extended) | |
| on: | |
| pull_request: | |
| types: [labeled, synchronize, reopened] | |
| paths-ignore: | |
| - 'packages/lexical-website/**' | |
| - 'packages/*/README.md' | |
| pull_request_review: | |
| types: [submitted] | |
| permissions: | |
| pull-requests: read | |
| actions: read | |
| concurrency: | |
| # Only cancel an in-progress run when a newer commit lands on the same ref. | |
| # Other events (labeled, reopened, review submitted) get a distinct group so | |
| # they never cancel a run that is already underway. | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}-${{ github.event_name == 'pull_request' && github.event.action == 'synchronize' && 'synchronize' || github.run_id }} | |
| cancel-in-progress: true | |
| jobs: | |
| check_should_run: | |
| if: github.repository_owner == 'facebook' | |
| runs-on: ubuntu-latest | |
| outputs: | |
| should_run: ${{ steps.check.outputs.should_run }} | |
| steps: | |
| - id: check | |
| uses: actions/github-script@v9 | |
| with: | |
| script: | | |
| const pr = context.payload.pull_request; | |
| const labels = (pr.labels || []).map((l) => l.name); | |
| const gatingLabels = labels.filter( | |
| (l) => l === 'extended-tests' || l === 'dependencies', | |
| ); | |
| const isSync = | |
| context.eventName === 'pull_request' && | |
| context.payload.action === 'synchronize'; | |
| // ---- Gate ---------------------------------------------------------- | |
| let gateOpen = false; | |
| let gateReason = ''; | |
| if (gatingLabels.length > 0) { | |
| gateOpen = true; | |
| gateReason = `gating label present (${gatingLabels.join(', ')})`; | |
| } else if (context.eventName === 'pull_request_review') { | |
| const state = context.payload.review?.state; | |
| if (state === 'approved') { | |
| gateOpen = true; | |
| gateReason = 'review submitted as approved'; | |
| } else { | |
| gateReason = `review state is "${state}", not approved`; | |
| } | |
| } else { | |
| // pull_request synchronize/reopened with no gating label: open the | |
| // gate if the PR is currently approved. reviewDecision is | |
| // GraphQL-only. | |
| const { repository } = await github.graphql( | |
| `query($owner: String!, $repo: String!, $number: Int!) { | |
| repository(owner: $owner, name: $repo) { | |
| pullRequest(number: $number) { reviewDecision } | |
| } | |
| }`, | |
| { owner: context.repo.owner, repo: context.repo.repo, number: pr.number }, | |
| ); | |
| const decision = repository.pullRequest.reviewDecision; | |
| if (decision === 'APPROVED') { | |
| gateOpen = true; | |
| gateReason = 'no gating label; PR reviewDecision is APPROVED'; | |
| } else { | |
| gateReason = `no gating label; PR reviewDecision is ${decision ?? 'null'}`; | |
| } | |
| } | |
| const summarize = async (verdict, detail) => { | |
| const label = verdict ? 'Running' : 'Skipped'; | |
| core.summary | |
| .addHeading('Extended tests gate', 3) | |
| .addRaw(`**${label}** — ${detail}`, true) | |
| .addBreak() | |
| .addRaw( | |
| `Event: \`${context.eventName}\`` + | |
| (context.payload.action ? ` (\`${context.payload.action}\`)` : '') + | |
| `, head SHA: \`${pr.head.sha.slice(0, 7)}\``, | |
| true, | |
| ); | |
| await core.summary.write(); | |
| core.info(`should_run=${verdict}: ${detail}`); | |
| core.setOutput('should_run', verdict ? 'true' : 'false'); | |
| }; | |
| if (!gateOpen) { | |
| await summarize(false, gateReason); | |
| return; | |
| } | |
| // ---- New commit always runs --------------------------------------- | |
| if (isSync) { | |
| await summarize( | |
| true, | |
| `${gateReason}. New commit — always runs the extended suite.`, | |
| ); | |
| return; | |
| } | |
| // ---- Metadata event: only run if tests haven't already started ---- | |
| // For labeled / reopened / review submitted, defer to any prior run | |
| // of this workflow on the same head SHA that already kicked off (or | |
| // completed) the extended test jobs. A prior run that only executed | |
| // check_should_run (gate closed at the time) doesn't count — its | |
| // workflow conclusion is success even though no tests ran. | |
| const { data: runsData } = await github.rest.actions.listWorkflowRuns({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| workflow_id: 'tests-extended.yml', | |
| head_sha: pr.head.sha, | |
| per_page: 100, | |
| }); | |
| let blockingRun = null; | |
| for (const run of runsData.workflow_runs) { | |
| if (run.id === context.runId) continue; | |
| const completedOk = | |
| run.status === 'completed' && run.conclusion === 'success'; | |
| const active = | |
| run.status === 'in_progress' || run.status === 'queued'; | |
| if (!completedOk && !active) continue; | |
| const { data: jobsData } = | |
| await github.rest.actions.listJobsForWorkflowRun({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| run_id: run.id, | |
| per_page: 100, | |
| }); | |
| const ranTests = jobsData.jobs.some( | |
| (j) => | |
| j.name !== 'check_should_run' && | |
| (j.conclusion === 'success' || | |
| j.status === 'in_progress' || | |
| j.status === 'queued'), | |
| ); | |
| if (ranTests) { | |
| blockingRun = run; | |
| break; | |
| } | |
| } | |
| if (blockingRun) { | |
| const state = | |
| blockingRun.status === 'completed' | |
| ? 'completed successfully' | |
| : 'already in progress'; | |
| await summarize( | |
| false, | |
| `${gateReason}, but extended tests are ${state} for this SHA in ` + | |
| `[run #${blockingRun.id}](${blockingRun.html_url}). ` + | |
| `Metadata events only restart tests when none have run yet.`, | |
| ); | |
| return; | |
| } | |
| await summarize( | |
| true, | |
| `${gateReason}. No prior run has executed the extended tests for this SHA.`, | |
| ); | |
| e2e-tests: | |
| needs: check_should_run | |
| if: needs.check_should_run.outputs.should_run == 'true' | |
| uses: ./.github/workflows/call-e2e-all-tests.yml | |
| integration-tests: | |
| needs: check_should_run | |
| if: needs.check_should_run.outputs.should_run == 'true' | |
| uses: ./.github/workflows/call-integration-tests.yml | |
| browser-tests: | |
| needs: check_should_run | |
| if: needs.check_should_run.outputs.should_run == 'true' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # Each combination is fully specified. ubuntu + chromium is already | |
| # covered by the default browser run in call-core-tests.yml, and WebKit | |
| # is only exercised on macOS, so neither is repeated here. | |
| include: | |
| - {os: 'ubuntu-latest', browser: 'firefox'} | |
| - {os: 'macos-latest', browser: 'chromium'} | |
| - {os: 'macos-latest', browser: 'firefox'} | |
| - {os: 'macos-latest', browser: 'webkit'} | |
| - {os: 'windows-2022', browser: 'chromium'} | |
| - {os: 'windows-2022', browser: 'firefox'} | |
| uses: ./.github/workflows/call-browser-tests.yml | |
| with: | |
| os: ${{ matrix.os }} | |
| node-version: '24.x' | |
| browser: ${{ matrix.browser }} |