Automatically control Leiningen project version based on Git metadata.
We assume you'll want to follow Semantic Versioning.
If no tags exist yet, we recommend adding an all-zeroes tag such as v0.0.0
to any commit:
git tag -a v0.0.0 -m "initial version"
If you're not sure, you can check if a suitable tag exists with the command
git describe --tags --dirty --long
v3.0.1-28-gf2e808057 # this repository has the tag v3.0.1
Suitable format for the tag is dependent on Configuration/Tag Pattern.
Simply add the plugin to your :plugins
vector:
:plugins [[fi.polycode/lein-git-revisions "LATEST"]
...]
and default configuration
:git-revisions {:format :semver
:adjust [:env/project_revision_adjustment :minor]}
This automatically registers the plugin middleware which handles the version string generation and applies the Semantic Versioning scheme.
Additionally, you may want to set project version to a dummy string to highlight the fact it's controlled elsewhere:
(defproject foo "_"
...)
The version must be a string for IDE compatability. For example Cursive makes assumptions based on the version always being a string.
There's roughly three phases in the plugin's execution:
All lookups are referenced as namespaced keywords, wherein the namespace defines the kind of lookup to be done. For
example :env/user
looks up the value of environment variable USER
.
:env/*
Environment variable lookup. Key is uppercased but otherwise untouched; remember to use underscores as word
delimiter:rev/*
Lookup a value from Tag pattern based on named capture group:git/*
Properties matching the current Git state, such as previous tag, versioning status, ahead/dirty...:constants/*
See Common constants:gen/*
Miscellanous values generated during runtimeTop-level configuration is as follows:
:git-revisions {:format ... ; required
:adjust ... ; optional
:revision-file ... ; optional
}
:format
)Use either a predefined built-in pattern:
:git-revisions {:format :semver}
or define your own:
:git-revisions {:format {:tag-pattern ...
:pattern ...
:adjustments ...
:constants ...}}
:semver
is built-in configuration set for the Semantic Versioning scheme.:tag-pattern
)Regular expression with named groups. Used as lookup source for :rev/*
keys.
; use any matching Git tag as-is as direct revision pattern
{:format {:tag-pattern #"(?<everything>.+)$"
:pattern [:segment/always [:rev/everything]]}}
:pattern
)Vector of segments expressed as implicit, ordered pairing of segment directives and segment parts for the pattern.
:segment/always
is always included in the revision string:segment/when
inspects the first value of the vector and based on its truthiness includes the following parts in
the resulting revision string:segment/when-not
complement of :segment/when
{:format {:pattern [:segment/when [:env/kenobi "Hello there."]
:segment/when [:env/grievous " General Kenobi!"]]}}
; When environment variable KENOBI is set, produces "Hello there."
; When environment variable GRIEVOUS is set, produces "General Kenobi!"
; When neither are set, an empty string is produced.
; When both are set, both are included as is; "Hello there. General Kenobi!"
or more practical
; only CI can build non-snapshots, optionally including pre-release tag
{:format {:pattern [:segment/when-not [:env/ci "-SNAPSHOT"]
:segment/when [:env/lein_revisions_prerelease "-" :env/lein_revisions_prerelease]]}}
:adjustments
)Map of labeled adjustments to be executed conditionally during resolution based on lookup context.
{:format {:tag-pattern #"(?<numbers>\d.+)$"
:pattern [:segment/always [:rev/numbers]]
:adjustments {:bump {:rev/numbers :inc}}}
:adjust [:env/project_next_revision :bump]}
The adjust selector drives the selection of an adjustment to be applied to the revision
string during resolving. In the example above the :adjust
selector is set to look up the value first from environment
variable PROJECT_NEXT_VERSION
and if such isn't present, use the :bump
adjustment instead.
All parts referenced in the revision pattern can be adjusted. For example Semantic Versioning Specification item 8 declares that when the MAJOR part is incremented, MINOR and PATCH parts must be reset to zero. This can be expressed - and in fact is in the built-in configuration with
{:format {...
:adjustments {:major {:rev/major :inc :rev/minor :clear :rev/patch :clear}}
...}}
Available operations for adjustments are
:inc
Increment numeric part by one:clear
Always use 0
as value:constants
)Define constants to be used for revision string resolution.
{:format {:pattern [:segment/always [:constants/coca-cola]]
:constants {:coca-cola "Pepsi"}}}
; resulting revision is always "Pepsi"
:adjust
)Control the modification of the revision string based on external information, such as environment variable set by
Continuous Integration. Should be set so that last value is some known adjustment to ensure the revision automatically
rolls onwards. Without :adjust
the revision will be stuck in whatever tag was previously defined defeating the purpose
of the plugin.
{:format {:tag-pattern #"v(?<numbers>\d.+)$"
:pattern [:segment/always "v" [:rev/numbers]]
:adjustments {:bump {:rev/numbers :inc}}}
:adjust [:bump]}
; For tag v27 produces revision v28
Using Git tags to control project version isn't a new problem and by no means an unsolved issue, in fact there are alternative libraries already available which solve this same issue but in a different way:
The main two differences compared to the ones above are
Additional motivator in creating our own was including the ability to alter specific parts of the revision string in automatic, externally configured fashion.
All the contributors to the other plugins, in no specific order, non-exhaustively:
Copyright © 2022 Esko Suomi
This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0.
This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version, with the GNU Classpath Exception which is available at https://www.gnu.org/software/classpath/license.html.
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close