Changelog¶
Package: pkg/changelog
Parses and generates conventional commit-based release notes into structured Go types. Includes a pure-Go changelog generator (cmd/changelog) that replaces external tools like git-cliff. Breaking changes are highlighted prominently so consumers can assess upgrade risk.
Types¶
Category¶
const (
CategoryBreaking Category = iota // breaking change requiring user action
CategoryFeature // new feature
CategoryFix // bug fix
CategoryPerformance // performance improvement
CategoryOther // refactor, docs, chore, etc.
)
Entry¶
A single change within a release:
type Entry struct {
Category Category
Scope string // e.g., "http", "chat" โ may be empty
Description string
Raw string // original unparsed line
}
Release¶
Parsed changelog for a single version:
Changelog¶
Parsed changelog across multiple releases:
Parsing¶
Parse processes raw release notes markdown line-by-line:
- Splits into per-release sections by detecting
# vX.Y.Zheaders. - Within each release, detects section headers (
### Features,### Bug Fixes,### BREAKING CHANGES, etc.) to determine the current category. - Parses bullet points (
* **scope:** descriptionor* description) intoEntrystructs. - Detects
BREAKING CHANGE:footers within entry descriptions and reclassifies them asCategoryBreaking.
Releases are returned oldest-first.
Supported Section Headers¶
| Header | Category |
|---|---|
### BREAKING CHANGES |
CategoryBreaking |
### Features |
CategoryFeature |
### Bug Fixes |
CategoryFix |
### Performance Improvements |
CategoryPerformance |
| Any other section | CategoryOther |
Querying¶
// Check for breaking changes
if cl.HasBreakingChanges() {
for _, e := range cl.BreakingChanges() {
fmt.Printf("BREAKING: %s: %s\n", e.Scope, e.Description)
}
}
// Filter by category
features := cl.EntriesByCategory(changelog.CategoryFeature)
Formatting¶
FormatSummary produces human-readable terminal output. Breaking changes appear first with a WARNING prefix, followed by features, bug fixes, performance improvements, and other changes.
Example output:
WARNING: Breaking changes detected!
BREAKING: config: rename ConfigPath to ConfigDir
Features:
- http: add middleware chaining
- chat: add streaming support
Bug Fixes:
- fix startup race condition
Integration with SelfUpdater¶
The SelfUpdater in pkg/setup provides a convenience method that fetches and parses release notes in one call:
cl, err := updater.GetStructuredReleaseNotes(ctx, "v1.0.0", "v1.3.0")
if err != nil {
return err
}
if cl.HasBreakingChanges() {
fmt.Print(changelog.FormatSummary(cl))
}
The existing GetReleaseNotes method continues to return raw markdown and is unchanged.
Archive-Bundled Changelog¶
Release archives can include a CHANGELOG.md file alongside the binary (generated by go tool changelog generate in the CI release workflow). When present, the changelog is parsed directly from the archive โ zero extra API calls.
Integrated Fallback via SelfUpdater¶
GetStructuredReleaseNotes accepts an optional archive buffer. When provided, it tries the bundled changelog first and falls back to per-release API calls automatically:
archive, _ := updater.DownloadAsset(ctx, asset)
cl, err := updater.GetStructuredReleaseNotes(ctx, "v1.0.0", "v1.3.0", archive)
Direct ParseFromArchive¶
For lower-level control, ParseFromArchive can be called directly. It scans tar entries for CHANGELOG.md, parses it via Parse, and returns nil (not an error) if no changelog file is found:
cl, err := changelog.ParseFromArchive(archiveReader)
if err != nil {
return err
}
if cl == nil {
// No CHANGELOG.md in archive โ fall back to API-based retrieval
cl, err = updater.GetStructuredReleaseNotes(ctx, from, to)
}
The file is matched case-insensitively and at any nesting depth within the archive.
Generation¶
The GenerateFromRepo function reads git history directly using go-git and produces markdown compatible with Parse():
Options¶
| Option | Description |
|---|---|
WithSinceTag(tag) |
Only include releases after the given tag |
WithMaxReleases(n) |
Limit to the N most recent releases |
WithIncludeAll() |
Include non-conventional commits under "Other" |
CLI Tool¶
The cmd/changelog tool wraps GenerateFromRepo as a Go tool directive:
# Generate to stdout
go tool changelog generate
# Generate to file
go tool changelog generate --output CHANGELOG.md
# Limit to releases after v1.5.0
go tool changelog generate --since v1.5.0
# Include non-conventional commits
go tool changelog generate --include-all
Add the tool directive to go.mod:
Use with go:generate:
Testing¶
The parser is pure logic with no I/O dependencies. Tests use inline markdown strings and testdata fixtures:
cl := changelog.Parse(rawNotes)
assert.True(t, cl.HasBreakingChanges())
assert.Len(t, cl.EntriesByCategory(changelog.CategoryFeature), 3)
Related Documentation¶
- Setup / Update โ self-update lifecycle that consumes the changelog parser
- Version โ version comparison utilities used alongside changelog diffing