GitHub

Test status GitHub release Platforms License

Finch is a configurable tool designed to make tracking the history and evolution of a product simple and easy to automate. It transforms a project's Git commit messages into well-formatted version changelogs — tailored to your team's specific needs.

Table of Contents

Why is it called 'Finch'?

The name Finch is derived from the purpose of the application itself — tracking the evolution of a product. Because evolution is at the core of Finch, it seemed appropriate to name it after an evolutionary landmark, Darwin's finches.

Philosophy

We strongly believe in the importance of a good changelog. We also know changelogs can occasionally end up A) overlooked/untimely and B) difficult to maintain in terms of styling/approach as different team-members are managing a given release. It was these issues, and the desire to automate them for our team, which led to the creation of Finch. We believe that well-formed and intentional Git commit messages can serve as the underlying data for powering an automated and hassle-free changelog system. Through the use of some relatively minor commit-message discipline — and according to whatever conventions your team would like to use — Finch can help you automate your internal and external-facing changelogs, providing as much detail or polish as is desired.

Installation

Building Finch from source — via Homebrew, Mint or make install — requires a Swift 6.0 or newer toolchain. The packaged release requires nothing beyond macOS.

Finch is available via multiple installation methods:

  1. Homebrew
    1. Add tap brew tap namolnad/formulae
    2. Install finch brew install --formula finch
  2. Installable package
    1. Download and run the most recent release's Finch.pkg file and follow the on-screen instructions
  3. Mint:
    1. Install mint brew install mint
    2. Install finch mint install namolnad/finch
  4. From source
    1. If you’d like to build from source, you can clone this repository and run make install from the root of the cloned directory. This will install and link the Finch binary and will place a template config file at the following location $HOME/.finch/template.config.yml

Usage

Finch reads Conventional Commitstype(scope): description — and uses the type and scopes as the tags which decide the section a commit belongs to.

Example commit messages

chore: remove legacy obj-c code

feat(app-store): add teleportation capabilities

feat(api)!: drop v1 endpoints

The type and every scope become tags, so feat(app-store) carries both feat and app-store — which is what --required-tags app-store matches on. A ! before the colon, or a line opening with BREAKING CHANGE:, adds a breaking tag, which the default configuration collects under its own heading.

Prose is left alone: only a lower-case type followed by a colon opens an entry, so an ordinary body line like Note: ... or Fixes: #123 is not mistaken for one.

Describing a breaking change

A BREAKING CHANGE: footer describes the commit rather than standing on its own, so its text is attached to the commit's entry instead of becoming a separate one, and the entry is tagged breaking exactly as a ! would. Wrapped footers are joined, and footers are read whichever commit style the project uses.

Put << breaking_change >> in a section's format_string to print that description:

- title: Breaking Changes
  tags: [breaking]
  format_string: ' - << tags >> << message >> — << breaking_change >>'
### Breaking Changes
 - |breaking||feat||api| drop the v1 endpoints — v1 is gone. Move to v2, which takes the same parameters and returns an envelope.
 - |breaking||feat||ui| restyle the header

The second entry has no footer, and the separator introducing it is dropped rather than left dangling — which holds for any component rendering nothing, << tags >> on an untagged commit included.

Multiple entries per commit

A commit which does more than one thing can carry more than one changelog entry. Every line which opens an entry becomes one — placed in its own section and linked to the same commit or pull request — while lines which don't either continue the entry above them or, when separated from it by a blank line, are left out of the changelog entirely.

Example commit message

feat: add teleportation capabilities
chore: remove legacy obj-c code
Teleportation is behind the `beam_me_up` feature flag until the
telemetry lands.

Using Finch's original tag convention

Finch previously required a [tag] commit message convention, with one or more delimited tags opening the message. That is still supported — set commit_style: delimited under format: in your configuration and the delimiters remain configurable as before.

format:
  commit_style: delimited

A --commit-style conventional|delimited argument overrides the configured value for a single run, which is useful when comparing versions either side of a migration.

To generate a changelog you must run the compare command. If compare is passed no arguments, Finch will first look for the two most recent semantically-versioned branches then the two most recent semantically-versioned git tags. You can also explicitly pass two versions by using the --versions option and passing 2 version arguments (branch or tag). Other accepted argurments are:

  1. The ability to hide the version header (--no-show-version)
  2. Release manager (--release-manager)
  3. Project directory (--project-dir) if Finch is not called from project directory
  4. Manual git log (--git-log). Must be received in format: git log --left-right --cherry-pick --oneline --format=format:'&&&%H&&& - @@@%B@@@###%ae###' --date=short OLD_VERSION...NEW_VERSION. Note: --graph is not supported, as its connecting lines are indistinguishable from the body of a commit message
  5. Don't fetch origin before auto-generating changelog (--no-fetch).
  6. Build number string to be included in version header (--build-number) Takes precedence over build number command in config. Example output: 6.19.1 (6258)

In many cases it may be easiest to create a new shell function when your shell startup files are sourced, such as the following:

project-changelog() {
  finch compare --project-dir="$HOME/Code/YourProject" --release-manager=$(git config --get user.email) $@
}
# Used in the following manner:
# project-changelog --versions '6.12.1 6.13.0'

Configuration

View Finch's configurable components in this configuration template.

Config file location

Finch searches for a hidden .finch directory containing a config.yml file. The .finch directory can be placed in either the home, current, or project directories. Alternatively, if you provide a custom path through a --config argument or an env variable, Finch will look for a valid configuration file at the included path. Finch also allows for private config files in case you prefer to keep portions of your config outside your version-control sytem. See the search behavior below.

Config format

config.yml should be a valid YAML file in the same format as this config template. (Note: Not all keys need to be included as Finch uses default values where needed. You can see an example config at any time by running finch config show-example.

Config merging and search behavior

Finch will start with a default configuration and will search several paths for valid configuration files to override existing values. Any non-empty elements included in later configuration files will override their existing counterparts. Empty or omitted config file components will be ignored.

The config search paths will be executed in the following manner:

  • --config argument
  • FINCH_CONFIG Env var OR
  • Built in defaults overridden w/ waterfall technique (searching each directory first for config.yml, then for config.private.yml)
    • Home directory
    • Finch's current directory
    • --project-dir argument

Notes

  • Sections should be listed in the order you want them to be displayed in the output
  • If included sections have duplicative tags, the last section with a given tag wins. Each matching commit will be placed into its owning section.
  • One wildcard section can be included. Do so by including a * in the section's tag config.
  • Commits will only appear in a single section. Searches first for a section matching the first commit tag, then the second and so on.
  • Sections may be excluded by passing excluded: true in section config

Contributing

See CONTRIBUTING.md

Example output

# 6.13.0 (3242)
### Release Manager
 - @User.2
### Features
 - |wip||custom-lib| initial work on incorporating 1.0.0 — [PR #912](https://github.com/your_repo/pull/912) — @User.3
 - |checkout| improved tracking + logging — [PR #958](https://github.com/your_repo/pull/958) - @User.2
### Bug Fixes
 - |cleanup| remove unused obj-c experiment, fix some warnings — [PR #949](https://github.com/your_repo/pull/949) — @User.1
 - |cleanup| remove unused Lib — [PR #947](https://github.com/your_repo/pull/947) - @User.3
### Platform Improvements
 - |tooling| re-enable new build system — [PR #959](https://github.com/your_repo/pull/959) — @User.1
 - |platform| move to incremental compilation and ensure we're using same swift version across the board — [PR #966](https://github.com/your_repo/pull/966) — @User.2
### Timeline
 - Begin development:
 - Feature cut-off / Start of bake / dogfooding:
 - Submission:
 - Release (expected):
 - Release (actual):

License

Finch is released under the MIT License

Read the original on github.com ↗