From 1bb249a975dfaa2558155e80a5fa7a0b7106d5a7 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 22 Oct 2026 17:02:05 +0000 Subject: [PATCH 1/5] ci: skip CodeQL, release preview and title checks on the standing release PR Every merge to main updates release/next. Once those runs are approved, CodeQL analyses code main already scanned, and the release preview does a full-history checkout and builds every package before its CLI skips the standing PR. Each label change on the standing PR repeats the preview, and each edit of the PR repeats the title check, although releasekit writes that title. A diff of version bumps and changelogs gives none of them anything to find, and none is a required check. The repo check keeps a fork's release/next branch checked. CodeQL also had no concurrency group, so back-to-back pushes to main or a PR each ran a full analysis. Cancel the superseded run, as CI does: the newer run scans the latest code. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01HQN3v9Z4f1mu3xK4Z7K44e --- .github/workflows/codeql.yml | 7 +++++++ .github/workflows/pr-title.yml | 2 ++ .github/workflows/release-preview.yml | 2 ++ 3 files changed, 11 insertions(+) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index da3bed9f..2152878b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -8,9 +8,16 @@ on: schedule: - cron: '0 6 * * 1' # Weekly on Monday at 06:00 UTC +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: analyze: name: Analyze + # Not on the standing release PR (ci.standingPr.branch), which only bumps versions and changelogs. + # The repo check keeps a fork's branch of the same name scanned. + if: ${{ github.head_ref != 'release/next' || github.event.pull_request.head.repo.full_name != github.repository }} runs-on: ubuntu-latest permissions: security-events: write diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml index 77411a6e..0ab9fa33 100644 --- a/.github/workflows/pr-title.yml +++ b/.github/workflows/pr-title.yml @@ -12,6 +12,8 @@ permissions: jobs: validate: name: Validate PR Title + # releasekit writes the standing PR's (ci.standingPr.branch) title. + if: ${{ github.head_ref != 'release/next' || github.event.pull_request.head.repo.full_name != github.repository }} runs-on: ubuntu-latest steps: - uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6 diff --git a/.github/workflows/release-preview.yml b/.github/workflows/release-preview.yml index 59dba631..af901871 100644 --- a/.github/workflows/release-preview.yml +++ b/.github/workflows/release-preview.yml @@ -19,6 +19,8 @@ env: jobs: preview: name: Release Preview + # The preview CLI skips the standing PR (ci.standingPr.branch) itself, but only after a full checkout and build. + if: ${{ github.head_ref != 'release/next' || github.event.pull_request.head.repo.full_name != github.repository }} runs-on: ubuntu-latest steps: - name: Checkout From 0eac66e7b20b64bf9bf7fb8e56f8ffa0a31b3829 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 22 Oct 2026 19:59:50 +0000 Subject: [PATCH 2/5] ci(codeql): say what the repo check in the standing-PR guard prevents Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01HQN3v9Z4f1mu3xK4Z7K44e --- .github/workflows/codeql.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 2152878b..daa35dda 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -15,8 +15,8 @@ concurrency: jobs: analyze: name: Analyze - # Not on the standing release PR (ci.standingPr.branch), which only bumps versions and changelogs. - # The repo check keeps a fork's branch of the same name scanned. + # Skip the standing release PR (ci.standingPr.branch), which only bumps versions and changelogs. + # The repo check stops a fork from skipping the scan by naming its branch release/next. if: ${{ github.head_ref != 'release/next' || github.event.pull_request.head.repo.full_name != github.repository }} runs-on: ubuntu-latest permissions: From 20ec3e8f4475c0bb45a84803b3b705473e4bc798 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 22 Oct 2026 20:08:05 +0000 Subject: [PATCH 3/5] ci: fail when a workflow guard's branch drifts from ci.standingPr.branch The job guards hardcode release/next because if: can't read the config. pnpm workflows:check compares every github.head_ref literal with the configured branch (or the schema default) and runs in the Lint job. releasekit.config.json joins the infra filter so a config-only change still runs it. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01HQN3v9Z4f1mu3xK4Z7K44e --- .../workflows/_ci-detect-changes.reusable.yml | 1 + .github/workflows/ci.yml | 3 ++ package.json | 1 + scripts/check-workflow-guards.ts | 37 +++++++++++++++++++ 4 files changed, 42 insertions(+) create mode 100644 scripts/check-workflow-guards.ts diff --git a/.github/workflows/_ci-detect-changes.reusable.yml b/.github/workflows/_ci-detect-changes.reusable.yml index 765783e9..ebfe755c 100644 --- a/.github/workflows/_ci-detect-changes.reusable.yml +++ b/.github/workflows/_ci-detect-changes.reusable.yml @@ -84,6 +84,7 @@ jobs: - '.github/workflows/**' - '.github/actions/**' - 'package.json' + - 'releasekit.config.json' - 'pnpm-workspace.yaml' - 'pnpm-lock.yaml' - 'turbo.json' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 69a41edc..0ddb930f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -118,6 +118,9 @@ jobs: - name: Check generated config docs are up to date run: pnpm docs:check + - name: Check workflow guards match ci.standingPr.branch + run: pnpm workflows:check + typecheck: name: Typecheck needs: [detect-changes, build] diff --git a/package.json b/package.json index 4755b77b..6430fac7 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "schema:check": "tsx scripts/generate-schema.ts --check", "docs:config": "tsx scripts/generate-config-docs.ts", "docs:check": "tsx scripts/generate-config-docs.ts --check", + "workflows:check": "tsx scripts/check-workflow-guards.ts", "examples:smoke:generate": "tsx scripts/examples-smoke/generate-smoke-workflow.ts", "examples:smoke:check": "tsx scripts/examples-smoke/generate-smoke-workflow.ts --check", "prepare": "husky" diff --git a/scripts/check-workflow-guards.ts b/scripts/check-workflow-guards.ts new file mode 100644 index 00000000..05fb14ad --- /dev/null +++ b/scripts/check-workflow-guards.ts @@ -0,0 +1,37 @@ +#!/usr/bin/env tsx +/** + * Workflow `if` guards can't read releasekit.config.json, so they name the standing-PR branch as a + * literal. Fails when a `github.head_ref` comparison names any other branch than ci.standingPr.branch. + * Usage: pnpm workflows:check + */ + +import { readdirSync, readFileSync } from 'node:fs'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..'); +const WORKFLOWS_DIR = join(ROOT, '.github', 'workflows'); + +const config = JSON.parse(readFileSync(join(ROOT, 'releasekit.config.json'), 'utf8')); +const schema = JSON.parse(readFileSync(join(ROOT, 'releasekit.schema.json'), 'utf8')); +const branch: string = + config.ci?.standingPr?.branch ?? schema.properties.ci.properties.standingPr.properties.branch.default; + +const mismatches: string[] = []; +for (const file of readdirSync(WORKFLOWS_DIR).filter((name) => /\.ya?ml$/.test(name))) { + const lines = readFileSync(join(WORKFLOWS_DIR, file), 'utf8').split('\n'); + lines.forEach((line, index) => { + for (const [, literal] of line.matchAll(/github\.head_ref\s*[!=]=\s*'([^']*)'/g)) { + if (literal !== branch) { + mismatches.push(`.github/workflows/${file}:${index + 1} compares github.head_ref with '${literal}'`); + } + } + }); +} + +if (mismatches.length > 0) { + console.error(`ci.standingPr.branch is '${branch}', but:\n${mismatches.map((m) => ` ${m}`).join('\n')}`); + process.exit(1); +} + +console.log(`Workflow guards match ci.standingPr.branch ('${branch}').`); From 1ca824d5bbfefc25b83212aae11ab86c293e8601 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 22 Oct 2026 20:10:32 +0000 Subject: [PATCH 4/5] Revert "ci: fail when a workflow guard's branch drifts from ci.standingPr.branch" This reverts commit 20ec3e8f4475c0bb45a84803b3b705473e4bc798. --- .../workflows/_ci-detect-changes.reusable.yml | 1 - .github/workflows/ci.yml | 3 -- package.json | 1 - scripts/check-workflow-guards.ts | 37 ------------------- 4 files changed, 42 deletions(-) delete mode 100644 scripts/check-workflow-guards.ts diff --git a/.github/workflows/_ci-detect-changes.reusable.yml b/.github/workflows/_ci-detect-changes.reusable.yml index ebfe755c..765783e9 100644 --- a/.github/workflows/_ci-detect-changes.reusable.yml +++ b/.github/workflows/_ci-detect-changes.reusable.yml @@ -84,7 +84,6 @@ jobs: - '.github/workflows/**' - '.github/actions/**' - 'package.json' - - 'releasekit.config.json' - 'pnpm-workspace.yaml' - 'pnpm-lock.yaml' - 'turbo.json' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0ddb930f..69a41edc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -118,9 +118,6 @@ jobs: - name: Check generated config docs are up to date run: pnpm docs:check - - name: Check workflow guards match ci.standingPr.branch - run: pnpm workflows:check - typecheck: name: Typecheck needs: [detect-changes, build] diff --git a/package.json b/package.json index 6430fac7..4755b77b 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,6 @@ "schema:check": "tsx scripts/generate-schema.ts --check", "docs:config": "tsx scripts/generate-config-docs.ts", "docs:check": "tsx scripts/generate-config-docs.ts --check", - "workflows:check": "tsx scripts/check-workflow-guards.ts", "examples:smoke:generate": "tsx scripts/examples-smoke/generate-smoke-workflow.ts", "examples:smoke:check": "tsx scripts/examples-smoke/generate-smoke-workflow.ts --check", "prepare": "husky" diff --git a/scripts/check-workflow-guards.ts b/scripts/check-workflow-guards.ts deleted file mode 100644 index 05fb14ad..00000000 --- a/scripts/check-workflow-guards.ts +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env tsx -/** - * Workflow `if` guards can't read releasekit.config.json, so they name the standing-PR branch as a - * literal. Fails when a `github.head_ref` comparison names any other branch than ci.standingPr.branch. - * Usage: pnpm workflows:check - */ - -import { readdirSync, readFileSync } from 'node:fs'; -import { dirname, join, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..'); -const WORKFLOWS_DIR = join(ROOT, '.github', 'workflows'); - -const config = JSON.parse(readFileSync(join(ROOT, 'releasekit.config.json'), 'utf8')); -const schema = JSON.parse(readFileSync(join(ROOT, 'releasekit.schema.json'), 'utf8')); -const branch: string = - config.ci?.standingPr?.branch ?? schema.properties.ci.properties.standingPr.properties.branch.default; - -const mismatches: string[] = []; -for (const file of readdirSync(WORKFLOWS_DIR).filter((name) => /\.ya?ml$/.test(name))) { - const lines = readFileSync(join(WORKFLOWS_DIR, file), 'utf8').split('\n'); - lines.forEach((line, index) => { - for (const [, literal] of line.matchAll(/github\.head_ref\s*[!=]=\s*'([^']*)'/g)) { - if (literal !== branch) { - mismatches.push(`.github/workflows/${file}:${index + 1} compares github.head_ref with '${literal}'`); - } - } - }); -} - -if (mismatches.length > 0) { - console.error(`ci.standingPr.branch is '${branch}', but:\n${mismatches.map((m) => ` ${m}`).join('\n')}`); - process.exit(1); -} - -console.log(`Workflow guards match ci.standingPr.branch ('${branch}').`); From 3f6e1ddcfc1f4330c8e20e1c630c7f437a4fa9a5 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 22 Oct 2026 20:10:38 +0000 Subject: [PATCH 5/5] ci(codeql): don't name the branch in the guard comment Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01HQN3v9Z4f1mu3xK4Z7K44e --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index daa35dda..7e0c4b22 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -16,7 +16,7 @@ jobs: analyze: name: Analyze # Skip the standing release PR (ci.standingPr.branch), which only bumps versions and changelogs. - # The repo check stops a fork from skipping the scan by naming its branch release/next. + # The repo check stops a fork from skipping the scan with a branch of the same name. if: ${{ github.head_ref != 'release/next' || github.event.pull_request.head.repo.full_name != github.repository }} runs-on: ubuntu-latest permissions: