Skip to content

Repository Credentials and Deploying

Juho Teperi edited this page Dec 24, 2015 · 7 revisions

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/"}]])

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]] (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

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.

Clone this wiki locally