Package projects with tools.buildλ︎
Improved build script examples have been added
Please report any issues using the new examples
Clojure.org tools.build is a library to define build related tasks using Clojure code.
The tools.build API provides a consistent interface to access the project configuration (project basis) and common tasks that facilitate building and packaging projects.
Include a build alias and build script in each project to make use of Clojure tools.build:
:build/taskalias adding tools.build library to the class path in the projectdeps.ednfilebuild.cljdefines a namespace requiring tools.build, a project configuration and functions as build tasks
Practicalli Project Templates include tools.build tasks
Practicalli Project templates include a build.clj tasks to generate a library jar or a service uberjar.
Define build aliasλ︎
Add an alias to the project deps.edn file which includes the org.clojure/tools.build project.
:build/task alias created by Practicalli Project Templates
Use Clojure CLI to run any of the tasks defined in the build namespaces.
tools.build release information
Clojure.org tools.build release information shows the current values for git/tag and :git/sha
Developing code in the build script
:replace-paths ["."] includes the build.clj file on the class path to allow for REPL development of the build tasks
Include :build alias in the Clojure command when starting the REPL.
Build Scriptλ︎
Create a build.clj file which defines a namespace requiring tools.build, a project configuration and functions as build tasks
An Uberjar file is built to deploy a Clojure service, e.g. in test, staging or production environment.
A Jar file is built to published a Clojure library to a Maven repository, e.g. Clojars.org, Maven Central or a private Maven repository.
Namespace definitionλ︎
Define the namespace and require the clojure.tools.build.api and any additional libraries.
Build configurationλ︎
Define a hash-map containing keys and values required to build the project.
Define a project configuration for building an Uberjar file to run a service using the java -jar command.
The Uberjar can be deployed to run the service in test, staging and production environments.
Clojure Service build tasks
;; ---------------------------------------------------------
;; Project configuration
(def project-config
"Project configuration to support build tasks"
{:class-directory "target/classes"
:main-namespace 'practicalli/project-name/service
:project-basis (build-api/create-basis)
:uberjar-file "target/practicalli-servicename-standalone.jar"})
(defn config
"Display build configuration"
[config]
(pprint/pprint (or config project-config)))
;; End of Build configuration
;; ---------------------------------------------------------
Define a project configuration for building a jar file for deployment on Clojars and Maven Central, or a private repository.
pom-templateis the standard structure for generating a pom.xml file, required by Maven repositories, i.e. Clojars.org and Maven Centralproject-configspecific values for building the project, e.g. name, version, etc.configfunction to pretty print the build configuration
Clojure Library build tasks
;; ---------------------------------------------------------
;; Build configuration
(defn- pom-template
"Standard structure for a `pom.xml` file, a Maven project configuration
required to deploy libraries to Clojars.org, Maven Central or private Maven repositories
https://maven.apache.org/guides/introduction/introduction-to-the-pom.html"
[project-version]
[[:description "FIXME: add purpose of library."]
[:url "https://github.com/organisation/project-name"]
[:licenses
[:license
[:name "Creative Commons Attribution-ShareAlike 4.0 International"]
[:url "https://creativecommons.org/licenses/by-sa/4.0/"]]]
[:developers
[:developer
[:name "Organisation name"]]]
[:scm
[:url "https://github.com/organisation/project-name"]
[:connection "scm:git:https://github.com/organisation/project-name.git"]
[:developerConnection "scm:git:ssh:git@github.com:organisation/project-name.git"]
[:tag (str "v" project-version)]]])
(def project-config
"Project configuration to support build tasks"
(let [library-name 'net.clojars.organisation/project-name
version "0.1.0-SNAPSHOT"]
{:library-name library-name
:project-version version
:jar-file (format "target/%s-%s.jar" (name library-name) version)
:project-basis (build-api/create-basis)
:class-directory "target/classes"
:src-directory ["src"]
:target-directory "target"
:pom-config (pom-template version)}))
(defn config
"Display build configuration"
[config]
(pprint/pprint (or config project-config)))
;; End of Build configuration
;; ---------------------------------------------------------
Build Taskλ︎
Define Clojure functions to run the required build tasks
cleanto remove build artefacts, e.g.targetdirectoryUberjarcreates a Jar file for a Clojure library, ready for publishing
Clojure Service build tasks
;; ---------------------------------------------------------
;; Build tasks
(defn clean
"Remove a directory
- `:path '\"directory-name\"'` for a specific directory
- `nil` (or no command line arguments) to delete `target` directory
`target` is the default directory for build artefacts
Checks that `.` and `/` directories are not deleted"
[directory]
(when
(not (contains? #{"." "/"} directory))
(build-api/delete {:path (or (:path directory) "target")})))
(defn uberjar
"Create an archive containing Clojure and the build of the project
Merge command line configuration to the default project config"
[options]
(let [config (merge project-config options)
{:keys [class-directory main-namespace project-basis uberjar-file]} config]
(clean "target")
(build-api/copy-dir {:src-dirs ["src" "resources"]
:target-dir class-directory})
(build-api/compile-clj {:basis project-basis
:class-dir class-directory
:src-dirs ["src"]})
(build-api/uber {:basis project-basis
:class-dir class-directory
:main main-namespace
:uber-file uberjar-file})))
;; End of Build tasks
;; ---------------------------------------------------------
Define Clojure functions to run the required build tasks
cleanto remove build artefacts, e.g.targetdirectoryjarcreates a Jar file for a Clojure library, ready for publishinginstalla built jar into the local Maven repository, e.g. `~/.m2/repository/publisha built jar to Clojars.org
Clojure Library build tasks
;; ---------------------------------------------------------
;; Build tasks
(defn clean
"Remove a directory
- `:path '\"directory-name\"'` for a specific directory
- `nil` (or no command line arguments) to delete `target` directory
`target` is the default directory for build artefacts
Checks that `.` and `/` directories are not deleted"
[directory]
(when (not (contains? #{"." "/"} directory))
(build-api/delete {:path (or (:path directory) "target")})))
(defn jar "Run the CI pipeline of tests (and build the JAR)."
[config]
(clean "target")
(let [config (project-config config)
class-directory (config :class-directory)]
(println "\nWriting pom.xml...")
(build-api/write-pom (merge (pom-template config)))
(println "\nCopying source...")
(build-api/copy-dir {:src-directory ["resources" "src"] :target-directory class-directory})
(println "\nBuilding JAR..." (:jar-file config))
(build-api/jar config))
config)
(defn install
"Install a built JAR in the local Maven repository, e.g. `.m2/repository`"
[config]
(let [config (project-config config)]
(build-api/install config))
config)
(defn publish
"Publish the built JAR to Clojars."
[config]
(let [{:keys [jar-file] :as config} (project-config config)]
(deploy-api/deploy
{:installer :remote :artifact (build-api/resolve-path jar-file)
:pom-file (build-api/pom-path (select-keys config [:library-name :class-directory]))}))
config)
;; End of Build tasks
;; ---------------------------------------------------------