WIP: merge change task and release.

This commit is contained in:
Phil Hagelberg 2014-05-24 09:59:29 -07:00
parent 80d4f130fc
commit c83b2facfe
4 changed files with 69 additions and 81 deletions

View file

@ -181,17 +181,17 @@
:clean-targets ^:top-displace [:target-path] :clean-targets ^:top-displace [:target-path]
;; TODO: remove :top-displace for :prep-tasks in 3.0 ;; TODO: remove :top-displace for :prep-tasks in 3.0
:prep-tasks ^:top-displace ["javac" "compile"] :prep-tasks ^:top-displace ["javac" "compile"]
:prep-tasks ^:top-displace [["vcs" "assert-committed"] :release-tasks ^:top-displace [["vcs" "assert-committed"]
["change" "version" ["change" "version"
"leiningen.release/bump-version" "release"] "leiningen.release/bump-version" "release"]
["vcs" "commit"] ["vcs" "commit"]
["vcs" "tag"] ["vcs" "tag"]
["deploy"] ["deploy"]
["change" "version" ["change" "version"
;; TODO: level here should come from task arg ;; TODO: level here should come from task arg
"leiningen.release/bump-version" "minor"] "leiningen.release/bump-version" "minor"]
["vcs" "commit"] ["vcs" "commit"]
["vcs" "push"]] ["vcs" "push"]]
:jar-exclusions [#"^\."] :jar-exclusions [#"^\."]
:certificates ["clojars.pem"] :certificates ["clojars.pem"]
:offline? (not (nil? (System/getenv "LEIN_OFFLINE"))) :offline? (not (nil? (System/getenv "LEIN_OFFLINE")))

View file

@ -1,8 +1,10 @@
(ns leiningen.change (ns leiningen.change
"Rewrite project.clj by applying a function."
(:require [clojure.string :as str] (:require [clojure.string :as str]
[clojure.zip :as zip] [clojure.zip :as zip]
[net.cgrand.sjacket :refer [str-pt]] [clojure.java.io :as io]
[net.cgrand.sjacket.parser :refer [parser]])) [net.cgrand.sjacket :as sj]
[net.cgrand.sjacket.parser :as parser]))
;;; Helpers ;;; Helpers
@ -12,39 +14,22 @@
(defn- clj->sjacket [value] (defn- clj->sjacket [value]
(if (string? value) (if (string? value)
(str "\"" value "\"") (str "\"" value "\"")
(-> value print-str parser :content first))) (-> value print-str parser/parser :content first)))
;; NOTE: this destroy comments, formatting, etc. ;; NOTE: this destroy comments, formatting, etc.
;; NOTE: read-string may throw parse errors on badly formed config..
;; is this an issue or will files already have been sanity
;; checked before this task can run?
(defn- sjacket->clj [value] (defn- sjacket->clj [value]
(->> value str-pt read-string)) (->> value sj/str-pt read-string))
(defn- lookup-var [x] (defn ^:internal normalize-path [value]
;; ensure it's a namespaced var reference to avoid error (if (coll? value)
(if (re-find #"^[a-zA-Z]+\..+\/.+$" x) value
(-> x symbol find-var var-get))) (map keyword (remove empty? (str/split value #":")))))
(defn ^:internal normalize-path (defn ^:internal collapse-fn [f args]
"Coerce scalars, colls and cli-encoded lists of symbols/strings into keyword vector" (let [f (if (ifn? f)
[value] f
(mapv keyword (resolve (symbol f)))]
(if (coll? value) #(apply f % args)))
(map name value)
(let [value (name value)]
(if (re-find #":" (name value))
(remove empty? (str/split (name value) #":"))
[(name value)])))))
(defn ^:internal collapse-fn
"Partially apply args to right if fn, else return constant of first arg.
If string corresponds to a namespaced var, substite value for string"
[fn args]
(let [fn' (or (and (string? fn) (lookup-var fn)) fn)]
(if (fn? fn')
#(apply fn' % args)
(constantly fn'))))
;;; Traversal ;;; Traversal
@ -84,8 +69,8 @@
(remove (comp #{:whitespace :comment} :tag zip/node)) (remove (comp #{:whitespace :comment} :tag zip/node))
first)) first))
(defn- get-project [project-str] (defn- parse-project [project-str]
(-> (parser project-str) (-> (parser/parser project-str)
zip/xml-zip zip/xml-zip
find-defproject find-defproject
(or (fail-argument! "Project definition not found")) (or (fail-argument! "Project definition not found"))
@ -123,20 +108,23 @@
;;; Public API ;;; Public API
(defn change* (defn change-string
[project-str key-or-path fn & args] [project-str key-or-path f & args]
(let [fn' (collapse-fn fn args) (let [f (collapse-fn f args)
fn'' (comp clj->sjacket fn' sjacket->clj) wrapped-f (comp clj->sjacket f sjacket->clj)
path (normalize-path key-or-path) path (normalize-path key-or-path)
proj (get-project project-str)] proj (parse-project project-str)]
(str-pt (sj/str-pt
;; TODO: support :artifact-id, :group-id
(if (= path [:version]) (if (= path [:version])
(update-version proj fn'') (update-version proj wrapped-f)
(update-setting proj path fn''))))) (update-setting proj path wrapped-f)))))
(defn change (defn change
"Rewrite project.clj with new settings" "Rewrite project.clj with f applied to the value at key-or-path.
[project & args]
;; cannot work with project, want to preserve formatting, comments, etc TODO: document accepted args."
(let [source (slurp "project.clj")] [project key-or-path f & args]
(spit "project.clj" (apply change* source args)))) ;; cannot work with project map, want to preserve formatting, comments, etc
(let [source (slurp (io/file (:root project) "project.clj"))]
(spit "project.clj" (apply change-string source key-or-path f args))))

View file

@ -13,23 +13,23 @@
(testing "project definition not found" (testing "project definition not found"
(is (thrown-with-msg? (is (thrown-with-msg?
IllegalArgumentException #"Project definition not found" IllegalArgumentException #"Project definition not found"
(change* ";;(defproject stealth.library \"0.0.0\")" (change-string ";;(defproject stealth.library \"0.0.0\")"
:version "0.0.1")))) :version "0.0.1"))))
(testing "project version not found" (testing "project version not found"
(is (thrown-with-msg? (is (thrown-with-msg?
IllegalArgumentException #"Project version not found" IllegalArgumentException #"Project version not found"
(change* "(defproject com.someproject :dependencies [[\"some.thing\" \"2.3.1\"]])" (change-string "(defproject com.someproject :dependencies [[\"some.thing\" \"2.3.1\"]])"
:version "1.2.3")))) :version "1.2.3"))))
(testing "simplest possible case" (testing "simplest possible case"
(is (= "(defproject leingingen.change \"0.0.2-SNAPSHOT\")" (is (= "(defproject leingingen.change \"0.0.2-SNAPSHOT\")"
(change* "(defproject leingingen.change \"0.0.1\")" (change-string "(defproject leingingen.change \"0.0.1\")"
:version "0.0.2-SNAPSHOT")))) :version "0.0.2-SNAPSHOT"))))
(testing "the largest project.clj in the repo" (testing "the largest project.clj in the repo"
(let [before (slurp (clojure.java.io/resource "leiningen/help/project.clj")) (let [before (slurp (clojure.java.io/resource "leiningen/help/project.clj"))
after (change* before :version "6.4.1")] after (change-string before :version "6.4.1")]
;; check the key portion ;; check the key portion
(is (= "(defproject org.example/sample \"6.4.1\" " (.substring after 529 568))) (is (= "(defproject org.example/sample \"6.4.1\" " (.substring after 529 568)))
;; check a random dependency for changes ;; check a random dependency for changes
@ -38,42 +38,42 @@
(deftest test-external-function (deftest test-external-function
(testing "regular function by function reference" (testing "regular function by function reference"
(is (= "(defproject leingingen.change \"1.9.53-SNAPSHOT\")" (is (= "(defproject leingingen.change \"1.9.53-SNAPSHOT\")"
(change* "(defproject leingingen.change \"1.9.52-SNAPSHOT\")" (change-string "(defproject leingingen.change \"1.9.52-SNAPSHOT\")"
:version bump-version)))) :version bump-version))))
(testing "regular function by function reference" (testing "regular function by function reference"
(is (= "(defproject leingingen.change \"1.9.53-SNAPSHOT\")" (is (= "(defproject leingingen.change \"1.9.53-SNAPSHOT\")"
(change* "(defproject leingingen.change \"1.9.52-SNAPSHOT\")" (change-string "(defproject leingingen.change \"1.9.52-SNAPSHOT\")"
:version "leiningen.test.change/bump-version"))))) :version "leiningen.test.change/bump-version")))))
(deftest test-set-regular-key (deftest test-set-regular-key
(testing "can set a key" (testing "can set a key"
(is (= "(defproject leingingen.change \"0.0.1\" :description \"a dynamic description\")" (is (= "(defproject leingingen.change \"0.0.1\" :description \"a dynamic description\")"
(change* "(defproject leingingen.change \"0.0.1\" :description \"a static description\")" (change-string "(defproject leingingen.change \"0.0.1\" :description \"a static description\")"
:description "a dynamic description")))) :description "a dynamic description"))))
(testing "can create a new key" (testing "can create a new key"
(is (= "(defproject leingingen.change \"0.0.1\" :description \"a dynamic description\")" (is (= "(defproject leingingen.change \"0.0.1\" :description \"a dynamic description\")"
(change* "(defproject leingingen.change \"0.0.1\")" (change-string "(defproject leingingen.change \"0.0.1\")"
:description "a dynamic description"))))) :description "a dynamic description")))))
(deftest test-nested-key (deftest test-nested-key
(testing "can set a nested key" (testing "can set a nested key"
(is (= "(defproject leingingen.change \"0.0.1\" :license {:url \"http://example.com\"})" (is (= "(defproject leingingen.change \"0.0.1\" :license {:url \"http://example.com\"})"
(change* "(defproject leingingen.change \"0.0.1\" :license {:url \"http://old.com\"})" (change-string "(defproject leingingen.change \"0.0.1\" :license {:url \"http://old.com\"})"
[:license :url] "http://example.com")))) [:license :url] "http://example.com"))))
(testing "can create a nested value" (testing "can create a nested value"
(is (= "(defproject leingingen.change \"0.0.1\" :a {:b {:c 1}})" (is (= "(defproject leingingen.change \"0.0.1\" :a {:b {:c 1}})"
(change* "(defproject leingingen.change \"0.0.1\")" (change-string "(defproject leingingen.change \"0.0.1\")"
[:a :b :c] 1)))) [:a :b :c] 1))))
(testing "can understand cli short form" (testing "can understand cli short form"
(is (= "(defproject leingingen.change \"0.0.1\" :license {:url \"http://example.com\"})" (is (= "(defproject leingingen.change \"0.0.1\" :license {:url \"http://example.com\"})"
(change* "(defproject leingingen.change \"0.0.1\")" (change-string "(defproject leingingen.change \"0.0.1\")"
:license:url "http://example.com"))))) :license:url "http://example.com")))))
(deftest test-normalize-path (deftest test-normalize-path
(is (= [:a] (is (= [:a]

View file

@ -69,7 +69,7 @@
(is (= (nth semver-test-data 2) (is (= (nth semver-test-data 2)
(version-map->string (second semver-test-data)))))) (version-map->string (second semver-test-data))))))
(deftest test-increment-version (deftest test-bump-version
(testing "Testing semantic version increment" (testing "Testing semantic version increment"
(doseq [semver-test-data valid-semver-version-values] (doseq [semver-test-data valid-semver-version-values]
(testing (format "with valid version: %s\n" (testing (format "with valid version: %s\n"
@ -77,5 +77,5 @@
(doseq [[k v] (map identity (nth semver-test-data 3))] (doseq [[k v] (map identity (nth semver-test-data 3))]
(testing (format "version-level %s" (name k)) (testing (format "version-level %s" (name k))
(is (= v (version-map->string (is (= v (version-map->string
(increment-version (bump-version
(nth semver-test-data 1) k)))))))))) (nth semver-test-data 1) k))))))))))