1#!/usr/bin/env bun
2/**
3 * Prepend release notes for a tag to CHANGELOG.md. Idempotent: if the tag
4 * already appears as a heading in CHANGELOG.md, does nothing.
5 *
6 * Usage: bun release-notes.ts v2.0.0-beta.13
7 *
8 * Reads ALCHEMY_REPO for the GitHub repo to query commits/authors from.
9 */
10import { $ } from "bun";
11import { generate } from "./changelog.ts";
12import { readFile, writeFile } from "node:fs/promises";
13import { join } from "node:path";
14import { repo } from "./config.ts";
15import { renderMarkdown } from "./render.ts";
16
17const tag = process.argv[2];
18if (!tag) {
19 console.error("Usage: bun release-notes.ts <tag>");
20 process.exit(1);
21}
22
23const changelogPath = join(process.cwd(), "CHANGELOG.md");
24const existing = await readFile(changelogPath, "utf-8").catch((e) => {
25 if ((e as NodeJS.ErrnoException).code === "ENOENT") return "";
26 throw e;
27});
28if (existing.includes(`## ${tag}\n`)) {
29 console.log(`${tag} already in CHANGELOG.md, skipping`);
30 process.exit(0);
31}
32
33const tagExists =
34 (await $`git rev-parse --verify ${`refs/tags/${tag}`}`.nothrow().quiet())
35 .exitCode === 0;
36const toRev = tagExists ? tag : "HEAD";
37
38console.log(`Generating release notes for ${tag} (using ${toRev})`);
39const { commits, config } = await generate({
40 to: toRev,
41 emoji: true,
42 contributors: true,
43 repo: repo(),
44});
45
46const md = renderMarkdown(commits, config);
47
48await writeFile(changelogPath, `## ${tag}\n\n${md}\n\n---\n\n${existing}`);