I’d like to announce my new project called sbt-git-flow-version. As you might guess it’s a plugin for sbt. The goal of the project is set your sbt build version according to git flow rules.
I found that for big or medium size teams git flow is quite practical. What I didn’t
like about it, is that it requires to change the version all the time you change the branch
in your repository. At some point I took responsibilities of release engineer in our team.
Since I’m very lazy to do all of this styff I came up with some Scala code in the project
catalog
of my current working project. Later I rewrote it as an sbt plugin.
So, what can it do for you?
Let’s start with git flow. The typical git flow process have following branches:
master
- contains stable releases. Only tested releases are merged here, and only
stable artifacts are build from this branch (no snapshots allowed).develop
- current development release. Features for the next release are going here.
We can define the version as a next minor version: “(last version + 0.1)-SNAPSHOT”.release/x.y.z
- release branches. These branches are for upcoming releases during
stabilization. In our team we do not have develop
branch, but several release
branches. For me, it’s more clear. The versions on this branch is x.y.z-SNAPSHOT
.feature/xxx
, and also bugfix/yyy
, hotfix/zzz
- branches for a specific task
development. The version for such buildYou might see that we need three components to compose the version:
The main setting of sbt-git-flow-version is versionPolicy
which has type
Seq[(BranchMatcher => VersionCalculator)]
. So it tries to find matching rule for
a branch and calculate a version.
What is a BranchMatcher
? It’s a function String => Option[Matching]
where matching
is a case class containing branch name and some additional optional extracted string. There are several
predefined branch matchers:
exact(name: String)
- branch name is equals to name
, extraction is empty.prefix(prefix: String)
- branch name starts with prefix
. The part after prefix is extraction.prefixes(prefixes: String*)
- same as prefix but supports a number of prefixes.regex(r: String)
- branch name matches regular expression r
. If the expression contains
groups, the first group will be returned as extraction.any
- matches any branch (might be used to define default behaviour).The VersionCalculator
converts previous version, current version, and matching either
to the version number or error message. The predefined version calculators are:
currentTag
- take a version from a current tag. If there are several current tags it will take the
one with a maximal version.nextMajor
, nextMinor
, nextBuild
, nextN
- increment major, minor, build or n-th number of
a last version. The version is snapshot by default.matching
- take a version from matching returned by BranchMatcher
. The version is snapshot by default.lastVersion
- previous version. Version value is taken from last tag or initialVersion
setting.
The version is not snapshot by default.lastVersionWithMatching
- takes last version and append matching returned by BranchMatcher
. By default
new version is snapshot.unknownVersion
- fails with unknown version message.The default policy is defined as:
Seq(
exact("master") -> currentTag(),
exact("develop") -> nextMinor(),
prefix("release/") -> matching(),
prefixes("feature/", "bugfix/", "hotfix/") -> lastVersionWithMatching(),
-> unknownVersion
any )
What literally means following:
1.4.2
, the current version is 1.5.0-SNAPSHOT
.release/2.12.85
the version is 2.12.85-SNAPSHOT
.feature/123-new-ui
and the prevous version “1.0.1” the current version is 1.0.1-123-new-ui-SNAPSHOT
.You can define your own rules in you build.sbt
in the following way:
import sbtgitflowversion.BranchMatcher._
import sbtgitflowversion.VersionCalculator._
versionPolicy := (exact("big-release") -> next-major()) +: versionPolicy.value
This will set the next major version for the “big-release” branch.
Current verion of the plugin is 0.1
. So, to add to your project/plugins.sbt
the line:
addSbtPlugin("me.limansky" % "sbt-git-flow-version" % "0.1")