(#2043) release
task: support SNAPSHOTs on qualifiers
Prior to this commit, the `lein release` task was not really usable for releases that had qualifiers such as `-alpha1`, `-beta2`, or `-RC1`. The reason for this is that the code for parsing the semver could not handle a qualifier like `-alpha1` AND a `-SNAPSHOT` qualifier at the same time. The default `:release-tasks` include a `bump-version` at the `:release` level, and then the release, and then a `bump-version` at the `:patch` level. If you had a version that started out as `1.0.0-alpha1` *or* `1.0.0-alpha1-SNAPSHOT`, then the `:release` bump would always set the version to `1.0.0`. Then the actual release would occur, and then the `:patch` bump would take you to `1.0.1-SNAPSHOT`. With this commit, `qualifier` and `snapshot` are separated into two separate fields in the version map. This allows us to modify the `bump-version` behavior so that it works as one would expect with a qualifier like `alpha`: ```clj (is (= (bump-version "1.0.0-alpha1-SNAPSHOT" :release) "1.0.0-alpha1")) (is (= (bump-version "1.0.0-alpha1") "1.0.0-alpha2-SNAPSHOT")) ``` This allows the default `:release-tasks` setup to be used with qualifiers like alpha/beta. The commit also adds a new `level` that can be passed to the `change` task: `:qualifier`. If this level is passed, then the qualifier will be incremented instead of the major/minor/patch. It is a superset of the existing alpha/beta/RC behavior but works with arbitrary qualifier strings.
This commit is contained in:
parent
054a77af6c
commit
ef4e178f81
2 changed files with 173 additions and 50 deletions
|
@ -4,20 +4,22 @@
|
|||
[leiningen.core.main :as main]
|
||||
[leiningen.core.project :as project]))
|
||||
|
||||
(def ^:dynamic *level* :patch)
|
||||
(def ^:dynamic *level* nil)
|
||||
|
||||
(defn string->semantic-version [version-string]
|
||||
"Create map representing the given version string. Returns nil if the
|
||||
string does not follow guidelines setforth by Semantic Versioning 2.0.0,
|
||||
http://semver.org/"
|
||||
;; <MajorVersion>.<MinorVersion>.<PatchVersion>[-<BuildNumber | Qualifier >]
|
||||
(let [version-map (->> (re-matches #"(\d+)\.(\d+)\.(\d+).*" version-string)
|
||||
(drop 1)
|
||||
(map #(Integer/parseInt %))
|
||||
(zipmap [:major :minor :patch]))
|
||||
qualifier (last (re-matches #".*-(.+)?" version-string))]
|
||||
(if-not (empty? version-map)
|
||||
(merge version-map {:qualifier qualifier}))))
|
||||
;; <MajorVersion>.<MinorVersion>.<PatchVersion>[-<Qualifier>][-SNAPSHOT]
|
||||
(if-let [[_ major minor patch qualifier snapshot]
|
||||
(re-matches
|
||||
#"(\d+)\.(\d+)\.(\d+)(?:-(?!SNAPSHOT)([^\-]+))?(?:-(SNAPSHOT))?"
|
||||
version-string)]
|
||||
(->> [major minor patch]
|
||||
(map #(Integer/parseInt %))
|
||||
(zipmap [:major :minor :patch])
|
||||
(merge {:qualifier qualifier
|
||||
:snapshot snapshot}))))
|
||||
|
||||
(defn parse-semantic-version [version-string]
|
||||
"Create map representing the given version string. Aborts with exit code 1
|
||||
|
@ -29,32 +31,56 @@
|
|||
(defn version-map->string
|
||||
"Given a version-map, return a string representing the version."
|
||||
[version-map]
|
||||
(let [{:keys [major minor patch qualifier]} version-map]
|
||||
(if qualifier
|
||||
(str major "." minor "." patch "-" qualifier)
|
||||
(str major "." minor "." patch))))
|
||||
(let [{:keys [major minor patch qualifier snapshot]} version-map]
|
||||
(cond-> (str major "." minor "." patch)
|
||||
qualifier (str "-" qualifier)
|
||||
snapshot (str "-" snapshot))))
|
||||
|
||||
(defn next-qualifier [sublevel qualifier]
|
||||
(let [pattern (re-pattern (str sublevel "([0-9]+)"))
|
||||
[_ n] (and qualifier (re-find pattern qualifier))]
|
||||
(str sublevel (inc (Integer. (or n 0))))))
|
||||
(defn next-qualifier
|
||||
"Increments and returns the qualifier. If an explicit `sublevel`
|
||||
is provided, then, if the original qualifier was using that sublevel,
|
||||
increments it, else returns that sublevel with \"1\" appended.
|
||||
Supports empty strings for sublevel, in which case the return value
|
||||
is effectively a BuildNumber."
|
||||
([qualifier]
|
||||
(if-let [[_ sublevel] (re-matches #"([^\d]+)?(?:\d+)?"
|
||||
(or qualifier ""))]
|
||||
(next-qualifier sublevel qualifier)
|
||||
"1"))
|
||||
([sublevel qualifier]
|
||||
(let [pattern (re-pattern (str sublevel "([0-9]+)"))
|
||||
[_ n] (and qualifier (re-find pattern qualifier))]
|
||||
(str sublevel (inc (Integer. (or n 0)))))))
|
||||
|
||||
(defn bump-version-map
|
||||
"Given version as a map of the sort returned by parse-semantic-version, return
|
||||
a map of the version incremented in the level argument. Add qualifier unless
|
||||
releasing non-snapshot."
|
||||
[{:keys [major minor patch qualifier]} level]
|
||||
(case (keyword (name level))
|
||||
:major {:major (inc major) :minor 0 :patch 0 :qualifier "SNAPSHOT"}
|
||||
:minor {:major major :minor (inc minor) :patch 0 :qualifier "SNAPSHOT"}
|
||||
:patch {:major major :minor minor :patch (inc patch) :qualifier "SNAPSHOT"}
|
||||
:alpha {:major major :minor minor :patch patch
|
||||
:qualifier (next-qualifier "alpha" qualifier)}
|
||||
:beta {:major major :minor minor :patch patch
|
||||
:qualifier (next-qualifier "beta" qualifier)}
|
||||
:rc {:major major :minor minor :patch patch
|
||||
:qualifier (next-qualifier "RC" qualifier)}
|
||||
:release {:major major :minor minor :patch patch}))
|
||||
a map of the version incremented in the level argument. Always returns a
|
||||
SNAPSHOT version, unless the level is :release. For :release, removes SNAPSHOT
|
||||
if the input is a SNAPSHOT, removes qualifier if the input is not a SNAPSHOT."
|
||||
[{:keys [major minor patch qualifier snapshot]} level]
|
||||
(let [level (or level
|
||||
(if qualifier :qualifier)
|
||||
:patch)]
|
||||
(case (keyword (name level))
|
||||
:major {:major (inc major) :minor 0 :patch 0 :qualifier nil :snapshot "SNAPSHOT"}
|
||||
:minor {:major major :minor (inc minor) :patch 0 :qualifier nil :snapshot "SNAPSHOT"}
|
||||
:patch {:major major :minor minor :patch (inc patch) :qualifier nil :snapshot "SNAPSHOT"}
|
||||
:alpha {:major major :minor minor :patch patch
|
||||
:qualifier (next-qualifier "alpha" qualifier)
|
||||
:snapshot "SNAPSHOT"}
|
||||
:beta {:major major :minor minor :patch patch
|
||||
:qualifier (next-qualifier "beta" qualifier)
|
||||
:snapshot "SNAPSHOT"}
|
||||
:rc {:major major :minor minor :patch patch
|
||||
:qualifier (next-qualifier "RC" qualifier)
|
||||
:snapshot "SNAPSHOT"}
|
||||
:qualifier {:major major :minor minor :patch patch
|
||||
:qualifier (next-qualifier qualifier)
|
||||
:snapshot "SNAPSHOT"}
|
||||
:release (merge {:major major :minor minor :patch patch}
|
||||
(if snapshot
|
||||
{:qualifier qualifier :snapshot nil}
|
||||
{:qualifier nil :snapshot nil})))))
|
||||
|
||||
(defn bump-version
|
||||
"Given a version string, return the bumped version string -
|
||||
|
@ -100,9 +126,9 @@ is a task name and the rest are arguments to that task.
|
|||
The release task takes a single argument which should be one of :major,
|
||||
:minor, :patch, :alpha, :beta, or :rc to indicate which version level to
|
||||
bump. If none is given, it defaults to :patch."
|
||||
([project] (release project (str *level*)))
|
||||
([project] (release project *level*))
|
||||
([project level]
|
||||
(binding [*level* (read-string level)]
|
||||
(binding [*level* (if level (read-string level))]
|
||||
(doseq [task (:release-tasks project)]
|
||||
(let [current-project (project/init-project (project/read))]
|
||||
(main/resolve-and-apply current-project task))))))
|
||||
|
|
|
@ -12,55 +12,151 @@
|
|||
{:major 1
|
||||
:minor 0
|
||||
:patch 0
|
||||
:qualifier nil}
|
||||
:qualifier nil
|
||||
:snapshot nil}
|
||||
{:major "2.0.0-SNAPSHOT"
|
||||
:minor "1.1.0-SNAPSHOT"
|
||||
:patch "1.0.1-SNAPSHOT"}]
|
||||
:patch "1.0.1-SNAPSHOT"
|
||||
:release "1.0.0"
|
||||
:alpha "1.0.0-alpha1-SNAPSHOT"
|
||||
:beta "1.0.0-beta1-SNAPSHOT"
|
||||
:rc "1.0.0-RC1-SNAPSHOT"
|
||||
:qualifier "1.0.0-1-SNAPSHOT"}]
|
||||
|
||||
["1.2.3"
|
||||
{:major 1
|
||||
:minor 2
|
||||
:patch 3
|
||||
:qualifier nil}
|
||||
:qualifier nil
|
||||
:snapshot nil}
|
||||
{:major "2.0.0-SNAPSHOT"
|
||||
:minor "1.3.0-SNAPSHOT"
|
||||
:patch "1.2.4-SNAPSHOT"}]
|
||||
:patch "1.2.4-SNAPSHOT"
|
||||
:release "1.2.3"
|
||||
:alpha "1.2.3-alpha1-SNAPSHOT"
|
||||
:beta "1.2.3-beta1-SNAPSHOT"
|
||||
:rc "1.2.3-RC1-SNAPSHOT"
|
||||
:qualifier "1.2.3-1-SNAPSHOT"}]
|
||||
|
||||
["1.2.3-herp"
|
||||
{:major 1
|
||||
:minor 2
|
||||
:patch 3
|
||||
:qualifier "herp"}
|
||||
:qualifier "herp"
|
||||
:snapshot nil}
|
||||
{:major "2.0.0-SNAPSHOT"
|
||||
:minor "1.3.0-SNAPSHOT"
|
||||
:patch "1.2.4-SNAPSHOT"
|
||||
:release "1.2.3"}]
|
||||
:release "1.2.3"
|
||||
:alpha "1.2.3-alpha1-SNAPSHOT"
|
||||
:beta "1.2.3-beta1-SNAPSHOT"
|
||||
:rc "1.2.3-RC1-SNAPSHOT"
|
||||
:qualifier "1.2.3-herp1-SNAPSHOT"}]
|
||||
|
||||
["1.0.0-SNAPSHOT"
|
||||
{:major 1
|
||||
:minor 0
|
||||
:patch 0
|
||||
:qualifier "SNAPSHOT"}
|
||||
:qualifier nil
|
||||
:snapshot "SNAPSHOT"}
|
||||
{:major "2.0.0-SNAPSHOT"
|
||||
:minor "1.1.0-SNAPSHOT"
|
||||
:patch "1.0.1-SNAPSHOT"
|
||||
:release "1.0.0"
|
||||
:alpha "1.0.0-alpha1"
|
||||
:beta "1.0.0-beta1"
|
||||
:rc "1.0.0-RC1"}]
|
||||
:alpha "1.0.0-alpha1-SNAPSHOT"
|
||||
:beta "1.0.0-beta1-SNAPSHOT"
|
||||
:rc "1.0.0-RC1-SNAPSHOT"
|
||||
:qualifier "1.0.0-1-SNAPSHOT"}]
|
||||
|
||||
["1.0.0-alpha1"
|
||||
{:major 1
|
||||
:minor 0
|
||||
:patch 0
|
||||
:qualifier "alpha1"}
|
||||
:qualifier "alpha1"
|
||||
:snapshot nil}
|
||||
{:major "2.0.0-SNAPSHOT"
|
||||
:minor "1.1.0-SNAPSHOT"
|
||||
:patch "1.0.1-SNAPSHOT"
|
||||
:release "1.0.0"
|
||||
:alpha "1.0.0-alpha2"
|
||||
:beta "1.0.0-beta1"
|
||||
:rc "1.0.0-RC1"}]])
|
||||
:alpha "1.0.0-alpha2-SNAPSHOT"
|
||||
:beta "1.0.0-beta1-SNAPSHOT"
|
||||
:rc "1.0.0-RC1-SNAPSHOT"
|
||||
:qualifier "1.0.0-alpha2-SNAPSHOT"}]
|
||||
|
||||
["1.0.0-alpha1-SNAPSHOT"
|
||||
{:major 1
|
||||
:minor 0
|
||||
:patch 0
|
||||
:qualifier "alpha1"
|
||||
:snapshot "SNAPSHOT"}
|
||||
{:major "2.0.0-SNAPSHOT"
|
||||
:minor "1.1.0-SNAPSHOT"
|
||||
:patch "1.0.1-SNAPSHOT"
|
||||
:release "1.0.0-alpha1"
|
||||
:alpha "1.0.0-alpha2-SNAPSHOT"
|
||||
:beta "1.0.0-beta1-SNAPSHOT"
|
||||
:rc "1.0.0-RC1-SNAPSHOT"
|
||||
:qualifier "1.0.0-alpha2-SNAPSHOT"}]
|
||||
|
||||
["1.0.0-beta1"
|
||||
{:major 1
|
||||
:minor 0
|
||||
:patch 0
|
||||
:qualifier "beta1"
|
||||
:snapshot nil}
|
||||
{:major "2.0.0-SNAPSHOT"
|
||||
:minor "1.1.0-SNAPSHOT"
|
||||
:patch "1.0.1-SNAPSHOT"
|
||||
:release "1.0.0"
|
||||
:alpha "1.0.0-alpha1-SNAPSHOT"
|
||||
:beta "1.0.0-beta2-SNAPSHOT"
|
||||
:rc "1.0.0-RC1-SNAPSHOT"
|
||||
:qualifier "1.0.0-beta2-SNAPSHOT"}]
|
||||
|
||||
["1.0.0-RC2-SNAPSHOT"
|
||||
{:major 1
|
||||
:minor 0
|
||||
:patch 0
|
||||
:qualifier "RC2"
|
||||
:snapshot "SNAPSHOT"}
|
||||
{:major "2.0.0-SNAPSHOT"
|
||||
:minor "1.1.0-SNAPSHOT"
|
||||
:patch "1.0.1-SNAPSHOT"
|
||||
:release "1.0.0-RC2"
|
||||
:alpha "1.0.0-alpha1-SNAPSHOT"
|
||||
:beta "1.0.0-beta1-SNAPSHOT"
|
||||
:rc "1.0.0-RC3-SNAPSHOT"
|
||||
:qualifier "1.0.0-RC3-SNAPSHOT"}]
|
||||
|
||||
["1.2.3-herp2"
|
||||
{:major 1
|
||||
:minor 2
|
||||
:patch 3
|
||||
:qualifier "herp2"
|
||||
:snapshot nil}
|
||||
{:major "2.0.0-SNAPSHOT"
|
||||
:minor "1.3.0-SNAPSHOT"
|
||||
:patch "1.2.4-SNAPSHOT"
|
||||
:release "1.2.3"
|
||||
:alpha "1.2.3-alpha1-SNAPSHOT"
|
||||
:beta "1.2.3-beta1-SNAPSHOT"
|
||||
:rc "1.2.3-RC1-SNAPSHOT"
|
||||
:qualifier "1.2.3-herp3-SNAPSHOT"}]
|
||||
|
||||
["1.2.3-25"
|
||||
{:major 1
|
||||
:minor 2
|
||||
:patch 3
|
||||
:qualifier "25"
|
||||
:snapshot nil}
|
||||
{:major "2.0.0-SNAPSHOT"
|
||||
:minor "1.3.0-SNAPSHOT"
|
||||
:patch "1.2.4-SNAPSHOT"
|
||||
:release "1.2.3"
|
||||
:alpha "1.2.3-alpha1-SNAPSHOT"
|
||||
:beta "1.2.3-beta1-SNAPSHOT"
|
||||
:rc "1.2.3-RC1-SNAPSHOT"
|
||||
:qualifier "1.2.3-26-SNAPSHOT"}]])
|
||||
|
||||
(deftest test-string->semantic-version
|
||||
(testing "Testing semantic version string parsing"
|
||||
|
@ -88,6 +184,7 @@
|
|||
(deftest version-map->string-valid
|
||||
(doseq [[string parsed bumps] valid-semver-version-values]
|
||||
(is (= string (version-map->string parsed)))
|
||||
(doseq [[level string] bumps]
|
||||
(is (= (merge {:qualifier nil} (bump-version-map parsed level))
|
||||
(parse-semantic-version string))))))
|
||||
(doseq [[level expected-bumped-string] bumps]
|
||||
(let [bumped (bump-version-map parsed level)]
|
||||
(is (= bumped (parse-semantic-version expected-bumped-string)))
|
||||
(is (= expected-bumped-string (version-map->string bumped)))))))
|
Loading…
Reference in a new issue