Skip to content

Commit

Permalink
Merge pull request #237 from blue0513/feature/leiningen-resolve-priva…
Browse files Browse the repository at this point in the history
…te-repo

feature: access a private Maven repo with gpg in a Leiningen project
  • Loading branch information
liquidz authored Oct 2, 2023
2 parents d4e76ca + 25bb320 commit 7188302
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 28 deletions.
14 changes: 12 additions & 2 deletions src/antq/dep/leiningen.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
[antq.constant.project-file :as const.project-file]
[antq.record :as r]
[antq.util.dep :as u.dep]
[antq.util.leiningen :as u.lein]
[clojure.java.io :as io]
[clojure.walk :as walk]))

Expand Down Expand Up @@ -33,6 +34,13 @@
(get const/deps-exclude-key)
(u.dep/ensure-version-list)))

(defn- user-deps-repository
[]
(let [file (io/file (u.lein/lein-home) "profiles.clj")]
(when (.exists file)
(-> file slurp read-string
(get-in [:user :repositories])))))

(defn extract-deps
{:malli/schema [:=>
[:cat 'string? 'string?]
Expand All @@ -41,7 +49,8 @@
(let [dep-form? (atom false)
repos-form? (atom false)
deps (atom [])
repos (atom [])]
repos (atom [])
cross-project-repositories (user-deps-repository)]
(walk/prewalk (fn [form]
(cond
(keyword? form)
Expand Down Expand Up @@ -70,7 +79,8 @@
:file file-path
:name (normalize-name dep-name)
:version version
:repositories repositories
:repositories (merge repositories
(into {} cross-project-repositories))
:exclude-versions (seq (exclude-version-range dep))})))))

(defn load-deps
Expand Down
43 changes: 43 additions & 0 deletions src/antq/util/leiningen.clj
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
(ns antq.util.leiningen
(:require
[antq.log :as log]
[antq.util.env :as u.env]
[clojure.java.io :as io]
[clojure.java.shell :as shell]
[clojure.string :as str]))

(defn lein-home
[]
(io/file (System/getProperty "user.home") ".lein"))

(defn- env-name
"cf. https://github.com/technomancy/leiningen/blob/master/doc/DEPLOY.md#credentials-in-the-environment"
[kw]
Expand All @@ -17,6 +24,42 @@
:else
nil))

(defn- gpg-program
[]
(or (System/getenv "LEIN_GPG") "gpg"))

(defn- gpg
[& args]
(try
(apply shell/sh (gpg-program) args)
(catch java.io.IOException e
{:exit 1 :err (.getMessage e)})))

(defn- credentials-fn
"This method references to the code of Leiningen, an open-source project licensed under EPL 1.0.
cf. https://codeberg.org/leiningen/leiningen/src/tag/2.10.0/leiningen-core/src/leiningen/core/user.clj#L138"
([] (let [cred-file (io/file (lein-home) "credentials.clj.gpg")]
(if (.exists cred-file)
(credentials-fn cred-file)
(log/error (format "Could not find %s" (str cred-file))))))
([file]
(let [{:keys [out err exit]} (gpg "--quiet" "--batch"
"--decrypt" "--" (str file))]
(if (pos? exit)
(do
(log/error (format "Could not decrypt credentials from %s" (str file)))
(log/error err)
(log/error "See `lein help gpg` for how to install gpg."))
(read-string out)))))

(defn get-credential
[url]
(when-let [res (some->> (credentials-fn)
(filter (fn [[pattern _]] (re-seq pattern url)))
first
val)]
(select-keys res [:username :password])))

(defn env
[kw]
(some-> (env-name kw)
Expand Down
30 changes: 23 additions & 7 deletions src/antq/util/maven.clj
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,36 @@
(.setUsername (ensure-username-or-password username))
(.setPassword (ensure-username-or-password password))))

(defn- get-auth-info
[repository]
(let [[id {:keys [url username password creds]}] repository]
(cond
(and username password)
{:id id
:username username
:password password}

(= :gpg creds)
(let [credential-info (u.lein/get-credential url)]
{:id id
:username (:username credential-info)
:password (:password credential-info)}))))

(defn get-maven-settings
^Settings
[opts]
(let [settings ^Settings (deps.util.maven/get-settings)
server-ids (set (map #(.getId %) (.getServers settings)))]
;; NOTE
;; In Leiningen, authentication information is defined in project.clj instead of ~/.m2/settings.xml,
;; In Leiningen, authentication information is defined in project.clj or profiles.clj instead of ~/.m2/settings.xml,
;; so if there is authentication information in `:repositories`, apply to `settings`
(doseq [[id {:keys [username password]}] (:repositories opts)]
(when (and username
password
(not (contains? server-ids id)))
(.addServer settings
(new-repository-server {:id id :username username :password password}))))
(doseq [repo (:repositories opts)]
(let [{:keys [id username password]} (get-auth-info repo)]
(when (and username
password
(not (contains? server-ids id)))
(.addServer settings
(new-repository-server {:id id :username username :password password})))))
settings))

(def ^TransferListener custom-transfer-listener
Expand Down
32 changes: 17 additions & 15 deletions test/antq/dep/leiningen_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
[antq.constant.project-file :as const.project-file]
[antq.dep.leiningen :as sut]
[antq.record :as r]
[antq.util.leiningen :as u.lein]
[clojure.java.io :as io]
[clojure.test :as t]))

Expand All @@ -19,21 +20,22 @@
m)))

(t/deftest extract-deps-test
(let [deps (sut/extract-deps
file-path
(slurp (io/resource "dep/test_project.clj")))]
(t/is (sequential? deps))
(t/is (every? #(instance? antq.record.Dependency %) deps))
(t/is (= (->> [(dependency {:name "foo/core" :version "1.0.0"})
(dependency {:name "foo/core" :version "1.1.0"})
(dependency {:name "bar/bar" :version "2.0.0"})
(dependency {:name "baz/baz" :version "3.0.0"})
(dependency {:name "plug/plug" :version "4.0.0"})
(dependency {:name "managed/dependency" :version "5.0.0"})
(dependency {:name "meta/range-ignore1" :version "6.0.0" :exclude-versions ["7.x"]})
(dependency {:name "meta/range-ignore2" :version "7.0.0" :exclude-versions ["8.x" "9.x"]})]
(sort-by :name))
(sort-by :name deps)))))
(with-redefs [u.lein/lein-home (constantly "path/to/dummy/")]
(let [deps (sut/extract-deps
file-path
(slurp (io/resource "dep/test_project.clj")))]
(t/is (sequential? deps))
(t/is (every? #(instance? antq.record.Dependency %) deps))
(t/is (= (->> [(dependency {:name "foo/core" :version "1.0.0"})
(dependency {:name "foo/core" :version "1.1.0"})
(dependency {:name "bar/bar" :version "2.0.0"})
(dependency {:name "baz/baz" :version "3.0.0"})
(dependency {:name "plug/plug" :version "4.0.0"})
(dependency {:name "managed/dependency" :version "5.0.0"})
(dependency {:name "meta/range-ignore1" :version "6.0.0" :exclude-versions ["7.x"]})
(dependency {:name "meta/range-ignore2" :version "7.0.0" :exclude-versions ["8.x" "9.x"]})]
(sort-by :name))
(sort-by :name deps))))))

(t/deftest load-deps-test
(with-redefs [const.project-file/leiningen "test_project.clj"]
Expand Down
26 changes: 26 additions & 0 deletions test/antq/util/leiningen_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,36 @@
[antq.util.leiningen :as sut]
[clojure.test :as t]))

(def ^:private dummy-credentials
{#"https://one.example.com/repository/.*"
{:username "one-username"
:password "one-password"}
#"https://two.example.com/repository/.*"
{:username "two-username"
:password "two-password"}
#"three.example.com/repository/"
{:username "three-username"
:password "three-password"}})

(t/deftest env-test
(with-redefs [u.env/getenv identity]
(t/is (= "LEIN_PASSWORD" (sut/env :env)))
(t/is (= "FOO" (sut/env :env/foo)))
(t/is (= "FOO_BAR" (sut/env :env/foo_bar)))
(t/is (= nil (sut/env :invalid/foo_bar)))
(t/is (= nil (sut/env "string")))))

(t/deftest get-credential-test
(with-redefs [sut/credentials-fn (constantly dummy-credentials)]
(let [url1 "https://one.example.com/repository/releases"
url2 "https://two.example.com/repository/releases"
url3 "https://three.example.com/repository/releases"
url4 "https://four.example.com/repository/releases"]
(t/is (= "one-username" (:username (sut/get-credential url1))))
(t/is (= "one-password" (:password (sut/get-credential url1))))
(t/is (= "two-username" (:username (sut/get-credential url2))))
(t/is (= "two-password" (:password (sut/get-credential url2))))
(t/is (= "three-username" (:username (sut/get-credential url3))))
(t/is (= "three-password" (:password (sut/get-credential url3))))
(t/is (= nil (:username (sut/get-credential url4))))
(t/is (= nil (:password (sut/get-credential url4)))))))
16 changes: 12 additions & 4 deletions test/antq/util/maven_test.clj
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
(ns antq.util.maven-test
(:require
[antq.util.env :as u.env]
[antq.util.leiningen :as u.lein]
[antq.util.maven :as sut]
[clojure.data.xml :as xml]
[clojure.java.io :as io]
Expand Down Expand Up @@ -31,9 +32,12 @@
:username "three-user"
:password "three-pass"}
;; new to appear
"serv4" {:url "https://three.example.com"
"serv4" {:url "https://four.example.com"
:username :env
:password :env/four}
;; new to appear
"serv5" {:url "https://five.example.com"
:creds :gpg}
;; should not be added because of missing username and password
"dummy" {:url "https://dummy.example.com"}})

Expand Down Expand Up @@ -75,22 +79,26 @@

(t/deftest get-maven-settings-test
(with-redefs [deps.util.maven/get-settings (constantly dummy-settings)
u.env/getenv #(get dummy-env %)]
u.env/getenv #(get dummy-env %)
u.lein/get-credential (constantly {:username "gpg-user"
:password "gpg-pass"})]
(let [settings (sut/get-maven-settings {:repositories dummy-repos})
servers (map #(hash-map
:id (.getId %)
:username (.getUsername %)
:password (.getPassword %))
(.getServers settings))]
(t/is (= 4 (count servers)))
(t/is (= 5 (count servers)))

(t/is (= #{{:id "serv1" :username nil :password nil}
;; from settings.xml
{:id "serv2" :username "two-user" :password "two-pass"}
;; from project.clj
{:id "serv3" :username "three-user" :password "three-pass"}
;; from project.clj with environmental variable
{:id "serv4" :username "lein-pass" :password "env-four"}}
{:id "serv4" :username "lein-pass" :password "env-four"}
;; from profiles.clj with gpg
{:id "serv5" :username "gpg-user" :password "gpg-pass"}}
(set servers))))))

(t/deftest read-pom-s3-repos-test
Expand Down

0 comments on commit 7188302

Please sign in to comment.