Skip to content

Commit 1a0d02b

Browse files
committed
Improve project documentation
1 parent cfe2cd3 commit 1a0d02b

File tree

2 files changed

+212
-34
lines changed

2 files changed

+212
-34
lines changed

README.md

Lines changed: 199 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
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)
@@ -21,29 +21,116 @@
2121
Kmono is a suite of tools and API's for working in Clojure (mono)repos. It aims to meet Clojure where it's at by
2222
providing 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)**
3032
- **[Installation](#installation)**
31-
- **[Documentation](#Documentation)**
33+
- **[Documentation](#API-Documentation)**
3234
- **[Kmono CLI](#kmono-cli)**
3335
- **[Example Project](#example-project)**
36+
- **[Configuration](#configuration)**
37+
- **[Workspace Configuration](#workspace-configuration)**
38+
- **[Package Configuration](#package-configuration)**
39+
- **[Local-Only Configuration Overrides](#Local-Only-Configuration-Overrides)**
3440
- **[Clojure-lsp / Editor Integration](#clojure-lsp--editor-integration)**
3541

3642
## Features
3743

3844
- **Workspace features**: Discovers packages and understands relationships between dependencies
3945
- **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
46+
pull all alias definitions into a root `deps.edn`
47+
- **Build Tools**: Exposes a suite of tools and APIs intended to be used from `tools.build` programs to build and
48+
release monorepos
4349
- **Command Runner**: Allows executing Clojure and/or external commands in workspace packages
4450
- **Local Deps Overrides**: Allow overriding kmono config and `deps.edn` dependencies during local development. Useful
4551
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
52+
- **Editor/Clojure-lsp**: Integrates with clojure-lsp to provide better classpath information and improve the
53+
developer/editing experience in monorepos
54+
55+
## About
56+
57+
It's generally a bit of a pain to work with `deps.edn` based Clojure monorepos. There is a general lack of good
58+
workspace features that one might find in other languages and that one needs in order to work effectively in a large
59+
monorepo.
60+
61+
Here is a broad list:
62+
63+
- Start a repl with some subset of package aliases (such as `:test`) active
64+
- Have your editor / clojure-lsp know about these subpackage aliases and include their `:extra-paths` on the classpath
65+
- Run common commands across packages in a monorepo
66+
- Track and increment package versions.
67+
- Release package jars with with their referenced workspace dependencies/dependent package versions correctly set.
68+
- Run CI build/test/release workflows against only the subset of packages that have changed since the previous version
69+
or revision.
70+
- Be able to define custom workspace configurations and pipelines that make use of the workspace graph / metadata in an
71+
unopinionated way which may differ from workspace to workspace.
72+
- Script against the workspace package graph (run queries against the package graph)
73+
74+
Kmono aims to solve all of these problems.
75+
76+
There are some existing projects out there that are trying to solve for this problem too - but I find that they are
77+
either too opinionated, too rigid, or stray too far from the 'official' tooling too much.
78+
79+
Kmono tries to build on top of `tools.deps` and the clojure cli in order to add additional functionality / capabilities
80+
in a way that feels native to `tools.deps` based projects. It tries to do this in a way that does not require
81+
configuring the project in a non-standard way, or configuring it in a manner which would render it incompatible with
82+
other tools.deps based tooling.
83+
84+
I see the functionality added here as a kind of proposal to the Clojure core team for how I might want workspace
85+
features to work in the core tools.deps and clojure tooling.
86+
87+
## How It Works
88+
89+
### Workspace Package Graph
90+
91+
At the core kmono is a tool which understands how packages in a Clojure workspace relate and depend on each other. This
92+
is done by analysing the `:deps` of packages to find `:local/root` coordinates to other packages in the same workspace.
93+
Using this information kmono can build up a graph of packages and their dependencies.
94+
95+
All of kmono's features and capabilities are built on top of this package graph.
96+
97+
### The Classpath and Package Aliases
98+
99+
Using the package graph kmono can augment the clojure cli with additional aliases constructed from the package graph.
100+
This allows 'telling' clojure about the aliases and paths of subpackages in the workspace.
101+
102+
When you run a command like `kmono cp -P ':*/test'` kmono will look for packages in the workspace containing a `:test`
103+
alias, and it will 'lift' these aliases into the root deps.edn config.
104+
105+
If we were to run this command in the [example workspace project](./examples/workspace/) it would result in a call to
106+
the clojure CLI that looks something like:
107+
108+
```bash
109+
clojure -Sdeps '{:aliases {:a/test {:extra-paths ["packages/a/test"]
110+
:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}}
111+
:main-opts ["-m" "kaocha.runner" "-c" "../../tests.edn"]}
112+
:b/test {:extra-paths ["packages/b/test"]
113+
:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}}
114+
:main-opts ["-m" "kaocha.runner" "-c" "../../tests.edn"]}
115+
:kmono/packages {:extra-deps {com.kepler16/a {:local/root "packages/a"}
116+
com.kepler16/b {:local/root "packages/b"}}}}}' \
117+
-A:kmono/packages:a/test:b/test -Spath
118+
```
119+
120+
As you can see we have extended the `deps.edn` project configuration using `-Sdeps` and passing it a set of aliases
121+
dynamically constructed from the package graph.
122+
123+
You should also notice that any relative paths defined by package aliases in the workspace have been adjusted to be
124+
relative to the project root instead of to the package.
125+
126+
Using `-A` kmono can selectively pick which aliases to apply!
127+
128+
Most kmono cli commands can be run with `-v` to print out debug information about what clojure command kmono is
129+
constructing.
130+
131+
### Querying Workspace Graph
132+
133+
### Versioning / Releasing
47134

48135
## Installation
49136

@@ -64,7 +151,7 @@ bash < <(curl -s https://raw.githubusercontent.com/kepler16/kmono/master/install
64151
Or alternatively binaries for various platforms can be pulled directly from the
65152
[Releases](https://github.com/kepler16/kmono/releases) page.
66153

67-
## Documentation
154+
## API Documentation
68155

69156
- **[kmono](https://cljdoc.org/d/com.kepler16/kmono)** - A BOM package containing all the submodules of kmono. This is
70157
the best one to look at for docs.
@@ -87,7 +174,7 @@ Usage:
87174
kmono [opts] <args>
88175

89176
Version:
90-
4.6.0
177+
4.9.0
91178

92179
Commands:
93180
cp Produce a classpath string from a clojure project
@@ -108,16 +195,115 @@ Global Options
108195
#### Example project
109196
110197
Take 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
198+
kmono is built to support. This should provide a good reference on how to correctly use the kmono API's and integrate it
199+
into your own project.
200+
201+
## Configuration
202+
203+
Kmono will work in any `deps.edn` based project, but needs explicit configuration in order to treat a project as a
204+
workspace (or monorepo).
205+
206+
### Workspace Configuration
207+
208+
To mark a project as a kmono workspace add a `:kmono/workspace {}` field to the root `deps.edn` config file. This
209+
configuration accepts the following properties:
210+
211+
| Field | Type | Default | Description |
212+
| ------------------ | ----------------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
213+
| `:packages` | `string? \| #{string?}` | "./packages/\*\*" | A glob or set of file globs that describe the set of packages included in the workspace |
214+
| `:group` | `symbol?` | `nil` | The mvn group to apply to any packages in the workspace that have not specified a group |
215+
| `:repl-aliases` | `[keyword?]` | `nil` | A set of `deps` aliases to include when running `kmono repl` |
216+
| `:aliases` | `[keyword?]` | `nil` | A set of `deps` aliases to include for all kmono workspace commands by default |
217+
| `: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 |
218+
219+
Example:
220+
221+
```clojure
222+
;; deps.edn
223+
{:kmono/workspace {:group com.example
224+
:packages #{"./(packages|modules)/**"}
225+
;; Include any `:test` aliases from all (`*`) packages in the
226+
;; workspace
227+
:package-aliases [:*/test]}
228+
229+
:paths ["src" "resources"]
230+
231+
:deps {...}}
232+
```
233+
234+
### Package Configuration
235+
236+
Packages in the workspace can optionally provide their own configuration metadata. This is done by setting a
237+
`:kmono/package {}` config field in the packages `deps.edn` file. This config accepts the following properties:
238+
239+
| Field | Type | Default | Description |
240+
| ----------- | -------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
241+
| `: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. |
242+
| `: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 |
243+
| `:excluded` | `boolean?` | `false` | Whether or not this package is excluded from the project workspace |
244+
245+
Example
246+
247+
```clojure
248+
;; packages/example/deps.edn
249+
{:kmono/package {;; Maven artifacts group
250+
:group com.example
251+
;; Override the default package name
252+
:name example-lib}
253+
254+
:paths ["src"]
255+
:deps {...}
256+
:aliases {:test {...}}}
257+
```
258+
259+
### Local-Only Configuration Overrides
260+
261+
Kmono will automatically read in a `deps.local.edn` file from the project root and deep-merge it with the root
262+
`deps.edn` file if present.
263+
264+
This is very useful for adding additional configuration such as default-enabled project aliases, new project-specific
265+
dev-only deps aliases or any other metadata in a way that is local to the developers environment and won't be committed
266+
to the project.
267+
268+
This `deps.local.edn` file should typically be added to `.gitignore`.
269+
270+
The below is a good example of how this `deps.local.edn` config might be used in someones environment:
271+
272+
```clojure
273+
{:kmono/workspace {;; Add the :nrepl alias from ~/.clojure/deps.edn when running
274+
;; `kmono repl`
275+
:repl-aliases [:nrepl]
276+
;; - Include the :dev alias from ~/.clojure/deps.edn
277+
;;
278+
;; - Include the :local alias defined below
279+
:aliases [:dev :local]}
280+
281+
:aliases {;; Define a custom local-only alias for this project
282+
:local {;; Override some dependency with a locally checked out copy
283+
;; for development
284+
:extra-deps {com.example/some-lib {:local/root "/some/local/lib/path"}}}
285+
:extra-paths ["local"]}}
286+
```
287+
288+
This config will be loaded and included for this project when running commands such as
289+
290+
```bash
291+
kmono cp
292+
kmono repl
293+
kmono clojure ...
294+
```
295+
296+
This is especially useful in an editor that has been configured to use
297+
[kmono as the project-specs source](#clojure-lsp--editor-integration), or when using kmono to start a repl for the
112298
project.
113299
114300
## Clojure-lsp / Editor Integration
115301
116302
One 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.
303+
`clojure -Spath` which is used by clojure-lsp by default.
118304
119305
If we instead use `kmono cp` to generate the classpath then your clojure-lsp server will be able to provide better
120-
analysis.
306+
analysis that includes information about subpackages of your workspace, as well as package aliases.
121307
122308
#### Project local Clojure-LSP config
123309
@@ -142,15 +328,3 @@ lspconfig.clojure_lsp.setup({
142328
},
143329
})
144330
```
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-
```

examples/workspace/README.md

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,23 @@ This is the overall structure of the project:
2323

2424
In this structure we have two packages - `a` and `b` where package `b` depends on package `a`.
2525

26-
This project demonstrates a workflow where:
26+
> [!NOTE]
27+
>
28+
> Run `kmono query` to query the workspace package graph and see how packages relate
2729
28-
1) Packages are built and released when PR's are merged to master.
29-
2) Only packages that have changed since their previous version are build and released.
30-
3) The project uses convensional-commits and package versions are derived from commits.
30+
This project demonstrates a workflow where:
31+
32+
1. Packages are built and released when PR's are merged to master.
33+
2. Only packages that have changed since their previous version are build and released.
34+
3. The project uses convensional-commits and package versions are derived from commits.
3135

3236
The above requirements aren't needed to make use of kmono - this just serves to demonstrate a particular workflow and
3337
how you might use kmono to achieve it.
3438

3539
## Building/Releasing
3640

3741
The build and release workflow described above is entirely encapsulated in the `build.clj` file using `tools.build` and
38-
kmono-* APIs.
42+
kmono-\* APIs.
3943

4044
Packages can be built by running:
4145

@@ -49,8 +53,8 @@ And the built packages can then be released by running
4953
clojure -T:build release
5054
```
5155

52-
For both building and releasing you can add the `:skip-unchanged true` argument to build and release only packages that
53-
have changed. The idea being that you would pass this by default during CI.
56+
For both building and releasing you can add the `:skip-unchanged true` argument to only build and release packages that
57+
have changed since their last release. The idea being that you would pass this by default during CI.
5458

5559
```bash
5660
clojure -T:build build :skip-unchanged true
@@ -69,8 +73,8 @@ pipeline for release.
6973
To run the tests for each package you can run the command
7074

7175
```bash
76+
# Run `clojure -M` in each package (indicated by the `*`) that has a `:test` alias.
7277
kmono run -M ':*/test'
7378
```
7479

75-
This means run `clojure -M` in each package (indicated by the `*`) that has a `:test` alias. Each respective packages'
76-
`:test` alias will then be appended to the command when it is run, like so: `clojure -M:test`.
80+
Each respective packages' `:test` alias will then be appended to the command when it is run, like so: `clojure -M:test`.

0 commit comments

Comments
 (0)