# Changelog

Script and code to generate a [changelog](https://changelog.md/) loosely following
[Keep a Changelog](https://keepachangelog.com/en/1.0.0/), based on VCS history and
commit comments.

[![Build status](https://builds.sr.ht/~ser/changelog/.build.yml.svg)](https://builds.sr.ht/~ser/changelog/.build.yml?)
★ [Releases](https://downloads.ser1.net/software/changelog/)
★ ![Latest release](https://downloads.ser1.net/software/changelog/badges/latest_release.svg)
[![License](https://downloads.ser1.net/software/changelog/badges/license.svg)](https://hg.sr.ht/~ser/changelog/raw/LICENSE?rev=tip)
★ [Changelog](https://hg.sr.ht/~ser/changelog/browse/CHANGELOG.md?rev=tip)
★ [Issues](https://todo.sr.ht/~ser/changelog)
★ [Mailing List](https://lists.sr.ht/~ser/changelog)  

The idea came from [changeloguru](https://github.com/haunt98/*changelog*uru), but
that tool only works on git repositories. *changelog* works on Jujutsu and
Mercurial repositories.

## About & Features

*changelog* makes a _lot_ of assumptions about how you organize code; it's
mostly unavoidable to get any amount of non-trivial structure which limits
noise:

- jj and hg are using bookmarks, not tags (it doesn't matter for git). I might
  be able to adapt for jj and hg tags. hg tags are really dumb things, though;
  don't use them.
- comments start with "fix", "bug", "add", or some variation on several keywords
  (see [Usage][Usage]), and reference a single change each. Case is not
  sensitive, and *changelog* does a really idiot form of stemming ("fix",
  "fixes", "fixed" are all "fix", but then so is "Fixated").
- a commit may contain a comment with multiple lines. It doesn't have to, but
  *changelog* looks for them.
- a bookmark may roll up several commits. This shouldn't be surprising; it's
  sort of how tagging has worked forever.
- any bookmark with no comments that contain keywords use the comment on the
  bookmark'd commit as a summary for the change

Therefore if you use tags and your comments look like:

> fixes ticket #478384 git log is broken again
> adds support for flying elephants
> changes default language to tamil
> removes the dark side of the moon

then *changelog* might make pretty output for you.

*changelog* will append a list of all authors to the end of the log, and if you have
[legume](https://sr.ht/~ser/legume) installed, will tack on the output of that at
the very end to boot.

Only the ancestors of the current parent are considered; generated log history will
not include bookmarks on other, unrelated, branches.

Since 0.6.0, *changelog* is written in Go, which makes it much, _much_ faster than
the prior bash scripts.

You must have the tool installed for your VCS: git for git, hg for Mercurial, or jj
for Jujutsu. It shouldn't fail if you have only the one you use, but it won't work
on Mercurial repos if you don't have Mercurial installed.

The first N>0 commits will be gathered under a meta "unreleased" heading.

## Install

1. Grab a binary from [releases](https://downloads.ser1.net/software/changelog/), or
2. `go install ser1.net/changelog@latest`, or
3. Build it:

   ```
   hg clone https://hg.sr.ht/~ser/changelog
   cd changelog
   go build .
   cp changelog ~/.local/bin/   # or wherever you put user bins
   ```

## Usage

In your commits, start each line describing a change with one of the following keywords:

- add
- change (update)
- fix
- remove (revert)
- deprecate
- security

Case is insensitive, and any variation of a word *starting* with one of the
keywords will match; therefore, these all match one of the keywords:

```
Adds a new feature
Changes something
Added a thing
```

Bookmark your Mercurial or Jujutsu repositories as you normally would. _Optionally_, create a
file called `CHANGELOG.md` and start it with `# MyProject changelog` -- whatever
front matter, up to but not including the first level-2 heading (`## Heading`),
will be preserved across runs. E.g.:

```
$ <<EOL >CHANGELOG.md
# Change log for MyProject

- [My Project Home](https://sr.ht/~me/myproject)
- [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- [Semantic Versioning](https://semver.org/spec/v2.0.0.html)

EOL
```

Now, run `changelog`, and your `CHANGELOG.md` will be rebuilt from the commit history.

### Limitations

- The aforementioned ignoring of Mercurial and Jujutsu tags
- *changelog* is currently not very smart about commits with multiple versions bookmarked
- only semantic version formats are recognized
- there's no customizability: all of the assumptions are hard-coded

### Example

My workflow looks like this:

- Work & commit as usual. I'm usually on a bookmark, but if I'm not, when I'm
  ready to push a version I bookmark it:

  ```
  hg bo v0.0.1
     # or
  jj b c -r @- v0.0.1
  ```

- When I release, I run `changelog`
- Then I squash that into the last commit:

  ```
  hg ci --amend -m 'Update changelog'
     # or
  jj ci -m "Update changelog"
  jj squash -r @-```
  ```

- Mark the bookmark as inactive, which basically makes it a cheap tag that
  doesn't pollute the history:

  ```
  hg bookmark -i
  ```

  There's no jj command to make a bookmark inactive; all you can do is "forget"
  it to stop tracking it, but then you can't push it anymore.

- Push

  ```
  hg push -B v0.0.1
     # or
  jj git push --remote origin -b v0.0.1
  ```

- Start on the next thing.
