diff --git a/.github/MAINTAINERS.md b/.github/MAINTAINERS.md index e8321dd3b9..15ef191ead 100644 --- a/.github/MAINTAINERS.md +++ b/.github/MAINTAINERS.md @@ -48,6 +48,29 @@ function; create it once from **Issues → Labels** if it is missing. Applying `open-for-contribution` is currently a **manual step** — do it on the GitHub issue directly (from the GitHub UI, or from the Linear-linked issue). +## `run-ci`: full develop CI on stacked or draft PRs + +Ready (non-draft) PRs targeting `develop` already get the default suite: Test +(check / unit+integration / e2e), preview CLI packages, and PR-title lint. + +Stacked PRs (base is another PR branch) and drafts do **not** get that suite +unless they carry the **`run-ci`** label. [`run-ci.yml`](./workflows/run-ci.yml) +then calls Test and preview-package publish as reusable workflows, including +while the PR is still a draft. + +- Add `run-ci` to start (or resume) the suite; remove it to cancel in-progress + `run-ci` runs via that workflow's concurrency group. +- Other labels do not start or cancel Test / preview. PR-title lint may + retrigger because that check is cheap. +- After a stacked PR is retargeted onto `develop`, push or reopen so the + native required checks (`Check code quality`, etc.) populate. The opt-in + suite uses different check names (`Test / Check code quality`). +- This is independent of `run-live-e2e-ci`, which opts into the separate + supabox live e2e dispatch. + +The `run-ci` label must exist as a repository label; create it from +**Issues → Labels** if it is missing. + ## Deferred: automatic Linear → GitHub label sync We considered auto-applying `open-for-contribution` when a Linear issue moves out of diff --git a/.github/workflows/lint-pull-request.yml b/.github/workflows/lint-pull-request.yml index a2ba597315..c70377a830 100644 --- a/.github/workflows/lint-pull-request.yml +++ b/.github/workflows/lint-pull-request.yml @@ -2,6 +2,10 @@ name: Lint Pull Request # Release-notes PRs (head ref `release-notes/*`) skip CI; only # apply-release-notes.yml runs for those. +# +# Draft PRs skip this check unless they carry `run-ci` (same opt-in as Test +# and preview packages). Label events retrigger this cheap check so adding +# `run-ci` on a draft starts lint without waiting for a push. on: pull_request_target: types: @@ -10,6 +14,8 @@ on: - synchronize - reopened - ready_for_review + - labeled + - unlabeled merge_group: types: - checks_requested @@ -29,7 +35,8 @@ jobs: github.event_name == 'merge_group' || (github.event_name == 'pull_request_target' && !startsWith(github.event.pull_request.head.ref, 'release-notes/') && - github.event.pull_request.draft == false) + (github.event.pull_request.draft == false || + contains(github.event.pull_request.labels.*.name, 'run-ci'))) name: Lint Pull Request runs-on: ubuntu-latest steps: diff --git a/.github/workflows/publish-preview-cli-packages.yml b/.github/workflows/publish-preview-cli-packages.yml index afbc6ec537..5282341687 100644 --- a/.github/workflows/publish-preview-cli-packages.yml +++ b/.github/workflows/publish-preview-cli-packages.yml @@ -2,6 +2,9 @@ name: Publish Preview CLI Packages # Release-notes PRs (head ref `release-notes/*`) are markdown-only and are not # meant to produce installable preview packages. +# +# Default path: ready (non-draft) PRs targeting `develop`. +# `run-ci.yml` calls this workflow for drafts and stacked / non-develop PRs. on: pull_request: types: @@ -9,22 +12,35 @@ on: - synchronize - reopened - ready_for_review + - converted_to_draft branches: - develop + workflow_call: + inputs: + force: + description: Publish even when the PR is a draft (used by run-ci.yml) + type: boolean + default: false + secrets: + DF_FIREWALL_TOKEN: + required: true permissions: actions: read contents: read +# Literal prefix: called workflows inherit github.workflow from the caller +# (`run-ci`). `inputs.force` separates this call from a skipped native run on +# a develop draft. concurrency: - group: ${{ github.workflow }}-${{ github.head_ref }} + group: publish-preview-cli-packages.yml-${{ github.event.pull_request.number || github.head_ref }}-${{ inputs.force && 'run-ci' || 'direct' }} cancel-in-progress: true jobs: build: if: | !startsWith(github.head_ref, 'release-notes/') && - github.event.pull_request.draft == false + (inputs.force || github.event.pull_request.draft == false) name: Build preview CLI packages uses: ./.github/workflows/build-cli-artifacts.yml with: @@ -37,7 +53,7 @@ jobs: needs: build if: | !startsWith(github.head_ref, 'release-notes/') && - github.event.pull_request.draft == false && + (inputs.force || github.event.pull_request.draft == false) && needs.build.result == 'success' name: Publish preview package runs-on: blacksmith-8vcpu-ubuntu-2404 @@ -121,7 +137,7 @@ jobs: needs: publish if: | !startsWith(github.head_ref, 'release-notes/') && - github.event.pull_request.draft == false && + (inputs.force || github.event.pull_request.draft == false) && needs.publish.result == 'success' name: Post preview command comment runs-on: ubuntu-latest diff --git a/.github/workflows/run-ci.yml b/.github/workflows/run-ci.yml new file mode 100644 index 0000000000..c3dffb9788 --- /dev/null +++ b/.github/workflows/run-ci.yml @@ -0,0 +1,67 @@ +name: run-ci + +# Opt-in full develop CI for PRs that Test.yml / preview do not already cover: +# stacked PRs (base is not develop) and drafts. Ready develop PRs stay on the +# existing workflows so required check names and concurrency are unchanged. +# +# Add the `run-ci` label to start the suite; remove it to cancel in-progress +# runs via this workflow's concurrency group. Other labels do not retrigger. +on: + pull_request: + types: + - opened + - synchronize + - reopened + - ready_for_review + - labeled + - unlabeled + - converted_to_draft + +permissions: + actions: read + contents: read + pull-requests: write + +# Unrelated label events still start a run; give them a unique group so they +# cannot cancel an in-progress suite. Removing `run-ci` stays on the main +# group and cancels via cancel-in-progress. +concurrency: + group: >- + run-ci.yml-${{ github.event.pull_request.number || github.ref }}${{ + ((github.event.action == 'labeled' || github.event.action == 'unlabeled') + && github.event.label.name != 'run-ci' + && format('-noop-{0}', github.run_id)) + || '' + }} + cancel-in-progress: true + +jobs: + test: + name: Test + if: | + !startsWith(github.head_ref, 'release-notes/') && + contains(github.event.pull_request.labels.*.name, 'run-ci') && + (github.event.pull_request.draft || github.base_ref != 'develop') && + ((github.event.action != 'labeled' && + github.event.action != 'unlabeled') || + github.event.label.name == 'run-ci') + uses: ./.github/workflows/test.yml + with: + force: true + secrets: + DF_FIREWALL_TOKEN: ${{ secrets.DF_FIREWALL_TOKEN }} + + preview: + name: Preview packages + if: | + !startsWith(github.head_ref, 'release-notes/') && + contains(github.event.pull_request.labels.*.name, 'run-ci') && + (github.event.pull_request.draft || github.base_ref != 'develop') && + ((github.event.action != 'labeled' && + github.event.action != 'unlabeled') || + github.event.label.name == 'run-ci') + uses: ./.github/workflows/publish-preview-cli-packages.yml + with: + force: true + secrets: + DF_FIREWALL_TOKEN: ${{ secrets.DF_FIREWALL_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b0d4754442..daaf76f68d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,6 +2,9 @@ name: Test # Release-notes PRs (head ref `release-notes/*`) only add markdown under # `release-notes/` and are published via approval — skip the full CI suite. +# +# Default path: ready (non-draft) PRs targeting `develop`, plus the merge queue. +# `run-ci.yml` calls this workflow for drafts and stacked / non-develop PRs. on: pull_request: types: @@ -9,6 +12,7 @@ on: - synchronize - reopened - ready_for_review + - converted_to_draft branches: - develop merge_group: @@ -16,13 +20,26 @@ on: - checks_requested branches: - develop + workflow_call: + inputs: + force: + description: Run the suite even when the PR is a draft (used by run-ci.yml) + type: boolean + default: false + secrets: + DF_FIREWALL_TOKEN: + required: true permissions: contents: read actions: read +# Literal prefix: called workflows inherit github.workflow from the caller +# (`run-ci`), which would cancel the caller and the preview call. `inputs.force` +# keeps a skipped native Test run on a develop draft from cancelling the +# forced run-ci call. concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + group: test.yml-${{ github.event.pull_request.number || github.head_ref || github.ref }}-${{ inputs.force && 'run-ci' || 'direct' }} cancel-in-progress: true jobs: @@ -30,6 +47,7 @@ jobs: if: | !startsWith(github.head_ref, 'release-notes/') && (github.event_name == 'merge_group' || + inputs.force || github.event.pull_request.draft == false) name: Check code quality runs-on: blacksmith-8vcpu-ubuntu-2404 @@ -53,6 +71,7 @@ jobs: if: | !startsWith(github.head_ref, 'release-notes/') && (github.event_name == 'merge_group' || + inputs.force || github.event.pull_request.draft == false) name: Run unit and integration tests runs-on: blacksmith-8vcpu-ubuntu-2404 @@ -76,6 +95,7 @@ jobs: if: | !startsWith(github.head_ref, 'release-notes/') && (github.event_name == 'merge_group' || + inputs.force || github.event.pull_request.draft == false) name: Run end-to-end tests (shard ${{ matrix.shard }}/3) runs-on: blacksmith-8vcpu-ubuntu-2404 @@ -90,9 +110,18 @@ jobs: fetch-depth: 0 - name: Set base and head SHAs for affected - if: github.event_name == 'pull_request' + if: github.event.pull_request && !inputs.force uses: nrwl/nx-set-shas@afb73a62d26e41464e9254689e1fd6122ee683c1 # v5.0.1 + # Reusable calls inherit the caller's github context (event_name stays + # pull_request). Use the PR payload directly so we do not depend on + # nx-set-shas understanding the caller event. + - name: Set base and head SHAs for run-ci reusable call + if: inputs.force && github.event.pull_request + run: | + echo "NX_BASE=${{ github.event.pull_request.base.sha }}" >> "$GITHUB_ENV" + echo "NX_HEAD=${{ github.event.pull_request.head.sha }}" >> "$GITHUB_ENV" + - name: Set base and head SHAs for merge queue affected if: github.event_name == 'merge_group' run: | @@ -173,6 +202,7 @@ jobs: always() && !startsWith(github.head_ref, 'release-notes/') && (github.event_name == 'merge_group' || + inputs.force || github.event.pull_request.draft == false) name: Run end-to-end tests needs: test-e2e