From 096a586b41236d54d61e5b59eeae7e2ef8e65d30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Thu, 24 Sep 2026 11:19:00 -0400 Subject: [PATCH] ci: editing a PR's text no longer cancels its running checks (#4420) * ci: editing a PR's text no longer cancels its running checks CI, regression and Windows render re-run on pull_request edited (for base changes) with cancel-in-progress, so a body or title edit cancelled the running checks and the fail-closed Test aggregator went red on the cancelled run. Only a push or a base change cancels now; a text edit queues behind the running run. * test(ci): read the workflows folder by path, not as a module URL Fallow treated new URL('../.github/workflows/', import.meta.url) as an unresolvable import. Use import.meta.dirname and join, as scripts/check-skill-mirror.mjs does. --- .github/workflows/ci.yml | 3 ++- .github/workflows/regression.yml | 3 ++- .github/workflows/windows-render.yml | 3 ++- package.json | 2 +- scripts/pr-edit-concurrency.test.mjs | 37 ++++++++++++++++++++++++++++ 5 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 scripts/pr-edit-concurrency.test.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d0e13fc70..aee9246356 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,8 @@ on: concurrency: group: ci-${{ github.ref }} - cancel-in-progress: true + # A body or title edit queues behind running checks instead of cancelling them. + cancel-in-progress: ${{ github.event.action != 'edited' || github.event.changes.base != null }} jobs: test-reachability: diff --git a/.github/workflows/regression.yml b/.github/workflows/regression.yml index 306c591818..a5b68b81e4 100644 --- a/.github/workflows/regression.yml +++ b/.github/workflows/regression.yml @@ -13,7 +13,8 @@ env: # SHA. Keep only the newest expensive regression run for each PR/ref. concurrency: group: regression-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true + # A body or title edit queues behind running checks instead of cancelling them. + cancel-in-progress: ${{ github.event.action != 'edited' || github.event.changes.base != null }} on: workflow_dispatch: diff --git a/.github/workflows/windows-render.yml b/.github/workflows/windows-render.yml index 339c2da21e..323ca8a975 100644 --- a/.github/workflows/windows-render.yml +++ b/.github/workflows/windows-render.yml @@ -34,7 +34,8 @@ on: concurrency: group: windows-render-${{ github.ref }} - cancel-in-progress: true + # A body or title edit queues behind running checks instead of cancelling them. + cancel-in-progress: ${{ github.event.action != 'edited' || github.event.changes.base != null }} jobs: changes: diff --git a/package.json b/package.json index 655634268c..9b599711f1 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "player:perf": "bun run --filter @hyperframes/player perf", "format:check": "oxfmt --check .", "knip": "knip", - "test:scripts": "node --import tsx --test scripts/animejs-v4-guidance.test.mjs scripts/check-tracked-artifacts.test.mjs scripts/check-registry-set-delta.test.mjs scripts/check-no-main-deletions.test.mjs scripts/check-pr-captures.test.mjs scripts/check-docs-snippet-motion.test.mjs scripts/registry-target-paths.test.mjs scripts/check-workspace-contracts.test.mjs scripts/check-media-use-copy-parity.test.mjs scripts/check-svg-sanitize-parity.test.mjs scripts/check-media-use-svg-sanitize-generated.test.mjs scripts/check-package-cycles.test.mjs scripts/check-cli-process-ownership.test.mjs scripts/check-large-files.test.mjs scripts/package-subpaths.test.mjs scripts/validate-release-channel.test.mjs scripts/publish-workflow.test.mjs scripts/install-workspace-dependencies.test.mjs scripts/draft-changelog.test.ts scripts/set-version.test.ts scripts/release-prepare.test.ts scripts/cli-options.test.ts scripts/changelog-weekly.test.ts scripts/claude-plugin-compression.test.ts scripts/catalog-payload-assets.test.ts scripts/host-registry-assets.test.ts scripts/catalog-preview-temp.test.ts scripts/catalog-hosted-files.test.ts scripts/player-cdn-pin.test.ts scripts/studio-runtime-smoke.test.mjs scripts/verify-packed-manifests.test.mjs scripts/lint-skills.test.mjs scripts/creator-editing-recipes.test.mjs packages/gcp-cloud-run/check-dockerfile-workspaces.test.mjs packages/core/scripts/writeGeneratedFile.test.ts scripts/catalog-publication.test.mjs scripts/ci/resolve-workflow-pr.test.mjs scripts/check-catalog-source-pr.test.mjs scripts/generate-registry-items.test.ts scripts/catalog-drift.test.ts scripts/catalog-fetch-mirror.test.ts scripts/catalog-script-inlining.test.ts scripts/catalog-detail.test.ts scripts/generate-catalog-pages.test.ts scripts/verify-catalog-payloads.test.ts scripts/registry-skill-files.test.ts scripts/creator-editing-capabilities.test.mjs scripts/generate-catalog-previews.test.ts scripts/registry-primitive-payloads.test.ts registry/components/pan-stations/pan-stations.test.mjs && vitest run scripts/catalog/ scripts/contrastRatchet.test.ts scripts/generate-catalog-payloads.test.ts", + "test:scripts": "node --import tsx --test scripts/animejs-v4-guidance.test.mjs scripts/check-tracked-artifacts.test.mjs scripts/check-registry-set-delta.test.mjs scripts/check-no-main-deletions.test.mjs scripts/check-pr-captures.test.mjs scripts/check-docs-snippet-motion.test.mjs scripts/registry-target-paths.test.mjs scripts/check-workspace-contracts.test.mjs scripts/check-media-use-copy-parity.test.mjs scripts/check-svg-sanitize-parity.test.mjs scripts/check-media-use-svg-sanitize-generated.test.mjs scripts/check-package-cycles.test.mjs scripts/check-cli-process-ownership.test.mjs scripts/check-large-files.test.mjs scripts/package-subpaths.test.mjs scripts/validate-release-channel.test.mjs scripts/publish-workflow.test.mjs scripts/pr-edit-concurrency.test.mjs scripts/install-workspace-dependencies.test.mjs scripts/draft-changelog.test.ts scripts/set-version.test.ts scripts/release-prepare.test.ts scripts/cli-options.test.ts scripts/changelog-weekly.test.ts scripts/claude-plugin-compression.test.ts scripts/catalog-payload-assets.test.ts scripts/host-registry-assets.test.ts scripts/catalog-preview-temp.test.ts scripts/catalog-hosted-files.test.ts scripts/player-cdn-pin.test.ts scripts/studio-runtime-smoke.test.mjs scripts/verify-packed-manifests.test.mjs scripts/lint-skills.test.mjs scripts/creator-editing-recipes.test.mjs packages/gcp-cloud-run/check-dockerfile-workspaces.test.mjs packages/core/scripts/writeGeneratedFile.test.ts scripts/catalog-publication.test.mjs scripts/ci/resolve-workflow-pr.test.mjs scripts/check-catalog-source-pr.test.mjs scripts/generate-registry-items.test.ts scripts/catalog-drift.test.ts scripts/catalog-fetch-mirror.test.ts scripts/catalog-script-inlining.test.ts scripts/catalog-detail.test.ts scripts/generate-catalog-pages.test.ts scripts/verify-catalog-payloads.test.ts scripts/registry-skill-files.test.ts scripts/creator-editing-capabilities.test.mjs scripts/generate-catalog-previews.test.ts scripts/registry-primitive-payloads.test.ts registry/components/pan-stations/pan-stations.test.mjs && vitest run scripts/catalog/ scripts/contrastRatchet.test.ts scripts/generate-catalog-payloads.test.ts", "typecheck:scripts": "tsc --noEmit -p scripts/tsconfig.json", "test:skills": "node --test 'skills/**/*.test.mjs' 'packages/cli/src/media-use/**/*.test.mjs'", "generate:previews": "tsx scripts/generate-template-previews.ts", diff --git a/scripts/pr-edit-concurrency.test.mjs b/scripts/pr-edit-concurrency.test.mjs new file mode 100644 index 0000000000..2b94b7dba6 --- /dev/null +++ b/scripts/pr-edit-concurrency.test.mjs @@ -0,0 +1,37 @@ +import assert from "node:assert/strict"; +import { readdirSync, readFileSync } from "node:fs"; +import { join } from "node:path"; +import test from "node:test"; +import { parse } from "yaml"; + +const workflowsDir = join(import.meta.dirname, "..", ".github", "workflows"); +const workflows = readdirSync(workflowsDir) + .filter((file) => file.endsWith(".yml")) + .map((file) => ({ file, config: parse(readFileSync(join(workflowsDir, file), "utf8")) })); + +// A body or title edit must not cancel in-flight code checks: the cancelled run's +// fail-closed `Test` stays red on the PR. Only a push or a base change cancels. +const CANCEL_UNLESS_PLAIN_EDIT = + "${{ github.event.action != 'edited' || github.event.changes.base != null }}"; +// Reads the PR body itself, so the newest edit should replace an older run. +const BODY_WORKFLOWS = new Set(["pr-captures.yml"]); + +const editedWorkflows = workflows.filter(({ config }) => + config.on?.pull_request?.types?.includes("edited"), +); + +test("the workflows that re-run on a PR edit are known", () => { + assert.deepEqual(editedWorkflows.map(({ file }) => file).sort(), [ + "ci.yml", + "pr-captures.yml", + "regression.yml", + "windows-render.yml", + ]); +}); + +for (const { file, config } of editedWorkflows) { + if (BODY_WORKFLOWS.has(file)) continue; + test(`${file}: a body or title edit does not cancel its running checks`, () => { + assert.equal(config.concurrency?.["cancel-in-progress"], CANCEL_UNLESS_PLAIN_EDIT); + }); +}