From 00e0f96465dfb71f69c17851c169b40d7ca0234b Mon Sep 17 00:00:00 2001 From: luvs01 Date: Fri, 28 Aug 2026 16:41:23 +0900 Subject: [PATCH] ci: fetch full history for version-line guard --- .github/workflows/ci.yml | 17 +++++++---------- tests/ci-workflows.test.ts | 14 ++++++-------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e3ca186bb3..573f160a8e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -272,11 +272,9 @@ jobs: # without this the check reads an empty tag set and passes on anything - # the exact regression it exists to catch would ride through CI green. # - # Tags only, not full history: `fetch-depth: 0` would clone every commit to - # answer a question about refs. A shallow fetch still brings each tag and its - # target commit, which is all the check reads - the tag list, and whether the - # newest tag names HEAD. That second read only happens on a release commit, - # where the tag points at HEAD and the commit is present by definition. + # `fetch-tags` does not fetch historical tags outside a shallow checkout's + # history, so the version-line guard needs the complete tag-bearing history. + fetch-depth: 0 fetch-tags: true - name: Setup project Bun @@ -470,11 +468,9 @@ jobs: # without this the check reads an empty tag set and passes on anything - # the exact regression it exists to catch would ride through CI green. # - # Tags only, not full history: `fetch-depth: 0` would clone every commit to - # answer a question about refs. A shallow fetch still brings each tag and its - # target commit, which is all the check reads - the tag list, and whether the - # newest tag names HEAD. That second read only happens on a release commit, - # where the tag points at HEAD and the commit is present by definition. + # `fetch-tags` does not fetch historical tags outside a shallow checkout's + # history, so the version-line guard needs the complete tag-bearing history. + fetch-depth: 0 fetch-tags: true - name: Setup project Bun @@ -612,6 +608,7 @@ jobs: # Same reason as the Linux shards and the macOS control: this leg runs the # whole suite, and tests/release-version-line.test.ts reads release tags. # Without tags the check sees an empty set and cannot fail. + fetch-depth: 0 fetch-tags: true - name: Setup project Bun diff --git a/tests/ci-workflows.test.ts b/tests/ci-workflows.test.ts index 8a70f4e675..aa879d4555 100644 --- a/tests/ci-workflows.test.ts +++ b/tests/ci-workflows.test.ts @@ -152,17 +152,15 @@ describe("GitHub Actions hardening", () => { expect(linuxShards).toEqual([1, 2, 3, 4]); expect(workflow).toContain(`--shard=\${{ matrix.shard }}/${linuxShards.length}`); - // Every job that runs tests/ must fetch tags, because one of those tests reads - // them. tests/release-version-line.test.ts compares package.json against the - // newest release tag, and actions/checkout brings no tags by default: git is - // present, `git tag --list` exits 0, and stdout is empty. The check then has an - // empty set, cannot fail, and a version regression rides through green. That is - // how the first cut of that test shipped, so pin the flag rather than trusting a - // comment. Asserted per job so a future edit cannot drop it from one leg while - // the other still carries it. + // Every job that runs tests/ must fetch full history and tags, because one of + // those tests reads release tags. `fetch-tags` alone does not fetch historical + // tags outside a shallow checkout, so `git tag --list` can still return an empty + // set and let a version regression ride through green. Assert both settings per + // job so a future edit cannot silently make the guard vacuous in one leg. for (const jobName of ["test", "platform-macos", "platform-windows"]) { const steps = (ci.jobs?.[jobName] as { steps?: Array<{ uses?: string; with?: Record }> })?.steps ?? []; const checkout = steps.find(step => typeof step.uses === "string" && step.uses.includes("actions/checkout")); + expect(`${jobName}:${String(checkout?.with?.["fetch-depth"])}`).toBe(`${jobName}:0`); expect(`${jobName}:${String(checkout?.with?.["fetch-tags"])}`).toBe(`${jobName}:true`); }