Skip to content

Commit 906b629

Browse files
committed
Improve project documentation
1 parent cfe2cd3 commit 906b629

File tree

2 files changed

+211
-34
lines changed

2 files changed

+211
-34
lines changed

README.md

Lines changed: 198 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,115 @@
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)**
3031
- **[Installation](#installation)**
31-
- **[Documentation](#Documentation)**
32+
- **[Documentation](#API-Documentation)**
3233
- **[Kmono CLI](#kmono-cli)**
3334
- **[Example Project](#example-project)**
35+
- **[Configuration](#configuration)**
36+
- **[Workspace Configuration](#workspace-configuration)**
37+
- **[Package Configuration](#package-configuration)**
38+
- **[Local-Only Configuration Overrides](#Local-Only-Configuration-Overrides)**
3439
- **[Clojure-lsp / Editor Integration](#clojure-lsp--editor-integration)**
3540

3641
## Features
3742

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

48134
## Installation
49135

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

67-
## Documentation
153+
## API Documentation
68154

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

89175
Version:
90-
4.6.0
176+
4.9.0
91177

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