Project

milestoner

0.02
A long-lived project that still receives updates
A command line interface for managing Git repository milestones.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Runtime

~> 1.1
~> 1.0
~> 3.6
~> 6.1
~> 11.0
~> 2.6
~> 3.0
~> 0.16
~> 3.5
~> 3.2
~> 1.13
~> 1.3
~> 0.8
 Project Readme

Milestoner

Milestoner is a pure Git based Command Line Interface (CLI) for software deployment automation that is agnostic of the programming language or source control service you use (i.e. GitHub, GitLab, Bitbucket, etc). Each milestone (i.e. Git tag) includes the automatic generation of feature rich release notes sourced from the Git commits that make up the milestone. Finally, each milestone adheres to Strict Semantic Versioning so your milestones remain consistent.

You can use Milestoner to inspect the current state of the next milestone, celebrate the team members that contribute to each milestone, and share information with stakeholders with minimal effort. By having a tool, like Milestoner, you can automate software releases in a consistent and reliable fashion. 🎉

Milestoner pairs well with the following gems:

Table of Contents
  • Screenshots
  • Features
  • Requirements
  • Setup
  • Usage
    • Command Line Interface (CLI)
    • Customization
    • Config
    • Cache
    • Build
      • Automatic Versioning
      • Templates
      • Web Format
  • Security
  • Development
  • Tests
  • License
  • Security
  • Code of Conduct
  • Contributions
  • Versions
  • Community
  • Credits

Screenshots

ASCII Doc Format (i.e. milestoner build --format ascii_doc)

Usage

Markdown Format (i.e. milestoner build --format markdown)

Usage

Stream Format (i.e. milestoner build --format stream)

Usage

Web Format (i.e. milestoner build --format web)

Usage

Usage

Features

  • Uses Versionaire for Strict Semantic Versioning. Example:

    • Format: <major>.<minor>.<patch>.

    • Example: 0.0.0.

  • Ensures Git commits since last tag (or initialization of repository) are included in the release notes.

  • Ensures Git commit messages are grouped by prefix, in order defined, for categorization. For more details, see Git Lint Commit Subject Prefix. Defaults (can be customized):

    • Fixed Fixed

    • Added Added

    • Updated Updated

    • Removed Removed

    • Refactored Refactored

  • Ensures Git commit messages are alphabetically sorted for release note categorization and readability.

  • Provides automatic versioning based on last Git tag and current commit trailers. See Git Commit Anatomy for details.

  • Supports multiple release note build formats: ASCII Doc, Markdown, Stream (console), and Web (HTML). Each are fully customizable via your personal XDG configuration and Hanami View templates.

Requirements

  1. A UNIX-based system.

  2. Ruby.

  3. GnuPG (optional).

Setup

To install with security, run:

# 💡 Skip this line if you already have the public certificate installed.
gem cert --add <(curl --compressed --location https://alchemists.io/gems.pem)
gem install milestoner --trust-policy HighSecurity

To install without security, run:

gem install milestoner

Usage

Command Line Interface (CLI)

From the command line, type: milestoner --help

Usage

Customization

This gem can be configured via a global configuration:

~/.config/milestoner/configuration.yml

It can also be configured via XDG environment variables.

The default configuration is:

avatar:
  domain: https://avatars.githubusercontent.com
  uri: "%<domain>s/u/%<id>s"
build:
  format: web
  layout: page
  root: tmp/milestone
commit:
  categories:
    - emoji: 
      label: Fixed
    - emoji: 🟢
      label: Added
    - emoji: 🔼
      label: Updated
    - emoji: ⛔️
      label: Removed
    - emoji: 🔁
      label: Refactored
  domain: https://github.com
  format: asciidoc
  uri: "%<domain>s/%<owner>s/%<name>s/commit/%<id>s"
generator:
  label:
  uri:
  version:
profile:
  domain: https://github.com
  uri: "%<domain>s/%<id>s"
project:
  author:
  description:
  generator:
  label:
  name:
  owner:
  uri:
  version:
review:
  domain: https://github.com
  uri: "%<domain>s/%<owner>s/%<name>s/pulls/%<id>s"
tracker:
  domain: https://github.com
  uri: "%<domain>s/%<owner>s/%<name>s/issues/%<id>s"

The above can be customized as follows:

  • avatar: Manages team member avatar information.

    • domain: Required. The domain of your team member avatars. Default: GitHub.

    • uri: Required. The URI format for linking to avatars as formatted using String Formats. Default: GitHub. The id is dynamically calculated via the external_id of the user stored in the Lode cache.

  • build: Manages release note builds.

    • format: Required. The build output format. Multiple formats are supported. Default: web.

    • layout: Required. The layout used by the Hanami View gem when building release notes. Default: page.

    • root: Required. The output location. This can be a relative or absolute path. Defaults to the tmp directory of your current project. The path is automatically created if missing.

  • commit: Manages commit categories, emojis, and hyperlinks.

    • categories: Required. By default, only five categories are supported which pairs well with the Git Lint gem. Category order is important with the first taking precedence over the second and so forth. Special characters are allowed for prefixes but should be enclosed in quotes. To disable categories, use an empty array. Example: categories: [].

      • emoji: Required. The emoji associated with the label for output purposes. Used by the ASCII Doc, Markdown, and stream build formats. Defaults to the provided emojis.

      • label: Required. Allows you to customize the category label. All commits are grouped by label which equates to the prefix, or first word, used in each commit message. The defaults pair well with the Git Lint gem. Defaults to the provided labels.

    • domain: Required. The Git repository domain for all commits. Default: GitHub.

    • format: Required. Defines the default format used for rendering commit messages unless specified in the commit trailer metadata which takes higher precedence. Default: ASCII Doc.

    • uri: Required. The URI format for linking to commits as formatted using String Formats. Default: GitHub. The id is dynamically calculated via the commit SHA of each commit analyzed at runtime.

  • generator: Manages generator information.

    • label: Required. The label of the generator used for all software milestones. Default: Milestoner.

    • uri: Required. The URI of the generator used for all software milestones. Defaults to Milestoner’s homepage URL as provided by the Gem Specification of this project.

    • version: Required. The version of the generator used for all software milestones. Defaults to Milestoner’s current version as provided by the Gem Specification of this project.

  • profile: Manages team member profile information.

    • domain: Required. The domain of your Git repository. Default: GitHub.

    • uri: Required. The URI format for linking to profiles as formatted using String Formats. The id is dynamically calculated via the handle of the user stored in the Lode cache. Default: GitHub.

  • project: Manages project information.

    • author: Required. The project author. Dynamically calculated by the Etcher gem in the following order: This value or Git configuration user name.

    • description: Optional. The project description. Dynamically calculated by the Etcher gem in the following order: This value, Gem Specification summary, or CFF abstract.

    • generator: ⚠️ Deprecated and will be removed in the next major version. Please use the generator configuration section mentioned above instead.

    • label: Optional. The project label. Dynamically calculated by the Etcher gem in the following order: This value, Gem Specification metadata label, or CFF title.

    • name: Required. The project name. Dynamically calculated by the Etcher gem in the following order: This value or Gem Specification name.

    • owner: Optional. The project owner. This is your source code organization or user handle. Used when formatting URLs (mentioned above). Despite being optional, it is strongly recommended you configure this value so all links are formatted properly.

    • uri: Optional. The project URI. Dynamically calculated by the Etcher gem in the following order: This value or Gem Specification homepage.

    • version: Required. The project version. Dynamically calculated based on the last Git tag of your project and Git Milestone commit trailer metadata. The default is: 0.0.0. For more on this see, the Automatic Versioning section below. You can configure a value but, keep in mind, the value will be used for all deployments and release notes. Better to let this gem compute this for you.

  • review: Manages code review information.

    • domain: Required. The domain of your code review service. Default: GitHub.

    • uri: Required. The URI format for linking to code reviews as formatted using String Formats. Default: GitHub. The id is currently a placeholder for future feature support when API support is added. For now this links to all code reviews with the goal to link to individual code reviews based on issue tracker metadata from Git commit trailers.

  • tracker: Required. Allows you to customize the issue tracker service you are using. Default: GitHub.

    • domain: Required. The domain of your issue tracker service. Default: GitHub.

    • uri: Required. The URI format for linking to issues as formatted using String Formats. Default: GitHub. The id is dynamically calculated via the commit Issue trailer as linted by Git Lint.

💡 If you ever need to know what your current configuration looks like you can jump into your applications IRB console and inspect Milestoner::Container[:configuration] to see full details.

Config

Usage

Milestoner can be configured via the command line using: milestoner config. This allows you to create, edit, view, and/or delete your global or local configuration as desired. The configuration is managed by the Runcom gem which is built atop the XDG gem for managing global or local configurations. Please read the documentation of each gem to learn more.

Cache

Usage

Milestoner’s cache allows you to enrich user information (i.e. authors, collaborators, etc) by storing information in a PStore database as managed by the Lode gem. Cache location, as with the Config, is managed by the Runcom gem.

User information should be sourced from whatever service you use for managing your source code. For example, when using GitHub, your workflow might look like this:

milestoner cache --list
# 🟢 Listing users...
# 🟢 No users found.

milestoner cache --create "111,jsmith,Jane Smith"
# 🟢 Created: "Jane Smith"

milestoner cache --create "222,jdoe,John Doe"
# 🟢 Created: "John Doe"

milestoner cache --create "333,jgrey,Jill Grey"
# 🟢 Created: "Jill Grey"

milestoner cache --list
# 🟢 Listing users...
# 111, jsmith, Jane Smith
# 222, jdoe, John Doe
# 333, jgrey, Jill Grey

milestoner cache --delete "Jill Grey"
🟢 Deleted: "Jill Grey".

milestoner cache --list
# 🟢 Listing users...
# 111, jsmith, Jane Smith
# 222, jdoe, John Doe

milestoner cache --info
# 🟢 Path: /Users/demo/.cache/milestoner/database.store.

💡 Use https://api.github.com/users/<handle> to acquire the external ID for any GitHub user.

Once team member information is stored in your cache, you’ll be able to build release notes which automatically link to GitHub user information without constantly hitting the GitHub API. Users are identified by name so the full author name used for each commit message needs to match the same user name as stored in your source repository hosting service.

Build

Usage

The build command allows you to quickly build release notes to check the current status of your project or deploy a new milestone. By default, the build command uses either the default or custom configuration as documented in the Configuration section above. This means, when using the defaults, you can immediately build the release notes for your project in a temporary directory:

milestoner build --format web
# 🟢 Building milestone...
# 🟢 Milestone built: /Users/bkuhlmann/Engineering/OSS/milestoner/tmp/milestone

💡 The above command is so useful that I use the following msb (i.e. Milestoner Build) Bash alias: rm -rf tmp/milestone && milestoner build --format html && open tmp/milestone/index.html. This allows me to quickly rebuild release notes for any project and immediately view them in my default browser.

Check out the help documentation (i.e. milestoner build --help) for addition usage that explains what command line options you can use to overwrite the current configuration.

Automatic Versioning

As mentioned earlier, the calculation of version information happens automatically for you based on your last Git tag and any Git commit trailer metadata used. If none of this information is present, then the default version of 0.0.0 is used instead. All of this information is available to you via the following command:

milestoner build --help

Running the above will dynamically show you latest version information — along with help documentation — in case you have doubts. You can use this as a status check as well. If you don’t want to use the automatic version, you can override by using the --version option when building. Example:

# Uses automatic version.
milestoner build --format stream

# Uses manual version.
milestoner build --format stream --version 1.2.3

By default, automatic versioning is based on your last known Git tag and the version is bumped based on Git commit trailer information from untagged commits (i.e. those commits created since the last tag). All of this is managed via the Versionaire gem. To ensure automatic versioning works properly, you only need to add the Milestone Git commit trailer with a value of: patch, minor, or major. Here’s an example assuming you have published Version 1.0.0:

# First commit.
Milestone: patch

# Second commit.
Milestone: minor

# Third commit
Milestone: patch

Given the above, the resulting version would be: 1.1.0. This is because the highest milestone was a minor milestone. The highest milestone wins and doesn’t matter how many commits you made with the same milestone trailer information or the order in which the commits were made. Here’s another example:

# First commit.
Milestone: patch

# Second commit.
Milestone: patch

# Third commit
Milestone: patch

Given the above, the resulting version would be: 1.0.1. This is because the highest milestone was a patch. Here’s a final example:

# First commit.
Milestone: major

# Second commit.
Milestone: minor

# Third commit
Milestone: patch

Given the above, the resulting version would be: 2.0.0. This is because the highest milestone was a major milestone.

Templates

Build template functionality is powered by the Hanami View gem which means you can customize the HTML structure, CSS style, and more. The quickest way to get started is to copy the templates folder structure — included with this gem — to your preferred Runcom configuration. For example, this gem’s template structure is:

lib/milestoner/templates
├── layouts
│  ├── page.adoc.erb
│  ├── page.html.erb
│  ├── page.md.erb
│  └── page.stream.erb
├── milestones
│  ├── _avatar.html.erb
│  ├── _commit.adoc.erb
│  ├── _commit.html.erb
│  ├── _commit.md.erb
│  ├── _commit.stream.erb
│  ├── _icon.html.erb
│  ├── _profile.html.erb
│  ├── show.adoc.erb
│  ├── show.html.erb
│  ├── show.md.erb
│  └── show.stream.erb
└── public
   └── page.css.erb

This means you could, for example, copy all of this gem’s templates to your own Runcom configuration to customize how you like. Example:

cp -r <milestoner_gem_root>/lib/milestoner/templates $HOME/.config/milestoner/templates

Milestoner searches your Runcom configuration first and, if templates are detected, will be used instead. Otherwise, Milestoner will fall back to it’s own templates. Once Runcom has calculated all possible template locations, Hanami View handles the final loading and evaluation of your templates.

Web Format

Of all the build formats supported, the web format is the most powerful, feature rich, and is why it’s the default format. The following showcases some of the information rendered in this format based on commit activity.

Wit Basic Git Commit

Usage

With Git Commit Notes and Trailers

Usage

Each milestone is meant to provide you with the right amount of statistical information you can make informed decisions.

Security

To securely sign your Git tags, install and configure GPG:

brew install gpg
gpg --gen-key

When creating your GPG key, choose these settings:

  • Key kind: RSA and RSA (default)

  • Key size: 4096

  • Key validity: 0

  • Real Name: <your name>

  • Email: <your email>

  • Passphrase: <your passphrase>

To obtain your key, run the following and take the part after the forward slash:

gpg --list-keys | grep pub

Add your key to your global (or local) Git configuration and ensure GPG signing for your tag is enabled. Example:

[tag]
  gpgSign = true
[user]
  signingkey = <your GPG key>

Now, when publishing a new milestone (i.e. milestoner --publish <version>), the signing of your Git tag will happen automatically. You will be prompted for the GPG Passphrase each time unless you are running the GPG Agent in the background (highly recommend).

Development

To contribute, run:

git clone https://github.com/bkuhlmann/milestoner
cd milestoner
bin/setup

You can also use the IRB console for direct access to all objects:

bin/console

Tests

To test, run:

bundle exec spec

Credits