diff --git a/README.md b/README.md index 049bbac..ba1f3c7 100644 --- a/README.md +++ b/README.md @@ -9,16 +9,16 @@ A Leiningen plugin to build and deploy [Docker](https://www.docker.com/) images. Add docker-deploy to your plugin list in your `project.clj`: ```clojure -:plugins [[gorillalabs/lein-docker "1.3.0"]] +:plugins [[gorillalabs/lein-docker "1.6.0"]] ``` (see version badge above for newest release) Available commands: - $ lein docker build - $ lein docker push - $ lein docker rmi + $ lein docker build [image-name [additional-arguments ... ]] + $ lein docker push [image-name] + $ lein docker rmi [image-name] ## Configuration @@ -38,6 +38,27 @@ Defaults: * `:dockerfile` points to `Dockerfile` * `:build-dir` points to the project's root +### Injecting environment variables into configuration + +With a CI/CD pipeline such as Jenkins, you may want to generate Docker artifacts tagged +against specific properties of a build run. The values in the :docker configuration options +may contain bash-like references to environment variables, which will be replaced with +values from the environment. For example: + +```clojure +:docker {:image-name "myregistry.example.org/myimage" + :tags ["%s-${BUILD_NUMBER:-unknown}"]} +``` + +Running `lein docker build` command under Jenkins line will generate an image tagged with the +project number and build number (e.g., 1.6.0-306). If BUILD_NUMBER is undefined, as when +outside of Jenkins, then the default value ("unknown") will be spliced in instead. If the +environment variable expression does not contain a default string and the referenced +environment variable is not defined, the expression is replaced with the empty string. + +Environment variable injection is supported for the `:image-name`, `:tags`, `:dockerfile`, +and `:build-dir` entries in the project's `:docker` map. + ## Releasing your docker images You can use Leiningen to handle your technical release process. diff --git a/src/leiningen/docker.clj b/src/leiningen/docker.clj index 4107d9d..b9c902c 100644 --- a/src/leiningen/docker.clj +++ b/src/leiningen/docker.clj @@ -1,7 +1,23 @@ (ns leiningen.docker (:require [leiningen.core.eval :as eval] [leiningen.core.main :as main] - [clojure.java.shell :as shell])) + [clojure.java.shell :as shell] + [clojure.string :as str])) + +(def var-matcher-pattern #"\$\{(?[A-Za-z0-9_]+)(?::-(?[^}]+))?\}") + +(defn inject-environment-variables + "Given a string, replace text of the form ${NAME} or ${NAME:-default} + with the environment variable value corresponding to NAME. + In the second form, if NAME is not defined, use the default string. + If the default string is not provided and NAME is not defined, replace + the expression with the empty string." + [string] + (reduce (fn [s [match environment-variable default]] + (let [replacement (or (System/getenv environment-variable) default "")] + (str/replace s match replacement))) + string + (re-seq var-matcher-pattern string))) (defn- exec [& args] (apply main/debug "Exec: docker" args) @@ -63,6 +79,7 @@ (main/warn "Docker image could not be removed.") (main/exit exit-code)))))) + (def valid-command? #{:build :push :rmi}) (defn docker @@ -82,16 +99,16 @@ (let [config (:docker project) image-name (or image-name - (:image-name config) + (inject-environment-variables (:image-name config)) (str (:name project))) tags (or (:tags config) ["%s"]) images (map - #(str image-name ":" (format % (:version project))) + #(str image-name ":" (format (inject-environment-variables %) (:version project))) tags) - build-dir (or (:build-dir config) + build-dir (or (inject-environment-variables (:build-dir config)) (:root project)) - dockerfile (or (:dockerfile config) + dockerfile (or (inject-environment-variables (:dockerfile config)) "Dockerfile")] (case command