diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb48e00f..0ad64e7e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: - name: Install babashka uses: DeLaGuardo/setup-clojure@12.5 with: - bb: 1.3.190 + bb: 1.3.191 - uses: actions/checkout@v4 - name: Check for stale Dockerfiles run: | diff --git a/.github/workflows/official-images-pr.yml b/.github/workflows/official-images-pr.yml index c5a6d4c8..df70e21a 100644 --- a/.github/workflows/official-images-pr.yml +++ b/.github/workflows/official-images-pr.yml @@ -14,7 +14,7 @@ jobs: - name: Install babashka uses: DeLaGuardo/setup-clojure@12.5 with: - bb: 1.3.190 + bb: 1.3.191 - name: Checkout code uses: actions/checkout@v4 - name: Generate manifest @@ -67,7 +67,7 @@ jobs: github-username: ${{ github.actor }} token: ${{ secrets.API_TOKEN_GITHUB }} - name: Open official-images pull request - uses: peter-evans/create-pull-request@v6 + uses: peter-evans/create-pull-request@v7 with: token: ${{ secrets.API_TOKEN_GITHUB }} path: official-images diff --git a/bb.edn b/bb.edn index d1828062..0c62b9bd 100644 --- a/bb.edn +++ b/bb.edn @@ -11,5 +11,9 @@ build-images {:task (apply dc/-main "build-images" *command-line-args*)} test {:extra-paths ["test"] :requires ([docker-clojure.test-runner :as tr]) - :task (tr/-main 'docker-clojure.core-test 'docker-clojure.dockerfile-test - 'docker-clojure.manifest-test)}}} + :task (tr/-main + 'docker-clojure.core-test + 'docker-clojure.docker-test + 'docker-clojure.dockerfile-test + 'docker-clojure.manifest-test + 'docker-clojure.variant-test)}}} diff --git a/src/docker_clojure/config.clj b/src/docker_clojure/config.clj index 18b894a7..5a606c5b 100644 --- a/src/docker_clojure/config.clj +++ b/src/docker_clojure/config.clj @@ -55,14 +55,9 @@ "debian" #{:debian-slim/bookworm-slim :debian/bookworm :debian-slim/bullseye-slim :debian/bullseye}}) -(def default-architectures +(def architectures #{"amd64" "arm64v8"}) -(def distro-architectures - "Map of distro types to architectures it supports if different from - default-architectures." - {:alpine #{"amd64"}}) - (def default-distros "The default distro to use for tags that don't specify one, keyed by jdk-version. :default is a fallback for jdk versions not o/w specified." @@ -84,9 +79,10 @@ "1.12.0.1479" "94f29b9b66183bd58307c46fb561fd9e9148666bac13a4518a9931b6f989d830"}}) (def exclusions ; don't build these for whatever reason(s) - #{;; commented out example - #_{:jdk-version 8 - :distro :alpine/alpine}}) + #{;; No upstream ARM alpine images available before JDK 21 + {:jdk-version #(< % 21) + :architecture "arm64v8" + :distro :alpine/alpine}}) (def maintainers ["Paul Lam (@Quantisan)" diff --git a/src/docker_clojure/core.clj b/src/docker_clojure/core.clj index a1e2a384..c8ac88d1 100644 --- a/src/docker_clojure/core.clj +++ b/src/docker_clojure/core.clj @@ -1,158 +1,51 @@ (ns docker-clojure.core (:require + [clojure.core.async :refer [ distro namespace keyword)) - base {:jdk-version jdk-version - :base-image base-image - :base-image-tag (base-image-tag base-image - jdk-version distro) - :distro distro - :build-tool build-tool - :build-tool-version build-tool-version - :maintainer (str/join " & " cfg/maintainers)}] - (-> base - (assoc :docker-tag (default-docker-tag base)) - (assoc-if #(nil? (:build-tool-version base)) :build-tool-versions - cfg/build-tools) - (assoc-if #(seq variant-arch) :architectures variant-arch)))) - -(defn pull-image [image] - (sh "docker" "pull" image)) + :opt-un [::cfg/build-tool-versions ::cfg/architecture])) -(defn generate-dockerfile! [installer-hashes variant] - (let [build-dir (df/build-dir variant) - filename "Dockerfile"] - (log "Generating" (str build-dir "/" filename)) - (df/write-file build-dir filename installer-hashes variant) - (assoc variant - :build-dir build-dir - :dockerfile filename))) - -(defn build-image - [installer-hashes {:keys [docker-tag base-image architectures] :as variant}] - (let [image-tag (str "clojure:" docker-tag) - _ (log "Pulling base image" base-image) - _ (pull-image base-image) - - {:keys [dockerfile build-dir]} - (generate-dockerfile! installer-hashes variant) - - host-arch (let [jvm-arch (System/getProperty "os.arch")] - (if (= "aarch64" jvm-arch) - "arm64v8" - jvm-arch)) - platform-flag (if (contains? (or architectures - cfg/default-architectures) - host-arch) - nil - (str "--platform=linux/" (first architectures))) - - build-cmd (remove nil? ["docker" "buildx" "build" "--no-cache" - "-t" image-tag platform-flag "--load" - "-f" dockerfile "."])] - (apply log "Running" build-cmd) - (let [{:keys [out err exit]} - (with-sh-dir build-dir (apply sh build-cmd))] - (if (zero? exit) - (log "Succeeded building" (str "clojure:" docker-tag)) - (log "ERROR building" (str "clojure:" docker-tag ":") err out)))) - (log) - [::done variant]) - -(def latest-variant +(def latest-variants "The latest variant is special because we include all 3 build tools via the [::all] value on the end." - (list (-> cfg/base-images :default first) - cfg/default-jdk-version - (get-or-default cfg/default-distros cfg/default-jdk-version) - [::all])) - -(defn image-variant-combinations - [base-images jdk-versions distros build-tools] - (reduce - (fn [variants jdk-version] - (concat - variants - (let [jdk-base-images (get-or-default base-images jdk-version)] - (loop [[bi & r] jdk-base-images - acc #{}] - (let [vs (combo/cartesian-product #{bi} - #{jdk-version} - (get-or-default distros bi) - build-tools) - acc' (concat acc vs)] - (if (seq r) - (recur r acc') - acc')))))) - #{} jdk-versions)) + (for [arch cfg/architectures] + (list (-> cfg/base-images :default first) + cfg/default-jdk-version + (get-or-default cfg/default-distros cfg/default-jdk-version) + [::all] + arch))) (defn image-variants - [base-images jdk-versions distros build-tools] + [base-images jdk-versions distros build-tools architectures] (into #{} (comp - (map variant-map) + (map variant/->map) (remove #(= ::s/invalid (s/conform ::variant %)))) - (conj - (image-variant-combinations base-images jdk-versions distros - build-tools) - latest-variant))) + (concat + (variant/combinations base-images jdk-versions distros build-tools + architectures) + latest-variants))) (defn rand-delay "Runs argument f w/ any supplied args after a random delay of 100-1000 ms" @@ -164,12 +57,12 @@ (defn build-images [parallelization installer-hashes variants] (log "Building images" parallelization "at a time") - (let [variants-ch (to-chan! variants) - builds-ch (chan parallelization)] + (let [variants-ch (to-chan! variants) + builds-ch (chan parallelization)] ;; Kick off builds with a random delay so we don't have Docker race ;; conditions (e.g. build container name collisions) (async/thread (pipeline-blocking parallelization builds-ch - (map (partial rand-delay build-image + (map (partial rand-delay docker/build-image installer-hashes)) variants-ch)) (while (> ["git" "rev-parse" "HEAD"] (apply sh) :out) target-file (or (first args) :stdout) manifest (manifest/generate {:maintainers cfg/maintainers - :architectures cfg/default-architectures + :architectures cfg/architectures :git-repo cfg/git-repo} git-head variants)] (log "Writing manifest of" (count variants) "variants to" target-file "...") @@ -199,24 +92,6 @@ (when (not= :stdout target-file) (.close output-writer))))) -(defn sort-variants - [variants] - (sort - (fn [v1 v2] - (cond - (= "latest" (:docker-tag v1)) -1 - (= "latest" (:docker-tag v2)) 1 - :else (let [c (compare (:jdk-version v1) (:jdk-version v2))] - (if (not= c 0) - c - (let [c (compare (full-docker-tag v1) (full-docker-tag v2))] - (if (not= c 0) - c - (throw - (ex-info "No two variants should have the same full Docker tag" - {:v1 v1, :v2 v2})))))))) - variants)) - (defn generate-variants [args] (let [key-vals (->> args @@ -239,7 +114,7 @@ (case cmd :clean (df/clean-all) :dockerfiles (generate-dockerfiles! cfg/installer-hashes variants) - :manifest (-> variants sort-variants (generate-manifest! args)) + :manifest (generate-manifest! variants args) :build-images (build-images parallelization cfg/installer-hashes variants))) (logger/stop)) diff --git a/src/docker_clojure/docker.clj b/src/docker_clojure/docker.clj new file mode 100644 index 00000000..c1013398 --- /dev/null +++ b/src/docker_clojure/docker.clj @@ -0,0 +1,115 @@ +(ns docker-clojure.docker + (:require [clojure.java.shell :refer [sh with-sh-dir]] + [clojure.string :as str] + [docker-clojure.config :as cfg] + [docker-clojure.core :as-alias core] + [docker-clojure.dockerfile :as df] + [docker-clojure.util :refer [get-or-default]] + [docker-clojure.log :refer [log]])) + +(defn pull-image [image] + (sh "docker" "pull" image)) + +(defn build-image + [installer-hashes {:keys [docker-tag base-image architecture] :as variant}] + (let [image-tag (str "clojure:" docker-tag) + _ (log "Pulling base image" base-image) + _ (pull-image base-image) + + {:keys [dockerfile build-dir]} + (df/generate! installer-hashes variant) + + host-arch (let [jvm-arch (System/getProperty "os.arch")] + (if (= "aarch64" jvm-arch) + "arm64v8" + jvm-arch)) + platform-flag (if (= architecture host-arch) + nil + (str "--platform=linux/" architecture)) + + build-cmd (remove nil? ["docker" "buildx" "build" "--no-cache" + "-t" image-tag platform-flag "--load" + "-f" dockerfile "."])] + (apply log "Running" build-cmd) + (let [{:keys [out err exit]} + (with-sh-dir build-dir (apply sh build-cmd))] + (if (zero? exit) + (log "Succeeded building" (str "clojure:" docker-tag)) + (log "ERROR building" (str "clojure:" docker-tag ":") err out)))) + (log) + [::done variant]) + +(defn base-image-tag + [base-image jdk-version distro] + (str base-image ":" + (case base-image + "eclipse-temurin" (str jdk-version "-jdk-") + "debian" "" + "-") + (name distro))) + +(defn jdk-label + [omit-default? jdk-version base-image] + (if (and omit-default? (= cfg/default-jdk-version jdk-version) + (= (first (get-or-default cfg/base-images jdk-version)) + base-image)) + nil + (str + (case base-image + ("eclipse-temurin" "debian") "temurin" + base-image) + "-" jdk-version))) + +(defn tag + "Returns the Docker tag for the given variant with truthy keys from first arg + left out when possible." + [{:keys [omit-all? omit-jdk? omit-build-tool? omit-build-tool-version? + omit-distro?]} + {:keys [base-image jdk-version distro build-tool + build-tool-version] :as _variant}] + (if (= ::core/all build-tool) + "latest" + (let [jdk (jdk-label (or omit-all? omit-jdk?) + jdk-version base-image) + dd (get-or-default cfg/default-distros jdk-version) + distro-label (if (and (or omit-all? omit-distro?) (= dd distro)) + nil + (when distro (name distro))) + tag-elements (remove nil? [jdk distro-label]) + build-tool-label (if (and (seq tag-elements) ; ensure tag is non-empty + (or omit-all? omit-build-tool?) + (= build-tool cfg/default-build-tool)) + nil + build-tool) + build-tool-version-label (if (or omit-all? omit-build-tool? + omit-build-tool-version?) + nil + build-tool-version)] + (str/join "-" (remove nil? [jdk build-tool-label + build-tool-version-label + distro-label]))))) + +(def full-tag + (partial tag {})) + +(def default-tag + (partial tag {:omit-jdk? true, :omit-distro? true})) + +(defn all-tags + "Returns all Docker tags for the given variant" + [variant] + (let [short-tag (:docker-tag variant) + full-tag (full-tag variant) + base (into #{} [short-tag full-tag])] + (-> base + (conj + (tag {:omit-jdk? true} variant) + (tag {:omit-build-tool? true} variant) + (tag {:omit-build-tool-version? true} variant) + (tag {:omit-distro? true} variant) + (tag {:omit-distro? true, :omit-build-tool-version? true} variant) + (tag {:omit-jdk? true, :omit-build-tool-version? true} variant) + (tag {:omit-jdk? true, :omit-distro? true + :omit-build-tool-version? true} variant)) + vec + sort))) diff --git a/src/docker_clojure/dockerfile.clj b/src/docker_clojure/dockerfile.clj index ab3321fe..e2aa056c 100644 --- a/src/docker_clojure/dockerfile.clj +++ b/src/docker_clojure/dockerfile.clj @@ -4,7 +4,8 @@ [clojure.string :as str] [docker-clojure.dockerfile.lein :as lein] [docker-clojure.dockerfile.tools-deps :as tools-deps] - [docker-clojure.dockerfile.shared :refer [copy-resource-file! entrypoint]])) + [docker-clojure.dockerfile.shared :refer [copy-resource-file! entrypoint]] + [docker-clojure.log :refer [log]])) (defn build-dir [{:keys [base-image-tag jdk-version build-tool]}] (str/join "/" ["target" @@ -79,5 +80,14 @@ (throw (ex-info (str "Error creating directory " dir) {:error err}))))) +(defn generate! [installer-hashes variant] + (let [build-dir (build-dir variant) + filename "Dockerfile"] + (log "Generating" (str build-dir "/" filename)) + (write-file build-dir filename installer-hashes variant) + (assoc variant + :build-dir build-dir + :dockerfile filename))) + (defn clean-all [] (sh "sh" "-c" "rm -rf target/*")) diff --git a/src/docker_clojure/manifest.clj b/src/docker_clojure/manifest.clj index 7adb77f0..f74a1320 100644 --- a/src/docker_clojure/manifest.clj +++ b/src/docker_clojure/manifest.clj @@ -1,26 +1,8 @@ (ns docker-clojure.manifest (:require [clojure.string :as str] + [docker-clojure.docker :as docker] [docker-clojure.dockerfile :as df] - [docker-clojure.util :refer [docker-tag full-docker-tag]])) - -(defn variant-tags - "Generates all the Docker Hub tag variations for the given variant" - [variant] - (let [short-tag (:docker-tag variant) - full-tag (full-docker-tag variant) - base (into #{} [short-tag full-tag])] - (-> base - (conj - (docker-tag {:omit-jdk? true} variant) - (docker-tag {:omit-build-tool? true} variant) - (docker-tag {:omit-build-tool-version? true} variant) - (docker-tag {:omit-distro? true} variant) - (docker-tag {:omit-distro? true, :omit-build-tool-version? true} variant) - (docker-tag {:omit-jdk? true, :omit-build-tool-version? true} variant) - (docker-tag {:omit-jdk? true, :omit-distro? true - :omit-build-tool-version? true} variant)) - vec - sort))) + [docker-clojure.variant :as variant])) (defn variant->manifest [variant] @@ -28,19 +10,24 @@ (conj (remove nil? [(str/join " " (conj ["Tags:"] (->> variant - variant-tags + docker/all-tags (str/join ", ")))) (when-let [arch (:architectures variant)] - (str/join " " ["Architectures:" (str/join ", " arch)])) - (str/join " " ["Directory:" (df/build-dir variant)])]) + (str/join " " ["Architectures:" + (str/join ", " arch)])) + (str/join " " ["Directory:" + (df/build-dir variant)])]) nil))) (defn generate "Generates Docker manifest file for a given git commit and returns it as a string." [{:keys [maintainers architectures git-repo]} git-commit variants] - (let [maintainers-label "Maintainers:" - maintainers-sep (apply str ",\n" (repeat (inc (count maintainers-label)) " "))] + (let [merged-arch-variants (variant/merge-architectures variants + architectures) + maintainers-label "Maintainers:" + maintainers-sep (apply str ",\n" (repeat (inc (count maintainers-label)) + " "))] (str/join "\n" (concat [(str/join " " [maintainers-label @@ -49,7 +36,6 @@ (str/join " " ["GitRepo:" git-repo]) (str/join " " ["GitCommit:" git-commit])] - (map variant->manifest variants) + (map variant->manifest merged-arch-variants) [nil])))) - diff --git a/src/docker_clojure/util.clj b/src/docker_clojure/util.clj index cbe128be..ec28ec85 100644 --- a/src/docker_clojure/util.clj +++ b/src/docker_clojure/util.clj @@ -7,50 +7,3 @@ "Returns the value in map m for key k or else the value for key :default." [m k] (get m k (get m :default))) - -(defn jdk-label - [omit-default? jdk-version base-image] - (if (and omit-default? (= cfg/default-jdk-version jdk-version) - (= (first (get-or-default cfg/base-images jdk-version)) - base-image)) - nil - (str - (case base-image - ("eclipse-temurin" "debian") "temurin" - base-image) - "-" jdk-version))) - -(defn docker-tag - "Returns the Docker tag for the given variant with truthy keys from first arg - left out when possible." - [{:keys [omit-all? omit-jdk? omit-build-tool? omit-build-tool-version? - omit-distro?]} - {:keys [base-image jdk-version distro build-tool - build-tool-version] :as _variant}] - (if (= ::core/all build-tool) - "latest" - (let [jdk (jdk-label (or omit-all? omit-jdk?) - jdk-version base-image) - dd (get-or-default cfg/default-distros jdk-version) - distro-label (if (and (or omit-all? omit-distro?) (= dd distro)) - nil - (when distro (name distro))) - tag-elements (remove nil? [jdk distro-label]) - build-tool-label (if (and (seq tag-elements) ; ensure tag is non-empty - (or omit-all? omit-build-tool?) - (= build-tool cfg/default-build-tool)) - nil - build-tool) - build-tool-version-label (if (or omit-all? omit-build-tool? - omit-build-tool-version?) - nil - build-tool-version)] - (str/join "-" (remove nil? [jdk build-tool-label - build-tool-version-label - distro-label]))))) - -(def full-docker-tag - (partial docker-tag {})) - -(def default-docker-tag - (partial docker-tag {:omit-jdk? true, :omit-distro? true})) diff --git a/src/docker_clojure/variant.clj b/src/docker_clojure/variant.clj new file mode 100644 index 00000000..82ff1c3a --- /dev/null +++ b/src/docker_clojure/variant.clj @@ -0,0 +1,113 @@ +(ns docker-clojure.variant + (:refer-clojure :exclude [compare sort]) + (:require [clojure.math.combinatorics :as combo] + [clojure.string :as str] + [docker-clojure.config :as cfg] + [docker-clojure.docker :as docker] + [docker-clojure.util :refer [get-or-default]])) + +(defn assoc-if + [m pred k v] + (if (pred) + (assoc m k v) + m)) + +(defn ->map [[base-image jdk-version distro + [build-tool build-tool-version] architecture]] + (let [base {:jdk-version jdk-version + :architecture architecture + :base-image base-image + :base-image-tag (docker/base-image-tag base-image jdk-version + distro) + :distro distro + :build-tool build-tool + :build-tool-version build-tool-version + :maintainer (str/join " & " cfg/maintainers)}] + (-> base + (assoc :docker-tag (docker/default-tag base)) + (assoc-if #(nil? (:build-tool-version base)) :build-tool-versions + cfg/build-tools)))) + +(defn exclude? + "Returns true if the map `variant` contains every key-value pair in the map + `exclusion`. `variant` may contain additional keys that are not in + `exclusion`. Some values of `exclusion` can also be a predicate of one + argument which is then tested against the respective value from `variant`. + Returns false if any of the keys in `exclusions` are missing from `variant` or + have different values, or the predicate value returned false." + [variant exclusion] + (every? (fn [[k v]] + (if (fn? v) + (v (get variant k)) + (= v (get variant k)))) + exclusion)) + +(defn compare + [v1 v2] + (let [c (clojure.core/compare (:jdk-version v1) (:jdk-version v2))] + (if (not= c 0) + c + (let [c (clojure.core/compare (docker/full-tag v1) + (docker/full-tag v2))] + (if (not= c 0) + c + (clojure.core/compare (:architecture v1) (:architecture v2))))))) + +(defn sort + [variants] + (clojure.core/sort + (fn [v1 v2] + (cond + (= "latest" (:docker-tag v1)) -1 + (= "latest" (:docker-tag v2)) 1 + :else (compare v1 v2))) + variants)) + +(defn equal? + [v1 v2] + (= 0 (compare v1 v2))) + +(defn equal-except-architecture? + [v1 v2] + (= 0 (compare (dissoc v1 :architecture) (dissoc v2 :architecture)))) + +(defn combinations + [base-images jdk-versions distros build-tools architectures] + (reduce + (fn [variants jdk-version] + (concat + variants + (let [jdk-base-images (get-or-default base-images jdk-version)] + (loop [[bi & r] jdk-base-images + acc #{}] + (let [vs (combo/cartesian-product #{bi} #{jdk-version} + (get-or-default distros bi) + build-tools + architectures) + acc' (concat acc vs)] + (if (seq r) + (recur r acc') + acc')))))) + #{} jdk-versions)) + +(defn merge-architectures + [variants default-architectures] + (->> variants + (map #(assoc % :architectures #{(:architecture %)})) + (reduce + (fn [mav v] + (if-let [matching + (some #(when + (equal-except-architecture? v %) + %) + mav)] + (-> mav + (->> (remove #(= % matching))) + (conj (update matching :architectures conj + (:architecture v)))) + (conj mav v))) + []) + (map #(if (= (:architectures %) default-architectures) + (dissoc % :architectures :architecture) + (dissoc % :architecture))) + sort)) diff --git a/test/docker_clojure/core_test.clj b/test/docker_clojure/core_test.clj index d98e2404..7792e3a4 100644 --- a/test/docker_clojure/core_test.clj +++ b/test/docker_clojure/core_test.clj @@ -1,9 +1,7 @@ (ns docker-clojure.core-test (:require [clojure.test :refer [deftest is are testing]] - [docker-clojure.core :refer [exclude? image-variants variant-map]] - [docker-clojure.config :as cfg] - [docker-clojure.util :refer [default-docker-tag]] - [clojure.string :as str])) + [docker-clojure.core :refer [exclude? image-variants]] + [docker-clojure.config :as cfg])) (deftest image-variants-test (testing "generates the expected set of variants" @@ -12,16 +10,18 @@ :default :ubuntu/noble} cfg/default-jdk-version 11 cfg/maintainers ["Paul Lam " - "Wes Morgan "]] + "Wes Morgan "] + cfg/architectures #{"amd64" "arm64v8"}] (let [variants (image-variants {8 ["debian"] 11 ["debian"] :default ["eclipse-temurin"]} #{8 11 17 18} {"debian" #{:debian/buster :debian-slim/buster-slim} - :default #{:alpine/alpine :ubuntu/noble}} + :default #{:alpine/alpine :ubuntu/noble}} {"lein" "2.9.1" - "tools-deps" "1.10.1.478"})] + "tools-deps" "1.10.1.478"} + #{"amd64" "arm64v8"})] ;; filter is to make failure output a little more humane (are [v] (contains? (->> variants (filter #(and (= (:base-image %) (:base-image v)) @@ -30,73 +30,130 @@ (= (:build-tool %) (:build-tool v)))) set) v) - {:jdk-version 11, :distro :debian-slim/buster-slim, :build-tool "lein" - :base-image "debian" :base-image-tag "debian:buster-slim" - :maintainer "Paul Lam & Wes Morgan " - :docker-tag "temurin-11-lein-2.9.1", :build-tool-version "2.9.1"} + {:jdk-version 11, :distro :debian-slim/buster-slim, :build-tool "lein" + :base-image "debian" :base-image-tag "debian:buster-slim" + :maintainer "Paul Lam & Wes Morgan " + :docker-tag "temurin-11-lein-2.9.1", :build-tool-version "2.9.1" + :architecture "amd64"} + {:jdk-version 11, :distro :debian-slim/buster-slim, :build-tool "lein" + :base-image "debian" :base-image-tag "debian:buster-slim" + :maintainer "Paul Lam & Wes Morgan " + :docker-tag "temurin-11-lein-2.9.1", :build-tool-version "2.9.1" + :architecture "arm64v8"} {:jdk-version 18, :distro :ubuntu/noble :base-image "eclipse-temurin" :base-image-tag "eclipse-temurin:18-jdk-noble" :build-tool "tools-deps" :maintainer "Paul Lam & Wes Morgan " :docker-tag "temurin-18-tools-deps-1.10.1.478" - :build-tool-version "1.10.1.478"} - {:jdk-version 11, :distro :debian/buster, :build-tool "lein" - :base-image "debian" :base-image-tag "debian:buster" - :maintainer "Paul Lam & Wes Morgan " - :docker-tag "temurin-11-lein-2.9.1-buster", :build-tool-version "2.9.1"} + :build-tool-version "1.10.1.478" + :architecture "amd64"} + {:jdk-version 18, :distro :ubuntu/noble + :base-image "eclipse-temurin" + :base-image-tag "eclipse-temurin:18-jdk-noble" + :build-tool "tools-deps" + :maintainer "Paul Lam & Wes Morgan " + :docker-tag "temurin-18-tools-deps-1.10.1.478" + :build-tool-version "1.10.1.478" + :architecture "arm64v8"} + {:jdk-version 11, :distro :debian/buster, :build-tool "lein" + :base-image "debian" :base-image-tag "debian:buster" + :maintainer "Paul Lam & Wes Morgan " + :docker-tag "temurin-11-lein-2.9.1-buster", :build-tool-version "2.9.1" + :architecture "amd64"} + {:jdk-version 11, :distro :debian/buster, :build-tool "lein" + :base-image "debian" :base-image-tag "debian:buster" + :maintainer "Paul Lam & Wes Morgan " + :docker-tag "temurin-11-lein-2.9.1-buster", :build-tool-version "2.9.1" + :architecture "arm64v8"} {:jdk-version 11, :distro :debian/buster :base-image "debian" :base-image-tag "debian:buster" :build-tool "tools-deps" :maintainer "Paul Lam & Wes Morgan " :docker-tag "temurin-11-tools-deps-1.10.1.478-buster" - :build-tool-version "1.10.1.478"} + :build-tool-version "1.10.1.478" + :architecture "amd64"} + {:jdk-version 11, :distro :debian/buster + :base-image "debian" + :base-image-tag "debian:buster" + :build-tool "tools-deps" + :maintainer "Paul Lam & Wes Morgan " + :docker-tag "temurin-11-tools-deps-1.10.1.478-buster" + :build-tool-version "1.10.1.478" + :architecture "arm64v8"} + {:jdk-version 8, :distro :debian-slim/buster-slim, :build-tool "lein" + :base-image "debian" + :base-image-tag "debian:buster-slim" + :maintainer "Paul Lam & Wes Morgan " + :docker-tag "temurin-8-lein-2.9.1", :build-tool-version "2.9.1" + :architecture "amd64"} {:jdk-version 8, :distro :debian-slim/buster-slim, :build-tool "lein" :base-image "debian" :base-image-tag "debian:buster-slim" :maintainer "Paul Lam & Wes Morgan " - :docker-tag "temurin-8-lein-2.9.1", :build-tool-version "2.9.1"} + :docker-tag "temurin-8-lein-2.9.1", :build-tool-version "2.9.1" + :architecture "arm64v8"} {:jdk-version 8, :distro :debian-slim/buster-slim :build-tool "tools-deps" :base-image "debian" :base-image-tag "debian:buster-slim" :maintainer "Paul Lam & Wes Morgan " :docker-tag "temurin-8-tools-deps-1.10.1.478" - :build-tool-version "1.10.1.478"} + :build-tool-version "1.10.1.478" + :architecture "amd64"} + {:jdk-version 8, :distro :debian-slim/buster-slim + :build-tool "tools-deps" + :base-image "debian" + :base-image-tag "debian:buster-slim" + :maintainer "Paul Lam & Wes Morgan " + :docker-tag "temurin-8-tools-deps-1.10.1.478" + :build-tool-version "1.10.1.478" + :architecture "arm64v8"} + {:jdk-version 17, :distro :ubuntu/noble, :build-tool "lein" + :base-image "eclipse-temurin" + :base-image-tag "eclipse-temurin:17-jdk-noble" + :maintainer "Paul Lam & Wes Morgan " + :docker-tag "temurin-17-lein-2.9.1" + :build-tool-version "2.9.1" + :architecture "amd64"} {:jdk-version 17, :distro :ubuntu/noble, :build-tool "lein" :base-image "eclipse-temurin" :base-image-tag "eclipse-temurin:17-jdk-noble" :maintainer "Paul Lam & Wes Morgan " :docker-tag "temurin-17-lein-2.9.1" - :build-tool-version "2.9.1"} + :build-tool-version "2.9.1" + :architecture "arm64v8"} + {:jdk-version 17, :distro :alpine/alpine, :build-tool "lein" + :base-image "eclipse-temurin" + :base-image-tag "eclipse-temurin:17-jdk-alpine" + :maintainer "Paul Lam & Wes Morgan " + :docker-tag "temurin-17-lein-2.9.1-alpine" + :build-tool-version "2.9.1" + :architecture "amd64"} {:jdk-version 17, :distro :alpine/alpine, :build-tool "lein" - :base-image "eclipse-temurin", :architectures #{"amd64"} + :base-image "eclipse-temurin" :base-image-tag "eclipse-temurin:17-jdk-alpine" :maintainer "Paul Lam & Wes Morgan " :docker-tag "temurin-17-lein-2.9.1-alpine" - :build-tool-version "2.9.1"} + :build-tool-version "2.9.1" + :architecture "arm64v8"} {:jdk-version 17, :distro :ubuntu/noble :base-image "eclipse-temurin" :base-image-tag "eclipse-temurin:17-jdk-noble" :build-tool "tools-deps" :maintainer "Paul Lam & Wes Morgan " :docker-tag "temurin-17-tools-deps-1.10.1.478" - :build-tool-version "1.10.1.478"}))))) - -(deftest variant-map-test - (testing "returns the expected map version of the image variant list" - (with-redefs [cfg/maintainers ["Paul Lam " - "Wes Morgan "]] - (is (= {:jdk-version 8 - :base-image "eclipse-temurin" - :base-image-tag "eclipse-temurin:8-jdk-distro" - :distro :distro/distro - :build-tool "build-tool" - :docker-tag "temurin-8-build-tool-1.2.3-distro" - :build-tool-version "1.2.3" - :maintainer "Paul Lam & Wes Morgan "} - (variant-map '("eclipse-temurin" 8 :distro/distro ["build-tool" "1.2.3"]))))))) + :build-tool-version "1.10.1.478" + :architecture "amd64"} + {:jdk-version 17, :distro :ubuntu/noble + :base-image "eclipse-temurin" + :base-image-tag "eclipse-temurin:17-jdk-noble" + :build-tool "tools-deps" + :maintainer "Paul Lam & Wes Morgan " + :docker-tag "temurin-17-tools-deps-1.10.1.478" + :build-tool-version "1.10.1.478" + :architecture "arm64v8"}))))) (deftest exclude?-test (testing "excludes variant that matches all key-values in any exclusion" @@ -107,31 +164,3 @@ (testing "does not exclude partial matches" (is (not (exclude? #{{:base-image "bad", :build-tool "woof"}} {:base-image "bad", :build-tool "lein"}))))) - -(deftest docker-tag-test - (with-redefs [cfg/default-jdk-version 11 ; TODO: Make this an arg to the fn instead - cfg/default-distros {:default :debian-slim/slim-buster}] ; TODO: Rethink this too? - (testing "default java version is left out" - (is (not (str/includes? (default-docker-tag {:jdk-version 11}) - "openjdk-11")))) - (testing "non-default version is added as a prefix" - (is (str/starts-with? (default-docker-tag {:base-image "openjdk" - :jdk-version 14}) - "openjdk-14"))) - (testing "default distro is left out" - (is (not (str/includes? (default-docker-tag {:jdk-version 14 - :distro :debian-slim/slim-buster}) - "slim-buster")))) - (testing "alpine is added as a suffix" - (is (str/ends-with? (default-docker-tag {:jdk-version 8 - :distro :alpine/alpine}) - "alpine"))) - (testing "build tool is included" - (is (str/includes? (default-docker-tag {:jdk-version 11 - :build-tool "lein"}) - "lein"))) - (testing "build tool version is included" - (is (str/includes? (default-docker-tag {:jdk-version 11 - :build-tool "lein" - :build-tool-version "2.11.2"}) - "2.11.2"))))) diff --git a/test/docker_clojure/docker_test.clj b/test/docker_clojure/docker_test.clj new file mode 100644 index 00000000..583ae08b --- /dev/null +++ b/test/docker_clojure/docker_test.clj @@ -0,0 +1,69 @@ +(ns docker-clojure.docker-test + (:require [clojure.string :as str] + [clojure.test :refer :all] + [docker-clojure.config :as cfg] + [docker-clojure.docker :refer :all])) + +(deftest tag-test + (with-redefs [cfg/default-jdk-version 11 ; TODO: Make this an arg to the fn instead + cfg/default-distros {:default :debian-slim/slim-buster}] ; TODO: Rethink this too? + (testing "default java version is left out" + (is (not (str/includes? (default-tag {:jdk-version 11}) + "openjdk-11")))) + (testing "non-default version is added as a prefix" + (is (str/starts-with? (default-tag {:base-image "openjdk" + :jdk-version 14}) + "openjdk-14"))) + (testing "default distro is left out" + (is (not (str/includes? (default-tag {:jdk-version 14 + :distro :debian-slim/slim-buster}) + "slim-buster")))) + (testing "alpine is added as a suffix" + (is (str/ends-with? (default-tag {:jdk-version 8 + :distro :alpine/alpine}) + "alpine"))) + (testing "build tool is included" + (is (str/includes? (default-tag {:jdk-version 11 + :build-tool "lein"}) + "lein"))) + (testing "build tool version is included" + (is (str/includes? (default-tag {:jdk-version 11 + :build-tool "lein" + :build-tool-version "2.11.2"}) + "2.11.2"))))) + +(deftest all-tags-test + (testing "Generates all-defaults tag for a build tool" + (let [tags (all-tags {:base-image "debian" + :jdk-version 21 + :distro :debian/bookworm + :build-tool "tools-deps" + :build-tool-version "1.11.1.1155"})] + (is ((set tags) "tools-deps")))) + (testing "Generates jdk-version-build-tool tag for every jdk version" + (are [jdk-version tag] + (let [tags (all-tags {:base-image (if (< jdk-version 21) + "eclipse-temurin" + "debian") + :jdk-version jdk-version + :distro (if (< jdk-version 21) + :ubuntu/jammy + :debian/bookworm) + :build-tool "tools-deps" + :build-tool-version "1.11.1.1155"})] + ((set tags) tag)) + 11 "temurin-11-tools-deps" + 17 "temurin-17-tools-deps" + 21 "temurin-21-tools-deps")) + (testing "Generates build-tool-distro tag for every distro" + (are [distro tag] + (let [tags (all-tags {:base-image "debian" + :jdk-version 21 + :distro distro + :build-tool "tools-deps" + :build-tool-version "1.11.1.1155"})] + ((set tags) tag)) + :debian/bullseye "tools-deps-bullseye" + :debian-slim/bullseye-slim "tools-deps-bullseye-slim" + :debian/bookworm "tools-deps-bookworm" + :debian-slim/bookworm-slim "tools-deps-bookworm-slim"))) diff --git a/test/docker_clojure/manifest_test.clj b/test/docker_clojure/manifest_test.clj index 30303036..493b9eaa 100644 --- a/test/docker_clojure/manifest_test.clj +++ b/test/docker_clojure/manifest_test.clj @@ -1,39 +1,15 @@ (ns docker-clojure.manifest-test (:require [clojure.test :refer [deftest is are testing]] - [docker-clojure.manifest :refer [variant-tags]])) + [docker-clojure.manifest :refer [variant->manifest]])) -(deftest variant-tags-test - (testing "Generates all-defaults tag for a build tool" - (let [tags (variant-tags {:base-image "debian" - :jdk-version 21 - :distro :debian/bookworm - :build-tool "tools-deps" - :build-tool-version "1.11.1.1155"})] - (is ((set tags) "tools-deps")))) - (testing "Generates jdk-version-build-tool tag for every jdk version" - (are [jdk-version tag] - (let [tags (variant-tags {:base-image (if (< jdk-version 21) - "eclipse-temurin" - "debian") - :jdk-version jdk-version - :distro (if (< jdk-version 21) - :ubuntu/jammy - :debian/bookworm) - :build-tool "tools-deps" - :build-tool-version "1.11.1.1155"})] - ((set tags) tag)) - 11 "temurin-11-tools-deps" - 17 "temurin-17-tools-deps" - 21 "temurin-21-tools-deps")) - (testing "Generates build-tool-distro tag for every distro" - (are [distro tag] - (let [tags (variant-tags {:base-image "debian" - :jdk-version 21 - :distro distro - :build-tool "tools-deps" - :build-tool-version "1.11.1.1155"})] - ((set tags) tag)) - :debian/bullseye "tools-deps-bullseye" - :debian-slim/bullseye-slim "tools-deps-bullseye-slim" - :debian/bookworm "tools-deps-bookworm" - :debian-slim/bookworm-slim "tools-deps-bookworm-slim"))) +(deftest variant->manifest-test + (testing "generates the correct manifest text for a variant" + (is (= "\nTags: temurin-17-noble, temurin-17-tools-deps-1.10.1.478, temurin-17-tools-deps-1.10.1.478-noble, temurin-17-tools-deps-noble\nDirectory: target/eclipse-temurin-17-jdk-noble/tools-deps" + (variant->manifest + {:jdk-version 17, :distro :ubuntu/noble + :base-image "eclipse-temurin" + :base-image-tag "eclipse-temurin:17-jdk-noble" + :build-tool "tools-deps" + :maintainer "Paul Lam

& Wes Morgan " + :docker-tag "temurin-17-tools-deps-1.10.1.478" + :build-tool-version "1.10.1.478"}))))) diff --git a/test/docker_clojure/variant_test.clj b/test/docker_clojure/variant_test.clj new file mode 100644 index 00000000..aee0ff9c --- /dev/null +++ b/test/docker_clojure/variant_test.clj @@ -0,0 +1,20 @@ +(ns docker-clojure.variant-test + (:require [clojure.test :refer :all] + [docker-clojure.variant :refer :all] + [docker-clojure.config :as cfg])) + +(deftest ->map-test + (testing "returns the expected map version of the image variant list" + (with-redefs [cfg/maintainers ["Paul Lam " + "Wes Morgan "]] + (is (= {:jdk-version 8 + :base-image "eclipse-temurin" + :base-image-tag "eclipse-temurin:8-jdk-distro" + :distro :distro/distro + :build-tool "build-tool" + :docker-tag "temurin-8-build-tool-1.2.3-distro" + :build-tool-version "1.2.3" + :maintainer "Paul Lam & Wes Morgan " + :architecture "i386"} + (->map '("eclipse-temurin" 8 :distro/distro + ["build-tool" "1.2.3"] "i386")))))))