(
releases: PlannedRelease[],
bumpFiles: BumpFile[],
rootDir: string,
opts: GitHubReleaseOptions = {},
)
| 46 | |
| 47 | /** Create individual GitHub releases for each published package */ |
| 48 | export async function createIndividualReleases( |
| 49 | releases: PlannedRelease[], |
| 50 | bumpFiles: BumpFile[], |
| 51 | rootDir: string, |
| 52 | opts: GitHubReleaseOptions = {}, |
| 53 | ): Promise<void> { |
| 54 | if (!isGhAvailable()) { |
| 55 | log.dim(' gh CLI not found — skipping GitHub releases'); |
| 56 | return; |
| 57 | } |
| 58 | |
| 59 | const headSha = getHeadSha(rootDir); |
| 60 | |
| 61 | for (const release of releases) { |
| 62 | const tag = `${release.name}@${release.newVersion}`; |
| 63 | const body = opts.formatter |
| 64 | ? await generateReleaseBody(release, bumpFiles, opts.formatter) |
| 65 | : buildReleaseBody(release, bumpFiles); |
| 66 | const title = `${release.name} v${release.newVersion}`; |
| 67 | |
| 68 | if (opts.dryRun) { |
| 69 | log.dim(` Would create GitHub release: ${title}`); |
| 70 | continue; |
| 71 | } |
| 72 | |
| 73 | try { |
| 74 | // Use --target so gh can create the tag on the remote if it wasn't pushed yet |
| 75 | const args = ['gh', 'release', 'create', tag, '--title', title, '--notes', body]; |
| 76 | // Mark prerelease versions so they never show as "latest" on GitHub |
| 77 | if (/-/.test(release.newVersion)) args.push('--prerelease'); |
| 78 | if (headSha) args.push('--target', headSha); |
| 79 | await withReleaseToken(() => runArgsAsync(args, { cwd: rootDir })); |
| 80 | log.dim(` Created GitHub release: ${title}`); |
| 81 | } catch (err) { |
| 82 | log.warn(` Failed to create GitHub release for ${tag}: ${err instanceof Error ? err.message : err}`); |
| 83 | } |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | /** Generate a release body for a single package using the changelog formatter */ |
| 88 | export async function generateReleaseBody( |
no test coverage detected
searching dependent graphs…