From 2980a567f99632eb09c7ae6f300522231007a2b7 Mon Sep 17 00:00:00 2001 From: ejschoen Date: Fri, 14 Jun 2019 11:05:53 -0500 Subject: [PATCH 1/3] Allow for additional arguments to docker-build. Define build, push, and rmi as official subtasks to Leiningen so that lein help docker {{subtask}} works --- src/leiningen/docker.clj | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/leiningen/docker.clj b/src/leiningen/docker.clj index 048abfe..4107d9d 100644 --- a/src/leiningen/docker.clj +++ b/src/leiningen/docker.clj @@ -7,9 +7,15 @@ (apply main/debug "Exec: docker" args) (apply eval/sh "docker" args)) -(defn- build [image dockerfile build-dir] - (main/info "Building Docker image:" image) - (let [exit-code (exec "build" "-f" dockerfile "-t" image build-dir)] +(defn- build + "lein docker build [image-name [additional-arguments-to-build]] + Builds image name. + additional-arguments are inserted into the build command line before the final path argument." + [image dockerfile build-dir additional-args] + (if (not-empty additional-args) + (main/info "Building Docker image:" image "with additional args:" additional-args) + (main/info "Building Docker image:" image)) + (let [exit-code (apply exec "build" "-f" dockerfile "-t" image (concat additional-args [build-dir]))] (if (zero? exit-code) (main/info "Docker image built.") (do @@ -25,7 +31,10 @@ (main/warn "Docker image could not be tagged.") (main/exit exit-code))))) -(defn- push [image] +(defn- push + "lein docker push [image-name] + Pushes image-name to its registry" + [image] (main/info "Pushing Docker image:" image) (let [exit-code (exec "push" image)] (if (zero? exit-code) @@ -42,7 +51,9 @@ (main/warn err) (main/exit exit))))) -(defn- rmi [image] +(defn- rmi + "Remove an image from the local docker system." + [image] (when (image-exists? image) (main/info "Removing docker image:" image) (let [exit-code (exec "rmi" image)] @@ -60,7 +71,8 @@ 'build' builds your docker image 'push' pushes your docker image 'rmi' removes your docker image" - [project command & [image-name]] + {:subtasks [#'build #'push #'rmi]} + [project command & [image-name & additional-args]] (let [command (keyword command)] @@ -84,7 +96,7 @@ (case command :build (do - (build (first images) dockerfile build-dir) + (build (first images) dockerfile build-dir additional-args) (doseq [image (rest images)] (tag (first images) image))) :push (doseq [image images] From 181a86ab0644db7557a7e92ed28e40e0262221c5 Mon Sep 17 00:00:00 2001 From: ejschoen Date: Sun, 16 Jun 2019 10:25:45 -0500 Subject: [PATCH 2/3] Add ability to inject environment variables into docker configuration map strings --- README.md | 26 ++++++++++++++++++++++---- src/leiningen/docker.clj | 27 ++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 049bbac..d778489 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,24 @@ 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 Jenkiuns 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. 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 From 6841191f525d6f6023d2019832a517a1af8ea355 Mon Sep 17 00:00:00 2001 From: ejschoen Date: Sun, 16 Jun 2019 10:38:32 -0500 Subject: [PATCH 3/3] README.md fix --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d778489..ba1f3c7 100644 --- a/README.md +++ b/README.md @@ -50,11 +50,14 @@ values from the environment. For example: :tags ["%s-${BUILD_NUMBER:-unknown}"]} ``` -Running `lein docker build` command under Jenkiuns line will generate an image tagged with the +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. Environment -variable injection is supported for the `:image-name`, `:tags`, `:dockerfile`, and `:build-dir` -entries in the project's `:docker` map. +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