Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/scripts/release-notes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,12 @@ if (!repoUrl) {
console.error('CHANGELOG.md needs a "[Unreleased]: <repo url>/compare/..." link ref at the bottom')
process.exit(1)
}
// The previous release is the next version heading down (the changelog is newest first).
const previous = /^## \[([^\]]+)\]/.exec(lines[end] ?? "")?.[1]
// The previous release is the next version heading down that has a tag (the changelog is newest first).
// A heading for a version that never shipped (its CI or Publish failed) has no tag, so it is skipped.
const previous = lines
.slice(end)
.map((l) => /^## \[([^\]]+)\]/.exec(l)?.[1])
.find((v): v is string => v !== undefined && v !== "Unreleased" && refExists(`v${v}`))

// Before the tag exists (a dry run from main) the commits are the ones on HEAD.
const tag = `v${version}`
Expand Down
14 changes: 12 additions & 2 deletions .github/scripts/release.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync
import { tmpdir } from "node:os"
import { join } from "node:path"
import semver from "semver"
import { changelogBlock, collectCommits } from "./commit-detail.ts"
import { changelogBlock, collectCommits, refExists } from "./commit-detail.ts"
import { approvalState, judgeChecks, mergeRules, type CheckRow, type GhReview } from "./merge-gate.ts"
import { bumpInstallPins, replaceSinceNext } from "./since-next.ts"

Expand Down Expand Up @@ -516,7 +516,17 @@ const docRewrites = ["README.md", ...[...new Bun.Glob("docs/**/*.md").scanSync("
const linkAt = lines.findIndex((l) => l.startsWith("[Unreleased]: "))
const link = /^\[Unreleased\]: (.+)\/compare\/v(.+)\.\.\.HEAD$/.exec(lines[linkAt] ?? "")
if (!link) fail('CHANGELOG.md needs a "[Unreleased]: <repo url>/compare/v<previous>...HEAD" link ref at the bottom')
const [, repoUrl, previous] = link
const [, repoUrl, linkedPrevious] = link
// The link names the last version the changelog saw, but an unpublished version (a release whose CI or
// Publish failed) leaves a heading and link for a tag that does not exist, and the next release then fails
// on `git log v<that>..HEAD`. So the previous version is the newest tag that exists below this release.
const previous = refExists(`v${linkedPrevious}`)
? linkedPrevious
: git("tag", "--list", "v*", "--sort=-v:refname")
.split("\n")
.map((t) => t.slice(1))
.find((v) => semver.valid(v) && semver.lt(v, version))
if (!previous) fail(`no release tag below ${version} exists, and CHANGELOG.md links v${linkedPrevious}, which is not a tag`)
if (!semver.gt(version, previous)) fail(`${version} does not increase on the last released version ${previous}`)

// The commit-level detail: every commit since the previous tag, grouped by type, in a
Expand Down
Loading