1111 <h1 >Kmono</h1 >
1212
1313 <p >
14- The missing workspace tool for clojure tools.deps projects
14+ A monorepo/ workspace tool for clojure tools.deps projects
1515 </p >
1616
1717[ ![ Clojars Project] ( https://img.shields.io/clojars/v/com.kepler16/kmono-core.svg )] ( https://clojars.org/com.kepler16/kmono-core )
2121Kmono is a suite of tools and API's for working in Clojure (mono)repos. It aims to meet Clojure where it's at by
2222providing a better understanding of deps.edn projects.
2323
24- This project was built with a focus on improving the experience of working in Clojure monorepos but works great in
25- standalone projects too.
24+ While Kmono was designed with a focus on improving the experience of working in Clojure monorepos, care has been taken
25+ to ensure it works great in standalone (non-workspace) projects too.
2626
2727## Index
2828
2929- ** [ Features] ( #features ) **
30+ - ** [ About] ( #about ) **
31+ - ** [ How It Works] ( #how-it-works ) **
32+ - ** [ Workspace Package Graph] ( #workspace-package-graph ) **
33+ - ** [ The Classpath and Package Aliases] ( #The-Classpath-and-Package-Aliases ) **
34+ - ** [ Clojure APIs] ( #clojure-apis ) **
35+ - ** [ Versioning / Change Detection] ( #Versioning--Change-Detection ) **
3036- ** [ Installation] ( #installation ) **
31- - ** [ Documentation] ( #Documentation ) **
37+ - ** [ Documentation] ( #API- Documentation ) **
3238 - ** [ Kmono CLI] ( #kmono-cli ) **
3339 - ** [ Example Project] ( #example-project ) **
40+ - ** [ Configuration] ( #configuration ) **
41+ - ** [ Workspace Configuration] ( #workspace-configuration ) **
42+ - ** [ Package Configuration] ( #package-configuration ) **
43+ - ** [ Local-Only Configuration Overrides] ( #Local-Only-Configuration-Overrides ) **
3444- ** [ Clojure-lsp / Editor Integration] ( #clojure-lsp--editor-integration ) **
3545
3646## Features
3747
3848- ** Workspace features** : Discovers packages and understands relationships between dependencies
3949- ** Aliases** : Allows working with packages aliases defined in ` deps.edn ` in a 'Clojure native' way without having to
40- pull all alias definitions into root ` deps.edn `
41- - ** Build Tools** : Exposes a suite of libs intended to be used from ` tools.build ` programs to build and release
42- monorepos
50+ pull all alias definitions into a root ` deps.edn `
51+ - ** Build Tools** : Exposes a suite of tools and APIs intended to be used from ` tools.build ` programs to build and
52+ release monorepos
4353- ** Command Runner** : Allows executing Clojure and/or external commands in workspace packages
4454- ** Local Deps Overrides** : Allow overriding kmono config and ` deps.edn ` dependencies during local development. Useful
4555 for providing local paths to in-development libs without committing.
46- - ** Editor/Clojure-lsp** : Improves developer/editing experience by augmenting the classpath used by clojure-lsp
56+ - ** Editor/Clojure-lsp** : Integrates with clojure-lsp to provide better classpath information and improve the
57+ developer/editing experience in monorepos
58+
59+ ## About
60+
61+ It's generally a bit of a pain to work with ` deps.edn ` based Clojure monorepos. There is a general lack of good
62+ workspace features that one might find in other languages and that one needs in order to work effectively in a large
63+ monorepo.
64+
65+ Here is a broad list:
66+
67+ - Start a repl with some subset of package aliases (such as ` :test ` ) active
68+ - Have your editor / clojure-lsp know about these subpackage aliases and include their ` :extra-paths ` on the classpath
69+ - Run common commands across packages in a monorepo
70+ - Track and increment package versions.
71+ - Release package jars with with their referenced workspace dependencies/dependent package versions correctly set.
72+ - Run CI build/test/release workflows against only the subset of packages that have changed since the previous version
73+ or revision.
74+ - Be able to define custom workspace configurations and pipelines that make use of the workspace graph / metadata in an
75+ unopinionated way which may differ from workspace to workspace.
76+ - Script against the workspace package graph (run queries against the package graph)
77+
78+ Kmono aims to solve all of these problems.
79+
80+ There are some existing projects out there that are trying to solve for this problem too - but I find that they are
81+ either too opinionated, too rigid, or stray too far from the 'official' tooling too much.
82+
83+ Kmono tries to build on top of ` tools.deps ` and the clojure cli in order to add additional functionality / capabilities
84+ in a way that feels native to ` tools.deps ` based projects. It tries to do this in a way that does not require
85+ configuring the project in a non-standard way, or configuring it in a manner which would render it incompatible with
86+ other tools.deps based tooling.
87+
88+ I see the functionality added here as a kind of proposal to the Clojure core team for how I might want workspace
89+ features to work in the core tools.deps and clojure tooling.
90+
91+ ## How It Works
92+
93+ ### Workspace Package Graph
94+
95+ At the core kmono is a tool which understands how packages in a Clojure workspace relate and depend on each other. This
96+ is done by analysing the ` :deps ` of packages to find ` :local/root ` coordinates to other packages in the same workspace.
97+ Using this information kmono can build up a graph of packages and their dependencies.
98+
99+ All of kmono's features and capabilities are built on top of this package graph.
100+
101+ ### The Classpath and Package Aliases
102+
103+ Using the package graph kmono can augment the clojure cli with additional aliases constructed from the package graph.
104+ This allows 'telling' clojure about the aliases and paths of subpackages in the workspace.
105+
106+ When you run a command like ` kmono cp -P ':*/test' ` kmono will look for packages in the workspace containing a ` :test `
107+ alias, and it will 'lift' these aliases into the root deps.edn config.
108+
109+ If we were to run this command in the [ example workspace project] ( ./examples/workspace/ ) it would result in a call to
110+ the clojure CLI that looks something like:
111+
112+ ``` bash
113+ clojure -Sdeps ' {:aliases {:a/test {:extra-paths ["packages/a/test"]
114+ :extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}}
115+ :main-opts ["-m" "kaocha.runner" "-c" "../../tests.edn"]}
116+ :b/test {:extra-paths ["packages/b/test"]
117+ :extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}}
118+ :main-opts ["-m" "kaocha.runner" "-c" "../../tests.edn"]}
119+ :kmono/packages {:extra-deps {com.kepler16/a {:local/root "packages/a"}
120+ com.kepler16/b {:local/root "packages/b"}}}}}' \
121+ -A:kmono/packages:a/test:b/test -Spath
122+ ```
123+
124+ From this you can see kmono has extended the ` deps.edn ` project configuration using the clojure cli ` -Sdeps ` flag,
125+ passing it a set of aliases dynamically constructed from the package graph.
126+
127+ You should notice that any relative paths defined by package aliases in the workspace have been adjusted to be relative
128+ to the project root instead of to the package.
129+
130+ Using ` -A ` kmono can selectively pick which aliases to apply!
131+
132+ Most kmono cli commands can be run with ` -v ` to print out debug information about what clojure command kmono is
133+ constructing.
134+
135+ ### Clojure APIs
136+
137+ Kmono exposes a large set of clojure APIs which can be used to work with the analyzed workspace package graph. These
138+ APIs are primarily intended to be used within ` tools.build ` pipelines to define custom build + release workflows that
139+ fit the projects requirements, but could be used for building custom tools/clis/scripts.
140+
141+ Most API's are for querying, filtering, or versioning packages in the graph. Two key APIs exposed are
142+ ` k16.kmono.build/for-each-package ` and ` k16.kmono.build/create-basis ` .
143+
144+ #### ` k16.kmono.build/for-each-package `
145+
146+ This allows iterating over the packages in a given package graph and executing a given function in the context of that
147+ package. It allows using the ` tools.build ` API's as if they were executed from the directory of the workspace package.
148+
149+ #### ` k16.kmono.build/create-basis `
150+
151+ This allows constructing a ` tools.build ` basis wherein any references to workspace packages have been replaced with
152+ their maven coordinates. This is key to simplifying the process of incrementing package versions, building and
153+ releasing.
154+
155+ Please see the [ example workspace] ( ./examples/workspace/ ) or kmono itself for some examples on how to use the API's
156+ exposed by kmono.
157+
158+ ### Versioning / Change Detection
159+
160+ Packages in the graph can have a set of ` :commits ` associated with them, as well as a ` :version ` . Various kmono API's
161+ work by populating these fields for packages in a graph or operating over this information.
162+
163+ For example there is ` k16.kmono.version/inc-package-versions ` which will increment the version of packages in a given
164+ package graph.
165+
166+ There is ` k16.kmono.version/package-changed? ` which can be used to filter out packages which have not changed since some
167+ previous revision / version.
168+
169+ This information can be populated into the graph however you want, but there are also some built-in mechanisms for
170+ associating package versions and commits.
171+
172+ For versions the built-in mechanism is to track package versions in git tags. The
173+ ` k16.kmono.version/resolve-package-versions ` will look for git tags following the pattern ` <group>/<package-name>@<version> `
174+ and will use the ` <version> ` component to populate package version in the graph.
175+
176+ The ` k16.kmono.version/resolve-package-changes ` can be used to find commits that have changed the package since it's
177+ last tagged version.
178+
179+ The ` k16.kmono.version/resolve-package-changes-since ` can be used to find commits that have changed the package since a
180+ given git revision.
181+
182+ These tools and others can be used to build sophisticated build and release pipelines for kmono workspaces.
47183
48184## Installation
49185
@@ -64,7 +200,7 @@ bash < <(curl -s https://raw.githubusercontent.com/kepler16/kmono/master/install
64200Or alternatively binaries for various platforms can be pulled directly from the
65201[ Releases] ( https://github.com/kepler16/kmono/releases ) page.
66202
67- ## Documentation
203+ ## API Documentation
68204
69205- ** [ kmono] ( https://cljdoc.org/d/com.kepler16/kmono ) ** - A BOM package containing all the submodules of kmono. This is
70206 the best one to look at for docs.
@@ -87,7 +223,7 @@ Usage:
87223 kmono [opts] < args>
88224
89225Version:
90- 4.6 .0
226+ 4.9 .0
91227
92228Commands:
93229 cp Produce a classpath string from a clojure project
@@ -108,16 +244,115 @@ Global Options
108244# ### Example project
109245
110246Take a look at ** [the example project](./examples/workspace/)** to get a better idea of the type of project structures
111- kmono is built to support and for references on how to correctly use the kmono API' s and integrate it into your own
247+ kmono is built to support. This should provide a good reference on how to correctly use the kmono API' s and integrate it
248+ into your own project.
249+
250+ ## Configuration
251+
252+ Kmono will work in any `deps.edn` based project, but needs explicit configuration in order to treat a project as a
253+ workspace (or monorepo).
254+
255+ ### Workspace Configuration
256+
257+ To mark a project as a kmono workspace add a `:kmono/workspace {}` field to the root `deps.edn` config file. This
258+ configuration accepts the following properties:
259+
260+ | Field | Type | Default | Description |
261+ | ------------------ | ----------------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
262+ | `:packages` | `string? \| #{string?}` | "./packages/\*\*" | A glob or set of file globs that describe the set of packages included in the workspace |
263+ | `:group` | `symbol?` | `nil` | The mvn group to apply to any packages in the workspace that have not specified a group |
264+ | `:repl-aliases` | `[keyword?]` | `nil` | A set of `deps` aliases to include when running `kmono repl` |
265+ | `:aliases` | `[keyword?]` | `nil` | A set of `deps` aliases to include for all kmono workspace commands by default |
266+ | `:package-aliases` | `[keyword?]` | `nil` | A set of namespaced [alias globs](#alias-globs) that describe the aliases of packages within the workspace to include in the classpath |
267+
268+ Example:
269+
270+ ```clojure
271+ ;; deps.edn
272+ {:kmono/workspace {:group com.example
273+ :packages #{"./(packages|modules)/**"}
274+ ;; Include any `:test` aliases from all (`*`) packages in the
275+ ;; workspace
276+ :package-aliases [:*/test]}
277+
278+ :paths ["src" "resources"]
279+
280+ :deps {...}}
281+ ```
282+
283+ ### Package Configuration
284+
285+ Packages in the workspace can optionally provide their own configuration metadata. This is done by setting a
286+ `:kmono/package {}` config field in the packages `deps.edn` file. This config accepts the following properties:
287+
288+ | Field | Type | Default | Description |
289+ | ----------- | -------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
290+ | `:group` | `symbol?` | `nil` | The mvn group to use for this package. If not specified, the `:group` specified in the root `:kmono/workspace` configuration will be used. |
291+ | `:name` | `string? \| symbol?` | `$dir` | The name of the package. If not set the name of the parent directory containing the packages' ` deps.edn` file will be used as the package name |
292+ | ` :excluded` | ` boolean? ` | ` false` | Whether or not this package is excluded from the project workspace |
293+
294+ Example
295+
296+ ` ` ` clojure
297+ ;; packages/example/deps.edn
298+ {:kmono/package {;; Maven artifacts group
299+ :group com.example
300+ ;; Override the default package name
301+ :name example-lib}
302+
303+ :paths [" src" ]
304+ :deps {...}
305+ :aliases {:test {...}}}
306+ ` ` `
307+
308+ # ## Local-Only Configuration Overrides
309+
310+ Kmono will automatically read in a ` deps.local.edn` file from the project root and deep-merge it with the root
311+ ` deps.edn` file if present.
312+
313+ This is very useful for adding additional configuration such as default-enabled project aliases, new project-specific
314+ dev-only deps aliases or any other metadata in a way that is local to the developers environment and won' t be committed
315+ to the project.
316+
317+ This `deps.local.edn` file should typically be added to `.gitignore`.
318+
319+ The below is a good example of how this `deps.local.edn` config might be used in someones environment:
320+
321+ ```clojure
322+ {:kmono/workspace {;; Add the :nrepl alias from ~/.clojure/deps.edn when running
323+ ;; `kmono repl`
324+ :repl-aliases [:nrepl]
325+ ;; - Include the :dev alias from ~/.clojure/deps.edn
326+ ;;
327+ ;; - Include the :local alias defined below
328+ :aliases [:dev :local]}
329+
330+ :aliases {;; Define a custom local-only alias for this project
331+ :local {;; Override some dependency with a locally checked out copy
332+ ;; for development
333+ :extra-deps {com.example/some-lib {:local/root "/some/local/lib/path"}}}
334+ :extra-paths ["local"]}}
335+ ```
336+
337+ This config will be loaded and included for this project when running commands such as
338+
339+ ```bash
340+ kmono cp
341+ kmono repl
342+ kmono clojure ...
343+ ```
344+
345+ This is especially useful in an editor that has been configured to use
346+ [kmono as the project-specs source](#clojure-lsp--editor-integration), or when using kmono to start a repl for the
112347project.
113348
114349## Clojure-lsp / Editor Integration
115350
116351One of the things that kmono enables is integration into your editor by acting as a drop-in replacement for
117- `clojure -Spath` which is used by default by clojure-lsp.
352+ `clojure -Spath` which is used by clojure-lsp by default .
118353
119354If we instead use `kmono cp` to generate the classpath then your clojure-lsp server will be able to provide better
120- analysis.
355+ analysis that includes information about subpackages of your workspace, as well as package aliases .
121356
122357#### Project local Clojure-LSP config
123358
@@ -142,15 +377,3 @@ lspconfig.clojure_lsp.setup({
142377 },
143378})
144379```
145-
146- ### Package configuration
147-
148- Package-specific configurations are done within each `deps.edn` file under the `:kmono/package` key:
149-
150- ```clj
151- :kmono/package {;; maven artifact' s group
152- :group com.example
153- ;; the package name which is also used as maven' s artifactId
154- ;; this is optional and inferred from a package' s dir name
155- :name my-lib}
156- ` ` `
0 commit comments