Home

Awesome

lein-git-version

Clojars Project

Derive your Leiningen project version from your Git history.

Motivation

Leiningen projects, in their heritage from Maven, list an explicit version as the 3rd element of a project.clj file. For instance

(defproject foo "1.3.4"
  ...)

There are a couple of problems with this. First of all, until the arrival of leiningen.release/bump-version for the lein release task, there was really no sane way to update the version of a property short of a sed script to rewrite the project.clj.

While bump-version is a mostly acceptable solution, it still relies on storing the version identifier in a file, attached to some point in the history of the repository.

The problem with sticking a version identifier in the filesystem/version history is that it becomes a source of merge conflicts. To avoid the merge conflicts, teams sometimes build complicated merge hooks or automated workflows. Now you have two problems.

In monorepo patterns ala lein-modules, the problems above become amplified. Additionally, versions for inter-monorepo dependencies are not very meaningful as all dependencis are built from the same source commit, rather than depending on a specific Maven version identifier. Using a commit ID or version control tag/label is a more accurate and useful.

Usage

Add:

;; Add in the git-version plugin
:plugins [[me.arrdem/lein-git-version "2.0.3"]
          ...]

By default, my incarnation of lein-git-version doesn't do anything to your project, except make some additional keys visible in the project map.

{:tag       ;; Name of the last git tag if any
 :ahead     ;; Number of commits ahead of the last tag, or 0
 :ahead?    ;; Is the head ahead by more than 0 commits
 :ref       ;; The full current ref
 :ref-short ;; The "short" current ref
 :branch    ;; The name of the current branch
 :dirty?    ;; Optional. Boolean. Are there un-committed changes.
 :message   ;; Optional. The last commit message when clean.
 :timestamp ;; Optional. The last commit date when clean.
}

If the keyword :project/git-ref or :project/git-ref-short is used in place of a version string, lein-git-version will update the version string of the project to instead reflect the ref or short ref.

For instance,

(defproject bar :project/git-ref
  :plugins [[me.arrdem/lein-git-version "2.0.3"]]
  ...)

or

(defproject baz :project/git-ref-short
  :plugins [[me.arrdem/lein-git-version "2.0.3"]]
  ...)

lein-git-version can also be used to compute a versions string, as an arbitrary function of the current git status by specifying a status-to-version function of the above status structure in the :git-version map of your project.clj.

For instance, lein-git-version uses an earlier version of itself to compute its own version.

(defproject me.arrdem/lein-git-version "_"
  :plugins [[me.arrdem/lein-git-version "2.0.3"]]

  :git-version
    {:status-to-version
       (fn [{:keys [tag version branch ahead ahead? dirty?] :as git}]
          (assert (re-find #"\d+\.\d+\.\d+" tag)
                  "Tag is assumed to be a raw SemVer version")
          (if (and tag (not ahead?) (not dirty?))
             tag
             (let [[_ prefix patch] (re-find #"(\d+\.\d+)\.(\d+)" tag)
                   patch            (Long/parseLong patch)
                   patch+           (inc patch)]
               (format "%s.%d-%s-SNAPSHOT" prefix patch+ branch))))
  }
  ...)

Will use the last tag as the version if level with a tag, otherwise will produce a SNAPSHOT one SemVer patch ahead of the previous tag qualified with the name of the current branch.

This enables your release workflow to consist simply of creating a tag and doing a deploy. No source changes are required.

Like its predecessors, lein-git-version can be used to generate a version file. Previous incarnations tried to lay down a version namespace. This incarnation can be configured to lay down an EDN file containing git information at a specified location relative to the root of the project.

For instance,

(defproject com.my-app/cares-what-version-it-is :project/ref-short
  :plugins [[me.arrdem/lein-git-version "2.0.3"]]
  ...
  :git-version {:version-file "resources/com/my_app/version.edn"
                :version-file-keys [:ref :version :timestamp]}))

will cause lein-git-version to make the specified directory, and lay down an EDN file containing all the selected project status information from the project map.

It's suggested that rather than target a directory under source control, a source control ignored eg "gen-resources/..." directory be used to isolate generated build artifacts from user sources. Remember to add the target to your project's :resource-paths!

History

This repo is a fork and to my taste a massive cleanup of cvillecsteele's lein-git-version which is itself an un-maintained alternative to michalmarczyk's original project.

License

Copyright © 2017 Reid "arrdem" McKenzie

Derived from lein-git-version © 2016 Colin Steele

Derived from lein-git-version © 2011 Michał Marczyk

Distributed under the Eclipse Public License, the same as Clojure.