Home

Awesome

lein-modules Build Status

This Leiningen plugin provides the benefits of Maven multi-module projects without setting your hair on fire. It works well for a related suite of Leiningen projects stored in a single SCM repository.

Features include the building of automatically-discovered "child" projects in dependency order, flexible project inheritance based on Leiningen profiles, a simple dependency management mechanism, and automatic checkout dependencies.

Installation

Simply include [lein-modules "0.3.11"] in the :plugins vector of every associated module's project.clj.

Minimum supported versions:

Usage

From any "parent" project, use the modules higher-order task to build its "child" projects in the correct order. When you first create a project that has inter-dependent modules, you must install them to your local repo prior to running any task that may attempt to resolve them. You can do this easily from your root project:

$ lein modules install

Once installed, you can run any task you like, e.g.:

$ lein modules test
$ lein modules deps :tree
$ lein modules do clean, jar
$ lein modules analias

By default, the task is not applied to the project in which you run the modules task, only the child projects it finds. You can override this behavior by adding "." to the :dirs vector.

In a child module, just use lein as you normally would, relying on the plugin's implicit middleware to:

  1. merge all ancestors' profiles
  2. update the child's :dependencies from its ancestors' :versions maps.

See the Configuration section for more details on the supported options.

Checkout Dependencies

Run the following command to automatically create checkout dependencies for each related module:

$ lein modules :checkouts

Comparison to lein-sub

Both lein-modules and lein-sub support project aggregation. The modules task is feature-compatible with the sub task.

Consider the following lein-sub configuration:

:sub ["module/common" "module/web" "module/cli"]

And the equivalent lein-modules configuration:

:modules {:dirs ["module/common" "module/web" "module/cli"]
          :subprocess nil}

Usage for both tasks is similar:

$ lein sub install
$ lein sub -s "foo:bar" jar

$ lein modules install
$ lein modules :dirs "foo:bar" jar

But there are some important differences:

Release Management

Leiningen 2.4.0 provides a new release task. To use it with lein-modules, some configuration of its :release-tasks vector is required.

Invoking lein modules release isn't feasible because all the modules reside in the same repo. Only the first would succeed and subsequent modules would error due to the release tag already existing. The version in each modules' project.clj must be changed before committing and tagging the release. So instead of lein modules release, we run lein release in the parent project and adjust its :release-tasks to invoke the "change" and "deploy" tasks for the modules:

(defproject your-project "0.1.0-SNAPSHOT"
  ...
  :modules {:subprocess nil
            :inherited {:deploy-repositories
                        [["releases" {:url "https://clojars.org/repo/" :creds :gpg}]]}}
  :release-tasks [["vcs" "assert-committed"]
                  ["change" "version" "leiningen.release/bump-version" "release"]
                  ["modules" "change" "version" "leiningen.release/bump-version" "release"]
                  ["vcs" "commit"]
                  ["vcs" "tag"]
                  ["modules" "deploy"]
                  ["change" "version" "leiningen.release/bump-version"]
                  ["modules" "change" "version" "leiningen.release/bump-version"]
                  ["vcs" "commit"]
                  ["vcs" "push"]])

Note the :modules map:

Configuration

The modules task will attempt to discover child projects automatically, making the default assumption that each child project resides in an immediate subdirectory of its parent.

Optionally, a :modules map may be added to your project, containing any of the following keys:

Example

Hopefully, an example will clarify the above.

Note the underscores in the dependency vectors, which serve as a placeholder for the string returned from the :versions map. Whatever you set the version to in your dependency vector will be overwritten if a version is found in :versions. Otherwise, whatever is there will remain there. And if a mapping for the symbol can't be found, the version itself will be tried as a key.

Parent

(defproject org.immutant/immutant-suite "1.0.3-SNAPSHOT"
  :plugins [[lein-modules "0.3.11"]]

  :profiles {:provided
               {:dependencies [[org.clojure/clojure "_"]
                               [org.jboss.as/jboss-as-server "_"]
                               [org.jboss.as/jboss-as-web :jbossas]]}
             :dev
               {:dependencies [[midje "_"]]}
             :dist
               {:modules {:dirs ["../dist"]}}

             :fast
               {:modules {:subprocess nil}}}

  :modules  {:inherited
               {:deploy-repositories
                              [["releases" {:url "https://clojars.org/repo/" :creds :gpg}]]
                :repositories [["project:odd upstream"
                                "http://repository-projectodd.forge.cloudbees.com/upstream"]]
                :aliases      {"all" ^:displace ["do" "clean," "test," "install"]
                               "-f" ["with-profile" "+fast"]}
                :mailing-list {:name "Immutant users list"
                               :post "immutant-users@immutant.org"}
                :url          "http://immutant.org"
                :scm          {:dir ".."}
                :license      {:name "Apache Software License - v 2.0"
                               :url "http://www.apache.org/licenses/LICENSE-2.0"}}

             :versions {org.clojure/clojure           "1.5.1"
                        leiningen-core                "2.3.4"
                        midje                         "1.6.0"
                        ring                          "1.2.1"
                        :jbossas                      "7.2.x.slim.incremental.12"
                        org.jboss.as                  :jbossas
                        org.immutant                  :version}})

Child

(defproject org.immutant/web "1.0.3-SNAPSHOT"
  :plugins [[lein-modules "0.3.11"]]
  :description "The web component"
  :dependencies [[org.immutant/core :version]
                 [ring/ring-servlet "_"]
                 [potemkin "0.3.4"]])

License

Copyright © 2014 Jim Crossley

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.