From eb42e7677cdd4eee941f843d3654b3944f4dcce1 Mon Sep 17 00:00:00 2001 From: Theo Ephraim Date: Sun, 19 Apr 2026 23:38:01 -0700 Subject: [PATCH 1/2] Add thankContributors option to GitHub formatter and changelog docs page Add a `thankContributors` boolean option to the GitHub changelog formatter so contributor thanks messages can be disabled entirely. Also add a dedicated docs page covering all built-in formatters, their options, and custom formatter examples. Co-Authored-By: Claude Opus 4.6 (1M context) --- .bumpy/_changelog-formatter.ts | 39 ----- .bumpy/_config.json | 2 +- docs/changelog-formatters.md | 158 ++++++++++++++++++++ docs/configuration.md | 12 +- packages/bumpy/src/core/changelog-github.ts | 11 +- 5 files changed, 169 insertions(+), 53 deletions(-) delete mode 100644 .bumpy/_changelog-formatter.ts create mode 100644 docs/changelog-formatters.md diff --git a/.bumpy/_changelog-formatter.ts b/.bumpy/_changelog-formatter.ts deleted file mode 100644 index 7116e95..0000000 --- a/.bumpy/_changelog-formatter.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type { ChangelogFormatter } from '@varlock/bumpy'; - -const formatter: ChangelogFormatter = (ctx) => { - const { release, bumpFiles, date } = ctx; - const lines: string[] = []; - lines.push(`## 🐸 ${release.newVersion}`); - lines.push(''); - lines.push(`_${date}_`); - lines.push(''); - - const relevantBumpFiles = bumpFiles.filter((bf) => release.bumpFiles.includes(bf.id)); - - if (relevantBumpFiles.length > 0) { - for (const cs of relevantBumpFiles) { - if (cs.summary) { - const summaryLines = cs.summary.split('\n'); - lines.push(`- ${summaryLines[0]}`); - for (let i = 1; i < summaryLines.length; i++) { - if (summaryLines[i]!.trim()) { - lines.push(` ${summaryLines[i]}`); - } - } - } - } - } - - if (release.isDependencyBump && relevantBumpFiles.length === 0) { - lines.push('- Updated dependencies'); - } - - if (release.isCascadeBump && !release.isDependencyBump && relevantBumpFiles.length === 0) { - lines.push('- Version bump via cascade rule'); - } - - lines.push(''); - return lines.join('\n'); -}; - -export default formatter; diff --git a/.bumpy/_config.json b/.bumpy/_config.json index 6afd003..ff3ab0c 100644 --- a/.bumpy/_config.json +++ b/.bumpy/_config.json @@ -1,4 +1,4 @@ { "baseBranch": "main", - "changelog": "./_changelog-formatter.ts" + "changelog": ["github", { "internalAuthors": ["theoephraim", "philmillman"] }] } diff --git a/docs/changelog-formatters.md b/docs/changelog-formatters.md new file mode 100644 index 0000000..4fb263e --- /dev/null +++ b/docs/changelog-formatters.md @@ -0,0 +1,158 @@ +# Changelog Formatters + +Bumpy generates `CHANGELOG.md` entries automatically when releasing. + +There are several built-in formatters, or you can provide a custom function. + +## Built-in formatters + +### `default` + +Simple markdown formatter. Produces a version heading, date, and bullet points from bump file summaries. _This is the default -- no settting required to enable_. + +**Example output:** + +```markdown +## 1.2.0 + +_2026-04-19_ + +- Added support for custom themes +- Fixed a bug with config loading +``` + +No options are available for the default formatter. + +### `github` + +Enhanced formatter that adds PR links, commit links, and contributor attribution. Requires the `gh` CLI to be installed and authenticated. + +Enable in your `.bumpy/_config.json` using `"changelog": "github",` + +Or with options using a tuple format: + +```json +{ + "changelog": ["github", { "internalAuthors": ["username1"] }] +} +``` + +**Example output:** + +```markdown +## 1.2.0 + +_2026-04-19_ + +- [#42](https://github.com/myorg/myrepo/pull/42) [`abc1234`](https://github.com/myorg/myrepo/commit/abc1234) Thanks [@contributor](https://github.com/contributor)! - Added support for custom themes +- [#43](https://github.com/myorg/myrepo/pull/43) [`def5678`](https://github.com/myorg/myrepo/commit/def5678) - Fixed a bug with config loading +``` + +#### Options + +| Option | Type | Default | Description | +| ------------------- | ---------- | ------- | ----------------------------------------------------------------- | +| `repo` | `string` | — | `"owner/repo"` slug. Auto-detected from `gh` CLI if not provided. | +| `thankContributors` | `boolean` | `true` | Whether to include "Thanks @user" messages for contributors. | +| `internalAuthors` | `string[]` | `[]` | GitHub usernames (without `@`) to skip "Thanks" messages for. | + +#### Bump file metadata overrides + +The GitHub formatter also supports metadata lines in bump file summaries to override auto-detected values: + +```markdown +--- +'my-package': minor +--- + +pr: 42 +commit: abc1234 +author: @someuser + +Added support for custom themes +``` + +These overrides take precedence over git-derived info, which is useful when the automatic detection doesn't find the right PR or author. + +## Custom formatters + +You can write your own formatter as a TypeScript or JavaScript module. The module should export a `ChangelogFormatter` function as its default export. + +Create a file, for example `.bumpy/_changelog-formatter.ts`, and then reference it in your config: + +```json +{ + "changelog": "./.bumpy/_changelog-formatter.ts" +} +``` + +### Formatter interface + +```typescript +import type { ChangelogFormatter } from '@varlock/bumpy'; + +interface ChangelogContext { + release: PlannedRelease; + /** Bump files that contributed to this release */ + bumpFiles: BumpFile[]; + /** ISO date string (YYYY-MM-DD) */ + date: string; +} + +type ChangelogFormatter = (ctx: ChangelogContext) => string | Promise; +``` + +### Example: custom formatter + +```typescript +import type { ChangelogFormatter } from '@varlock/bumpy'; + +const formatter: ChangelogFormatter = (ctx) => { + const { release, bumpFiles, date } = ctx; + const lines: string[] = []; + lines.push(`## ${release.newVersion}`); + lines.push(''); + lines.push(`_${date}_`); + lines.push(''); + + const relevantBumpFiles = bumpFiles.filter((bf) => release.bumpFiles.includes(bf.id)); + + for (const bf of relevantBumpFiles) { + if (bf.summary) { + lines.push(`- ${bf.summary.split('\n')[0]}`); + } + } + + if (release.isDependencyBump && relevantBumpFiles.length === 0) { + lines.push('- Updated dependencies'); + } + + lines.push(''); + return lines.join('\n'); +}; + +export default formatter; +``` + +Custom formatters can also accept options. Export a factory function that returns a `ChangelogFormatter`: + +```typescript +import type { ChangelogFormatter } from '@varlock/bumpy'; + +export default function createFormatter(options: { emoji?: boolean }): ChangelogFormatter { + return (ctx) => { + const prefix = options.emoji ? '🚀 ' : ''; + const lines: string[] = []; + lines.push(`## ${prefix}${ctx.release.newVersion}`); + // ... rest of formatting + lines.push(''); + return lines.join('\n'); + }; +} +``` + +```json +{ + "changelog": ["./.bumpy/_changelog-formatter.ts", { "emoji": true }] +} +``` diff --git a/docs/configuration.md b/docs/configuration.md index 068d077..ea4a68d 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -114,17 +114,9 @@ Per-package settings can be defined in two places: ## Changelog formatters -Set `changelog` in config to control how changelog entries are generated: +Set `changelog` in config to control how changelog entries are generated. Built-in options are `"default"` and `"github"`, or you can provide a path to a custom formatter module. -- **`"default"`** — simple markdown with dates and bump file descriptions -- **`"github"`** — includes PR links and author attribution (requires `GH_TOKEN`) -- **Custom** — path to a TypeScript or JavaScript module that exports a formatter function - -```json -{ - "changelog": ["github", { "repo": "myorg/myrepo" }] -} -``` +See the [Changelog Formatters](./changelog-formatters.md) docs for full details and examples. ## Example config diff --git a/packages/bumpy/src/core/changelog-github.ts b/packages/bumpy/src/core/changelog-github.ts index a9eb01d..db30d3f 100644 --- a/packages/bumpy/src/core/changelog-github.ts +++ b/packages/bumpy/src/core/changelog-github.ts @@ -4,6 +4,8 @@ import type { ChangelogContext, ChangelogFormatter } from './changelog.ts'; export interface GithubChangelogOptions { /** "owner/repo" — auto-detected from gh CLI if not provided */ repo?: string; + /** Whether to include "Thanks @user" messages for contributors (default: true) */ + thankContributors?: boolean; /** GitHub usernames (without @) to skip "Thanks" messages for (e.g. internal team members) */ internalAuthors?: string[]; } @@ -15,9 +17,11 @@ export interface GithubChangelogOptions { * Usage in config: * "changelog": "github" * "changelog": ["github", { "repo": "dmno-dev/bumpy" }] - * "changelog": ["github", { "repo": "dmno-dev/bumpy", "internalAuthors": ["theoephraim"] }] + * "changelog": ["github", { "thankContributors": false }] + * "changelog": ["github", { "internalAuthors": ["theoephraim"] }] */ export function createGithubFormatter(options: GithubChangelogOptions = {}): ChangelogFormatter { + const thankContributors = options.thankContributors ?? true; const internalAuthorsSet = new Set((options.internalAuthors ?? []).map((a) => a.toLowerCase())); return async (ctx: ChangelogContext) => { @@ -47,7 +51,7 @@ export function createGithubFormatter(options: GithubChangelogOptions = {}): Cha const firstLine = linkifyIssueRefs(summaryLines[0]!, serverUrl, repoSlug); // Build the prefix: PR link, commit link, thanks - const prefix = formatPrefix(gitInfo, serverUrl, repoSlug, internalAuthorsSet); + const prefix = formatPrefix(gitInfo, serverUrl, repoSlug, thankContributors, internalAuthorsSet); lines.push(`-${prefix ? ` ${prefix} -` : ''} ${firstLine}`); @@ -239,6 +243,7 @@ function formatPrefix( info: BumpFileGitInfo, serverUrl: string, repo: string | undefined, + thankContributors: boolean, internalAuthors: Set, ): string { const parts: string[] = []; @@ -252,7 +257,7 @@ function formatPrefix( parts.push(`[\`${short}\`](${serverUrl}/${repo}/commit/${info.commitHash})`); } - if (info.author && !internalAuthors.has(info.author.toLowerCase())) { + if (thankContributors && info.author && !internalAuthors.has(info.author.toLowerCase())) { parts.push(`Thanks [@${info.author}](${serverUrl}/${info.author})!`); } From 588a4b204a073a4f4cfa96a7ebcc14fb67c6e6db Mon Sep 17 00:00:00 2001 From: Theo Ephraim Date: Mon, 20 Apr 2026 13:33:43 -0700 Subject: [PATCH 2/2] update package.json --- packages/bumpy/package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/bumpy/package.json b/packages/bumpy/package.json index 7cac5cf..6f76677 100644 --- a/packages/bumpy/package.json +++ b/packages/bumpy/package.json @@ -10,6 +10,8 @@ "version", "version management" ], + "homepage": "https://bumpy.varlock.dev", + "bugs": "https://github.com/dmno-dev/bumpy/issues", "license": "MIT", "author": "dmno-dev", "repository": {