From 79f42b50f99fa247fddfe8fd89cdc494b1b96dce Mon Sep 17 00:00:00 2001 From: Miloslav Nenadal Date: Thu, 31 Oct 2024 10:59:56 +0100 Subject: [PATCH 1/2] Add circleci support --- .circleci/config.yml | 5 ++++ README.adoc | 4 ++++ src/antq/core.clj | 4 ++++ src/antq/dep/circle_ci.clj | 33 ++++++++++++++++++++++++++ src/antq/record.clj | 4 ++-- src/antq/upgrade/circle_ci.clj | 25 ++++++++++++++++++++ src/antq/ver/circle_ci_orb.clj | 26 ++++++++++++++++++++ test/antq/dep/circle_ci_test.clj | 28 ++++++++++++++++++++++ test/antq/upgrade/circle_ci_test.clj | 34 +++++++++++++++++++++++++++ test/resources/dep/test_circle_ci.yml | 5 ++++ 10 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 .circleci/config.yml create mode 100644 src/antq/dep/circle_ci.clj create mode 100644 src/antq/upgrade/circle_ci.clj create mode 100644 src/antq/ver/circle_ci_orb.clj create mode 100644 test/antq/dep/circle_ci_test.clj create mode 100644 test/antq/upgrade/circle_ci_test.clj create mode 100644 test/resources/dep/test_circle_ci.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000..e868b2b5 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,5 @@ +version: 2.1 + +orbs: + node: circleci/node@6.3.0 + docker: circleci/docker@2.8.0 diff --git a/README.adoc b/README.adoc index 65f7b969..9874a7c4 100644 --- a/README.adoc +++ b/README.adoc @@ -42,6 +42,10 @@ If you have a trouble, please see link:./doc/non-supported-clojure-version.adoc[ | https://maven.apache.org[Maven] | +| .circleci/config.yml +| https://circleci.com/[CircleCI] +| + | .github/workflows/*.yml | https://github.com/features/actions[GitHub Actions] | diff --git a/src/antq/core.clj b/src/antq/core.clj index 3c0a64b8..8ec42548 100644 --- a/src/antq/core.clj +++ b/src/antq/core.clj @@ -11,6 +11,7 @@ [antq.changelog :as changelog] [antq.dep.babashka :as dep.bb] [antq.dep.boot :as dep.boot] + [antq.dep.circle-ci :as dep.circle-ci] [antq.dep.clojure :as dep.clj] [antq.dep.clojure.tool :as dep.clj.tool] [antq.dep.github-action :as dep.gh-action] @@ -32,6 +33,7 @@ [antq.report.table] [antq.upgrade :as upgrade] [antq.upgrade.boot] + [antq.upgrade.circle-ci] [antq.upgrade.clojure] [antq.upgrade.clojure.tool] [antq.upgrade.github-action] @@ -43,6 +45,7 @@ [antq.util.maven :as u.maven] [antq.util.ver :as u.ver] [antq.ver :as ver] + [antq.ver.circle-ci-orb] [antq.ver.git-sha] [antq.ver.git-tag-and-sha] [antq.ver.github-tag] @@ -275,6 +278,7 @@ (let [skip (set (:skip options))] (mapcat #(concat (when-not (skip "boot") (dep.boot/load-deps %)) + (when-not (skip "circle-ci") (dep.circle-ci/load-deps %)) (when-not (skip "clojure-cli") (dep.clj/load-deps %)) (when-not (skip "github-action") (dep.gh-action/load-deps %)) (when-not (skip "pom") (dep.pom/load-deps %)) diff --git a/src/antq/dep/circle_ci.clj b/src/antq/dep/circle_ci.clj new file mode 100644 index 00000000..8b7f4436 --- /dev/null +++ b/src/antq/dep/circle_ci.clj @@ -0,0 +1,33 @@ +(ns antq.dep.circle-ci + (:require + [clojure.java.io :as io] + [clojure.string :as str] + [clj-yaml.core :as yaml] + [antq.util.dep :as u.dep] + [antq.record :as r])) + +(defn extract-deps [file-path content-str] + (let [parsed (yaml/parse-string content-str)] + (->> parsed + :orbs + vals + (into + [] + (map (fn [orb-s] + (let [[name version] (str/split orb-s #"@")] + (r/map->Dependency {:name name + :version version + :type :circle-ci-orb + :project :circle-ci + :file file-path})))))))) + +(defn load-deps + {:malli/schema [:function + [:=> :cat [:maybe r/?dependencies]] + [:=> [:cat 'string?] [:maybe r/?dependencies]]]} + ([] (load-deps ".")) + ([dir] + (let [config-file (io/file dir ".circleci/config.yml")] + (when (.exists config-file) + (extract-deps (u.dep/relative-path config-file) + (slurp config-file)))))) diff --git a/src/antq/record.clj b/src/antq/record.clj index ae0ed88a..4ac378ea 100644 --- a/src/antq/record.clj +++ b/src/antq/record.clj @@ -4,10 +4,10 @@ [:map [:url 'string?]]) (def ?type - [:enum :git-sha :git-tag-and-sha :github-tag :java]) + [:enum :git-sha :git-tag-and-sha :github-tag :java :circle-ci-orb]) (def ?project - [:enum :boot :clojure :clojure-tool :github-action :gradle :leiningen :pom :shadow-cljs]) + [:enum :boot :clojure :clojure-tool :github-action :gradle :leiningen :pom :shadow-cljs :circle-ci]) (def ?dependency [:map diff --git a/src/antq/upgrade/circle_ci.clj b/src/antq/upgrade/circle_ci.clj new file mode 100644 index 00000000..e8a9e850 --- /dev/null +++ b/src/antq/upgrade/circle_ci.clj @@ -0,0 +1,25 @@ +(ns antq.upgrade.circle-ci + (:require + [clojure.string :as str] + [antq.upgrade :as upgrade] + [rewrite-indented.zip :as ri.zip])) + +(defn- update-value + [new-value] + (fn [line] + (str/replace line #"([^@]+\s*@\s*['\"]?)[^\s'\"]+(['\"]?)" + (str "$1" new-value "$2")))) + +(defn upgrade-dep [loc version-checked-dep] + (loop [loc loc] + (if-let [loc (ri.zip/find-next-string loc #(re-seq (re-pattern (str "[^:]+\\s*:\\s*" (:name version-checked-dep) "@")) %))] + (recur (-> (ri.zip/update loc (update-value (:latest-version version-checked-dep))) + ri.zip/next)) + (ri.zip/move-to-root loc)))) + +(defmethod upgrade/upgrader :circle-ci + [version-checked-dep] + (some-> (:file version-checked-dep) + (ri.zip/of-file) + (upgrade-dep version-checked-dep) + (ri.zip/root-string))) diff --git a/src/antq/ver/circle_ci_orb.clj b/src/antq/ver/circle_ci_orb.clj new file mode 100644 index 00000000..63d61e05 --- /dev/null +++ b/src/antq/ver/circle_ci_orb.clj @@ -0,0 +1,26 @@ +(ns antq.ver.circle-ci-orb + (:require + [clojure.java.io :as io] + [clojure.string :as str] + [clojure.data.json :as json] + [antq.ver :as ver])) + +(defn orb-id [ns name] + (-> (io/as-url (str "https://internal.circleci.com/api/v2/orbs?ns=" ns "&name=" name)) + slurp + (json/read-str :key-fn keyword) + :items + first + :id)) + +(defn orb-versions [id] + (-> (io/as-url (str "https://internal.circleci.com/api/v2/orbs/" id)) + slurp + (json/read-str :key-fn keyword) + :versions)) + +(defmethod ver/get-sorted-versions :circle-ci-orb + [dep _options] + (let [[ns name] (str/split (:name dep) #"/") + id (orb-id ns name)] + (orb-versions id))) diff --git a/test/antq/dep/circle_ci_test.clj b/test/antq/dep/circle_ci_test.clj new file mode 100644 index 00000000..4524d872 --- /dev/null +++ b/test/antq/dep/circle_ci_test.clj @@ -0,0 +1,28 @@ +(ns antq.dep.circle-ci-test + (:require + [antq.dep.circle-ci :as sut] + [antq.record :as r] + [clojure.test :as t] + [clojure.java.io :as io])) + +(defn- git-tag-dependency + [m] + (r/map->Dependency (merge {:project :circle-ci + :type :circle-ci-orb + :file "dep/test_circle_ci.yml"} m))) + +(t/deftest extract-deps-test + (let [deps (sut/extract-deps "dep/test_circle_ci.yml" + (slurp (io/resource "dep/test_circle_ci.yml")))] + (t/is (sequential? deps)) + (t/is (every? #(instance? antq.record.Dependency %) deps)) + (t/is (= #{(git-tag-dependency {:name "circleci/node" :version "6.3.0"}) + (git-tag-dependency {:name "circleci/docker" :version "2.8.0"})} + (set deps))))) + +(t/deftest load-deps-test + (let [deps (sut/load-deps)] + (t/is (= #{".circleci/config.yml"} + (set (map :file deps))))) + + (t/is (nil? (sut/load-deps "non_existing_directory")))) diff --git a/test/antq/upgrade/circle_ci_test.clj b/test/antq/upgrade/circle_ci_test.clj new file mode 100644 index 00000000..5b3a686c --- /dev/null +++ b/test/antq/upgrade/circle_ci_test.clj @@ -0,0 +1,34 @@ +(ns antq.upgrade.circle-ci-test + (:require + [antq.upgrade :as upgrade] + [antq.upgrade.circle-ci] + [antq.record :as r] + [antq.dep.circle-ci :as dep.circle-ci] + [antq.test-helper :as h] + [clojure.java.io :as io] + [clojure.test :as t])) + +(def ^:private node-dep + (r/map->Dependency {:project :circle-ci + :type :circle-ci-orb + :name "circleci/node" + :version "6.3.0" + :latest-version "7.0.0" + :file (io/resource "dep/test_circle_ci.yml")})) + +(t/deftest upgrade-dep-test + (t/testing "supported" + (let [from-deps (->> (:file node-dep) + (slurp) + (dep.circle-ci/extract-deps "")) + temp-content (->> node-dep + (upgrade/upgrader)) + to-deps (h/with-temp-file + [temp-file temp-content] + (->> (assoc node-dep + :version "7.0.0" + :file temp-file) + (upgrade/upgrader) + (dep.circle-ci/extract-deps "")))] + (t/is (= #{{:name "circleci/node" :version {:- "6.3.0" :+ "7.0.0"}}} + (h/diff-deps from-deps to-deps)))))) diff --git a/test/resources/dep/test_circle_ci.yml b/test/resources/dep/test_circle_ci.yml new file mode 100644 index 00000000..e868b2b5 --- /dev/null +++ b/test/resources/dep/test_circle_ci.yml @@ -0,0 +1,5 @@ +version: 2.1 + +orbs: + node: circleci/node@6.3.0 + docker: circleci/docker@2.8.0 From 356562cfe5a1e4c57b9be65b9ef587c3060dbdd1 Mon Sep 17 00:00:00 2001 From: Miloslav Nenadal Date: Mon, 4 Nov 2024 10:54:13 +0100 Subject: [PATCH 2/2] Fix pr remarks --- .circleci/config.yml | 5 ---- src/antq/core.clj | 1 + src/antq/dep/circle_ci.clj | 10 +++----- src/antq/ver/circle_ci_orb.clj | 37 +++++++++++++++++----------- test/antq/dep/circle_ci_test.clj | 13 +++------- test/antq/ver/circle_ci_orb_test.clj | 24 ++++++++++++++++++ 6 files changed, 55 insertions(+), 35 deletions(-) delete mode 100644 .circleci/config.yml create mode 100644 test/antq/ver/circle_ci_orb_test.clj diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index e868b2b5..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,5 +0,0 @@ -version: 2.1 - -orbs: - node: circleci/node@6.3.0 - docker: circleci/docker@2.8.0 diff --git a/src/antq/core.clj b/src/antq/core.clj index 8ec42548..5eb08a0b 100644 --- a/src/antq/core.clj +++ b/src/antq/core.clj @@ -68,6 +68,7 @@ (def ^:private skippable #{"boot" + "circle-ci" "clojure-cli" "github-action" "gradle" diff --git a/src/antq/dep/circle_ci.clj b/src/antq/dep/circle_ci.clj index 8b7f4436..a4433135 100644 --- a/src/antq/dep/circle_ci.clj +++ b/src/antq/dep/circle_ci.clj @@ -11,15 +11,13 @@ (->> parsed :orbs vals - (into - [] - (map (fn [orb-s] - (let [[name version] (str/split orb-s #"@")] - (r/map->Dependency {:name name + (mapv (fn [orb-s] + (let [[orb-name version] (str/split orb-s #"@" 2)] + (r/map->Dependency {:name orb-name :version version :type :circle-ci-orb :project :circle-ci - :file file-path})))))))) + :file file-path}))))))) (defn load-deps {:malli/schema [:function diff --git a/src/antq/ver/circle_ci_orb.clj b/src/antq/ver/circle_ci_orb.clj index 63d61e05..fc96f77c 100644 --- a/src/antq/ver/circle_ci_orb.clj +++ b/src/antq/ver/circle_ci_orb.clj @@ -3,24 +3,33 @@ [clojure.java.io :as io] [clojure.string :as str] [clojure.data.json :as json] + [antq.log :as log] [antq.ver :as ver])) -(defn orb-id [ns name] - (-> (io/as-url (str "https://internal.circleci.com/api/v2/orbs?ns=" ns "&name=" name)) - slurp - (json/read-str :key-fn keyword) - :items - first - :id)) +(defn- orb-id [orb-ns orb-name] + (try + (-> (io/as-url (str "https://internal.circleci.com/api/v2/orbs?ns=" orb-ns "&name=" orb-name)) + slurp + (json/read-str :key-fn keyword) + :items + first + :id) + (catch Exception ex + (log/error (str "Failed to fetch orb id from circleci: " + (.getMessage ex)))))) -(defn orb-versions [id] - (-> (io/as-url (str "https://internal.circleci.com/api/v2/orbs/" id)) - slurp - (json/read-str :key-fn keyword) - :versions)) +(defn- orb-versions [id] + (try + (-> (io/as-url (str "https://internal.circleci.com/api/v2/orbs/" id)) + slurp + (json/read-str :key-fn keyword) + :versions) + (catch Exception ex + (log/error (str "Failed to fetch orb versions from circleci: " + (.getMessage ex)))))) (defmethod ver/get-sorted-versions :circle-ci-orb [dep _options] - (let [[ns name] (str/split (:name dep) #"/") - id (orb-id ns name)] + (let [[orb-ns orb-name] (str/split (:name dep) #"/" 2) + id (orb-id orb-ns orb-name)] (orb-versions id))) diff --git a/test/antq/dep/circle_ci_test.clj b/test/antq/dep/circle_ci_test.clj index 4524d872..fcde50aa 100644 --- a/test/antq/dep/circle_ci_test.clj +++ b/test/antq/dep/circle_ci_test.clj @@ -5,7 +5,7 @@ [clojure.test :as t] [clojure.java.io :as io])) -(defn- git-tag-dependency +(defn- circle-ci-orb-dependency [m] (r/map->Dependency (merge {:project :circle-ci :type :circle-ci-orb @@ -16,13 +16,6 @@ (slurp (io/resource "dep/test_circle_ci.yml")))] (t/is (sequential? deps)) (t/is (every? #(instance? antq.record.Dependency %) deps)) - (t/is (= #{(git-tag-dependency {:name "circleci/node" :version "6.3.0"}) - (git-tag-dependency {:name "circleci/docker" :version "2.8.0"})} + (t/is (= #{(circle-ci-orb-dependency {:name "circleci/node" :version "6.3.0"}) + (circle-ci-orb-dependency {:name "circleci/docker" :version "2.8.0"})} (set deps))))) - -(t/deftest load-deps-test - (let [deps (sut/load-deps)] - (t/is (= #{".circleci/config.yml"} - (set (map :file deps))))) - - (t/is (nil? (sut/load-deps "non_existing_directory")))) diff --git a/test/antq/ver/circle_ci_orb_test.clj b/test/antq/ver/circle_ci_orb_test.clj new file mode 100644 index 00000000..33bc7779 --- /dev/null +++ b/test/antq/ver/circle_ci_orb_test.clj @@ -0,0 +1,24 @@ +(ns antq.ver.circle-ci-orb-test + (:require + [clojure.test :as t] + [antq.record :as r] + [antq.ver :as ver] + [antq.ver.circle-ci-orb :as sut])) + +(defn- dep + [m] + (r/map->Dependency (merge {:type :circle-ci-orb} m))) + +(defn- orb-id [orb-ns orb-name] + (get-in {"circleci" {"node" "circleci-node-id"}} [orb-ns orb-name])) + +(defn- orb-versions [id] + (get {"circleci-node-id" ["3.0.0" "2.0.0" "1.0.0"]} id)) + +(t/deftest get-sorted-versions-test + (with-redefs [sut/orb-id orb-id + sut/orb-versions orb-versions] + (t/is (= ["3.0.0" "2.0.0" "1.0.0"] + (ver/get-sorted-versions (dep {:name "circleci/node" + :version "1.0.0"}) + {})))))