diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a7f56b1a..f556c9a78 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -649,6 +649,13 @@ jobs: with: bun-version: "1.3" - name: Generate release notes from CHANGELOGs + env: + # `gh release list` (used to find the latest published GitHub + # Release tag below the target so silent-tag changelog sections + # roll forward — #2596) requires GH_TOKEN in Actions. Without + # it gh exits non-zero and the script would degrade to legacy + # single-version notes, defeating the recovery. + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: bun scripts/ci-release-notes.ts ${{ needs.release_metadata.outputs.release-tag }} - name: Download release binaries uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 diff --git a/scripts/ci-release-notes.ts b/scripts/ci-release-notes.ts index 8e69ab781..7a663e9b8 100755 --- a/scripts/ci-release-notes.ts +++ b/scripts/ci-release-notes.ts @@ -188,13 +188,18 @@ async function loadPackageName(pkgDir: string): Promise { /** * Resolve the highest published, non-prerelease, non-draft semver tag strictly - * below `targetVersion`. Falls back to `null` on error or no candidate, which - * downgrades the script to legacy single-version extraction. + * below `targetVersion` via `gh release list`. * - * `OMP_RELEASE_NOTES_FLOOR` env override: - * - unset → query `gh` (CI default) - * - `vX.Y.Z` → use as-is (manual rerun: "I know the floor") - * - empty string → force single-version mode (legacy escape hatch) + * Failure semantics: + * - `OMP_RELEASE_NOTES_FLOOR` set → honored verbatim (`""` forces null). + * - `gh` succeeded, no candidate < target → `null` (legitimate first-ever + * publish; legacy single-version output is correct). + * - `gh` itself failed (missing binary, missing `GH_TOKEN` in Actions, + * network/auth error) → throws. Letting this degrade to single-version + * output silently re-strands silent-tag entries (#2596 review); the CI + * step must die loudly so the release is rebuilt with the token wired. + * Local runs without `gh` should set `OMP_RELEASE_NOTES_FLOOR=` to opt + * into legacy mode explicitly. */ async function resolvePublishedFloorTag(targetVersion: string): Promise { const override = process.env.OMP_RELEASE_NOTES_FLOOR; @@ -207,21 +212,22 @@ async function resolvePublishedFloorTag(targetVersion: string): Promise) .filter(t => t.isDraft !== true && t.isPrerelease !== true) .map(t => (typeof t.tagName === "string" ? t.tagName : ""))