Repository Credentials and Deploying - boot-clj/boot GitHub Wiki
Boot comes with a built-in push task that allows you to deploy artifacts
to Maven repositories. Noteworthy are the repo
option, which is an alias
to the deployment target, and the gpg-sign
option, a boolean switch that
enables artifact signing.
Basic Operation
The simplest case is when you define your Maven repositories in the
:repositories
env key, in your build.boot
file, like this:
(set-env! :repositories [["clojars" {:url "https://clojars.org/repo/"
:username "foo"
:password "bar"}]])
With this configuration you can then do:
boot push --repo clojars
or you can configure the option in your build.boot
:
(task-options! push {:repo "clojars"})
Then you can just do
boot push
Adding additional repositories
When you are adding additional repositories like datomic, instead of modifying default repository list, you should update the list so that the default repositories are left as is. This can be achieved by providing an update function to set-env!
call:
(set-env! :repositories #(conj % ["datomic" {:url "https://my.datomic.com/repo"}]))
When value provided to set-env!
is a function, it works like update
and calls the function with the current value to create the new value.
Managing Credentials
The basic example is usually not satisfactory because you don't want to
commit your build.boot
file with your username and password in it!
The simplest alternative is to use environment variables, like this:
(set-env! :repositories [["clojars" {:url "https://clojars.org/repo/"
:username (System/getenv "CLOJARS_USER")
:password (System/getenv "CLOJARS_PASS")}]])
That accomplishes the goal, but it's not the best because it forces
others to populate their environment with the variables you hardcode
into your build.boot
if they want to deploy the project.
A better way is to omit the :username
and :password
fields from
the repo configuration in your build.boot
like this:
(set-env! :repositories ["clojars" {:url "https://clojars.org/repo/"}](/boot-clj/boot/wiki/"clojars"-{:url-"https://clojars.org/repo/"}))
Then you can use built-in configure-repositories!
function to set a callback
that will configure the repository credentials. The callback is a function
that accepts a repository map argument and returns a new repository map
with any extra configuration (eg. credentials) added to it.
Environment
For example, you can add this to your BOOT_HOME/profile.boot
file:
;; Get credentials for Clojars from the environment.
(configure-repositories!
(fn [{:keys [url] :as repo-map}]
(->> (condp re-find url
#"^https://clojars\.org/repo"
{:username (get-sys-env "CLOJARS_USER" :required)
:password (get-sys-env "CLOJARS_PASS" :required)}
#".*" nil)
(merge repo-map))))
Encrypted Credentials File
You could make a BOOT_HOME/credentials.gpg
file with the following
contents (encrypted of course):
{"https://clojars.org/repo/" {:username "foo" :password "bar"}}
and in your BOOT_HOME/profile.boot
:
(import java.io.File)
;; Get credentials from a GPG encrypted file.
(configure-repositories!
(let [creds-file (File. (boot.App/bootdir) "credentials.gpg")
creds-data (gpg-decrypt creds-file :as :edn)]
(fn [{:keys [url] :as repo-map}]
(merge repo-map (creds-data url)))))
You can, of course do anything you want in your callback, so any combination of environment, encrypted file, or anything else you can think of is posible.
Lein credentials file
You could also read the credentials from Leiningen credentials.clj.gpg. In this case the file contains map of regex to map with credentials. You can use a function to match repository to matching regex and value:
(configure-repositories!
(fn [m]
(merge m (some (fn [regex cred](/boot-clj/boot/wiki/regex-cred) (if (re-find regex (:url m)) cred))
(gpg-decrypt
(clojure.java.io/file
(System/getProperty "user.home") ".lein/credentials.clj.gpg")
:as :edn)))))
Keeping Deploy Repositories Separate
Sometimes you want to deploy to a repository that you don't want to pull
artifacts from; you just want to push to it. You can't add this repository
via (set-env! :repositories ...)
because then it would be used to fetch
as well as push.
The push
task provides the repo-map
option for this situation. This
option takes a repository configuration map and can be used to override
the repositories in :repositories
.
For example:
(task-options! push {:repo-map {:url "https://repos.com/repo/"}})
Your configure-repositories!
callback will be applied to the repo-map
the same a if you had specified it in :repositories
.
For More Info
-
Check
push
task help for complete options. -
Leiningen documentation about repository authentication, including documentation for creating the GPG encrypted credentials file: https://github.com/technomancy/leiningen/blob/master/doc/DEPLOY.md#authentication
GPG setup
Boot will use system GPG binary ($BOOT_GPG_COMAND
) to sign the artifacts
and to read encrypted credentials file. This means that Boot will use your
existing GPG configuration.
If you need to specify specific signing key or to provide passphrase for
key from Boot, check push
task documentation.