Ecosystem: Library Development and Distribution
- Prequisites
- Publishing Libraries
- Creating New Projects
- Making the Project your own
- Create your project's local git repository
- Write Tests
- Write Code
- Run Tests
- Commit any remaining changes
- Complete the GitHub Project Setup and Upload your Code
- Upload to Clojars
- Generate API docs (optional)
- Announce (optional)
- Make Updates to your library
- See Also
- Contributors
This guide covers how to create your own typical pure Clojure library and distribute it to the community via Clojars, as well as making it available in source form on a public repository such as GitHub.
Prequisites
This guide assumes you have an account on a public hosting service
like GitHub and you will need to use your account name as part of
your project. In this guide, we use clojure-example-library
as the
account name: you should substitute your own account name wherever you
see clojure-example-library
in this guide! We will use my-cool-lib
as the name of the new project we create and publish here, but you
can use whatever name you want -- just remember to substitute that
wherever you see my-cool-lib
in this guide.
This guide uses Clojure 1.11 and a recent version of the Clojure CLI
(at least 1.11.1.1139; current version is 1.11.4.1474 as of August 2024),
and requires you have git
installed (though very little familiarity with git
is required).
Note: you should always ensure you have an up-to-date version of the Clojure CLI installed! See Tools Releases. Several of the examples here require 1.11.1.1139 or later:
clojure -version
should tell you the version you have installed.
It's assumed that you're already somewhat familiar with Clojure. If not, see the Getting Started and Introduction guides.
This work is licensed under a Creative Commons Attribution 3.0 Unported License (including images & stylesheets). The source is available on Github.
Note: If you're using Leiningen, read the Library Development and Distribution with Leiningen guide.
Publishing Libraries
Prior to the appearance of the Clojure CLI in 2018, it was generally assumed that you would publish the source of your library to a public service like GitHub, but that you would also need to package your library as a JAR file and deploy it to Clojars (or Maven Central) so that it was available for others to use in their projects as a dependency.
The Clojure CLI can treat projects hosted on public services, like GitHub, as first-class dependencies, so that it is no longer necessary to package and deploy your library elsewhere -- if you expect your users to consume the library directly in source form. In order to make your library available to users who are working with Leiningen (or other build tools), it is still required to package and deploy your project as a JAR file -- which this guide also covers.
Publishing to GitHub
If you don't already have a GitHub account, create one, then log into it. GitHub provides good documentation on how to get started and how to create an SSH key pair. If you haven't already done so, get that set up before continuing.
Go to the Repositories tab and create a new repository there for your project using the icon/button/link (near the top-right if you already have existing projects, else prominently in the middle if this is your first repository).
You will have your local repository, and also a remote duplicate of it at GitHub.
For the repository name, we'll use my-cool-lib
in this guide (but you
can use whatever name you want).
Provide a one-line description if you want, make sure to select Public
so that others can access your project, and hit "Create repository".
You do not need GitHub to provide a README, a .gitignore
file, or
a license, since we'll add those.
For a project published to GitHub as clojure-example-library/my-cool-lib
,
the default dependency for others to use would be:
io.github.clojure-example-library/my-cool-lib {:git/sha "..."}
Where the "..."
value would be the full SHA (hex string) for the version
that they wanted to use (e.g., from the latest commit).
If you have tagged a release on GitHub, e.g., v0.1.0
then you can use
:git/tag "v0.1.0"
and the :git/sha
value can be the "short SHA" -- just
the first seven characters of the hex string.
The Clojure CLI understands that io.github.<account>/<repo>
maps to
https://github.com/<account>/<repo>
in order to fetch the repository.
The CLI understands
several source code repositories
so you could use GitLab, BitBucket, Beanstalk, or Sourcehut (as of May 2023).
Publishing to Clojars
If you don't already have an account, you will need to
register on Clojars.
It will convenient for you to use the same email account as you use
for GitHub, so that you can login to Clojars in future via GitHub,
which will automatically verify your GitHub-associated "group ID"
with Clojars (e.g., io.github.<account>
).
See Verified Group Names
for more details.
You will also need to set up at least one deploy token and provide environment variables when you get to the point of actually deploying your library JAR to Clojars:
CLOJARS_USERNAME
-- set to your Clojars usernameCLOJARS_PASSWORD
-- set to a valid deploy token
If you don't want to connect your Clojars account to your GitHub account,
you can use net.clojars.<username>
as your "group ID" for deploying
projects. That style of group name is always verified for Clojars.
Creating New Projects
If you only ever intend to publish your library to GitHub and not to Clojars,
you can create a fairly minimal project (deps.edn
file, src/
folder) and
rely on io.github.<account>/<project>
as the coordinates that the Clojure CLI
understands.
If you plan to deploy to Clojars at any point, you'll need to be able to
build a JAR file and deploy it. You can learn to do all that manually
via tools.build
and a build.clj
file,
and using deps-deploy
once you've built the JAR file. It's going to be easier if you use a
tool to create a "fully-fleshed" library project for you, that adds all
of that configuration for you.
In either case, you're probably going to want to add tests and run them, so you'll either need to add those manually or, again, rely on a tool to set up a project with testing already built in.
For this guide, we're going to use
deps-new
which can create "batteries-included" library (and application) projects
for you.
Installing deps-new
If you already have
deps-new
installed as a Clojure "tool", asnew
, then you can skip this section.
The Clojure CLI allows you to install useful tools for your user account so you can use them in any project or even outside projects.
A useful tool to create new projects is deps-new
so we're going to
install the latest version of that:
clojure -Ttools install-latest :lib io.github.seancorfield/deps-new :as new
Once deps-new
is installed as new
, we can use clojure -Tnew
to create
new projects.
Create the Project with deps-new
Bearing in mind the comments about groups and accounts and usernames above, we're going to create our example project with the name:
io.github.clojure-example-library/my-cool-lib
Our project will live on GitHub as https://github.com/clojure-example-library/my-cool-lib and can be used directly from there using the full project name shown above. We will also deploy it to Clojars so that people can depend on it as a JAR file dependency.
Create your new library project. Names are usually hyphen-separated lowercase words:
clojure -Tnew lib :name io.github.clojure-example-library/my-cool-lib
cd my-cool-lib
Typical deps-new
usage is clojure -Tnew (lib or app) :name yourname/your-project
.
If you use just <yourname>
, the project coordinates will be assumed to be
net.clojars.<yourname>/<your-project>
, which is why we used io.github.
as
a prefix above.
A Note Regarding Project Naming
A line near the top of your build.clj
includes something like:
(def lib 'io.github.clojure-example-library/my-cool-lib)
This means that your project has an artifact ID
of my-cool-lib
, and a group ID of
io.github.clojure-example-library
.
The artifact ID is the name of your project. The group ID is used
to distinguish your my-cool-lib
from anyone else's my-cool-lib
.
It typically identifies the group or organization to which a project belongs.
The maintainers of Clojars
require that new libs be published using verified groups,
such as org.my-domain
or io.github.<account>
or net.clojars.<account>
.
Read more about groups at https://github.com/clojars/clojars-web/wiki/Groups.
Making the Project your own
Our cool library example project will add a dependency on flatland's "useful" library.
Open up our new deps.edn
file and make add our dependency
(org.flatland/useful {:mvn/version "0.11.6"}
) to the :deps
hash map.
In build.clj
, remove -SNAPSHOT
from version
(so it is just "0.1.0"
).
Licensing
If you created your project using deps-new
, it will have added a
LICENSE
file pertaining to the Eclipse Public License and an
explanation at the end of the README.md
that this is just a default.
You can choose to license your project however you want. The most common licenses for Clojure libraries (along with grossly oversimplified blurbs, by this author John Gabriele, for each) are:
- The Eclipse Public License (the default).
- The LGPL (focused most on code and additions always being free; includes language addressing s/w patent concerns). See the FSF's recommendations and their instructions for use.
- The MIT License (focused most on the user's freedom to do what they want with the code). The FSF calls this the "Expat" License.
Another option is the Apache Source License which is a commercial-friendly license (this author Sean Corfield tends to prefer ASL for projects where the default, EPL, is not used).
Whichever one you choose, update your README.md
to
reflect that choice and save the text of the license as a file named
LICENSE
in your project directory. Some licenses may encourage
you to add a portion of the license text to the header comment in your
source files.
Update the README
Aside from providing a good overview, rationale, and introduction at the top, you're encouraged to provide some usage examples as well. A link to the lib's (future) Clojars page (which we'll get to below) might also be appreciated. Add acknowledgements near the end, if appropriate. Adjust the copyright and license info at the bottom of the README as needed.
deps-new
provides you with a doc
directory and a starter doc/intro.md
file. If you find that you have more to say than will comfortably fit
into the README.md
, consider moving content into the doc
directory.
This guide mentions cljdoc.org
below as a great option for providing
online documentation, so feel free to expand your doc
directory
per Cljdoc for Library Authors
which explains how to provide structure and organization for your
documentation.
Other goodies you might include in your README.md
or doc/*.md
files:
tutorial, news, bugs, limitations, alternatives, troubleshooting,
configuration.
Note that you generally won't add hand-written API documentation into
your README.md
or other documentation, as there are tools for creating that
directly from your source (discussed later).
Create your project's local git repository
Before going much further, you probably want to get your project under
version control. Make sure you've got git
installed and configured to
know your name and email address (i.e., that at some point you've run
git config --global user.name "Your Name"
and
git config --global user.email "your-email@somewhere.org"
).
Then, in your project dir, run:
git init
git add .
git commit -m "The initial commit."
At any time after you've made changes and want to inspect them and commit them to the repository:
git diff
git add -p
git commit -m "The commit message."
Write Tests
In test/clojure_example_library/my_cool_lib_test.clj
, add tests as needed.
An example is provided in there to get you started.
Note: the example test created by
deps-new
fails deliberately in order for you to get accustomed to writing tests!
Write Code
Write code to make your tests pass.
Remember to add a note at the top of each file indicating copyright (and the license under which the code is distributed, if applicable).
For example:
;; copyright (c) 2023 -- Sean Corfield, all rights reserved.
Run Tests
In your project dir:
clojure -M:test -m cognitect.test-runner
or:
clojure -T:build test
Note: if you didn't use
deps-new
to create your library project, you'll want to add a:test
alias that adds Cognitect'stest-runner
to your project -- see Configuration in that project'sREADME
. The:test
aliasdeps-new
generates does not have:exec-fn
or:main-opts
because it expects you to run tests via thebuild.clj
file, although you can provide-m cognitect.test-runner
on the command-line to run tests directly via the CLI, as shown above.
Commit any remaining changes
Before continuing to the next step, make sure all tests pass and
you've committed all your changes. Check to see the status of your
repo at any time with git status
and view changes with git diff
.
Complete the GitHub Project Setup and Upload your Code
Once your remote repository has been created, follow the instructions on the
resulting page to "Push an existing repository from the command
line". You'll of course run the git
commands from your project
directory:
git remote add origin git@github.com:clojure-example-library/my-cool-lib.git
git push -u origin master
You can now access your online repo. For this tutorial, it's https://github.com/clojure-example-library/my-cool-lib.
Any changes you commit to your local repository can now be pushed to the remote one at GitHub:
# work work work
git add -p
git commit -m "commit message here"
git push
Making a Release on GitHub
At this point, prior to deploying your project to Clojars, it is common to make a release on GitHub describing this new version of your project.
You can update version
in build.clj
to reflect the new version you
want to publish, then add, commit, and push those changes.
On GitHub, navigate to the Releases section of your project and click the icon/button/link to create a new release.
For example, for
clojure-example-library/my-cool-lib
this would be https://github.com/clojure-example-library/my-cool-lib/releases/new.
Choose a tag that reflects the version you are about to release, e.g., v0.1.0
.
Enter the release name or number, e.g., 0.1.0
(it is typically the version
without the leading v
).
Enter a description, explaining the changes in this version, new features, bug fixes, etc, and create the release.
You should see the release name/number with a tag and a short SHA, e.g.,
0.1.0
... v0.1.0 ec74557
Upload to Clojars
See Publishing to Clojars above to get started. For more info on working with Clojars, see the Clojars wiki.
Run the tests one more time and build the JAR file:
clojure -T:build ci
Once your Clojars account is all set up, upload your library to Clojars like so:
clojure -T:build deploy
If you haven't already setup your environment variables, you can supply
them as part of that deploy
command -- see
deps-deploy
usage:
env CLOJARS_USERNAME=username CLOJARS_PASSWORD=clojars-token clojure -T:build deploy
You should now be able to see your lib's Clojars page: for example, https://clojars.org/net.clojars.clojure-example-library/my-cool-lib!
Note: to deploy that example library, the
lib
var insidebuild.clj
was changed tonet.clojars.clojure-example-library/my-cool-lib
which is a default verified group name, to avoid verifying via GitHub, sinceclojure-example-library
is a GitHub organization rather than an individual account. If you use your GitHub username to login to Clojars to verify your account, you can useio.github.<username>
.
If everything goes smoothly, all of the links on that Clojars page
should work and clicking this git tree
in the Pushed by section
should take you to GitHub, showing the source code at that version, e.g.,
https://github.com/clojure-example-library/my-cool-lib/tree/v0.1.0
In addition, if you clicked on the cljdoc
link on that Clojars page,
it will take you to a page where you can build the API docs for your
library. Once that build has completed, you should be able to visit
the generated documentation, e.g.,
https://cljdoc.org/d/net.clojars.clojure-example-library/my-cool-lib/0.1.0/doc/readme
See the next section for more details.
Generate API docs (optional)
For larger library projects, you may want to automatically generate API docs (from your docstrings). See cljdoc for the most common, automated documentation site used for Clojure libraries.
If you've followed all the steps above, that should go smoothly, but
if you get into trouble, the #cljdoc
channel on the Clojurians Slack
is a great place to get help.
Announce (optional)
You're welcome to announce the availability of your new library wherever you choose -- e.g., on Clojurians Slack, Twitter, Mastodon, the Clojure mailing list, r/Clojure (Reddit), ClojureVerse. Just make sure to follow the etiquette about announcements, wherever you post!
Make Updates to your library
Making updates to your lib follows the same pattern as described above:
# work test work test
# document the updates in CHANGELOG.md
# update the version in README.md
# update version string in build.clj
git add -p
git commit
git push
# make a new release on GitHub for this new version
# final testing and build the JAR file
clojure -T:build ci
# deploy to Clojars
clojure -T:build deploy
And optionally announce the release (Clojurians Slack prefers that you
use #releases
for small, frequent announcements, and only use
#announcements
for an initial release and then only about once
a month for major releases or "round-up" announcements of multiple releases).
Merging pull-requests
Note that if you receive a pull-request at github, you can easily merge those changes into your project (right there, via the web page describing the pull-request). Afterwards, update your local repo to grab those changes as well:
git pull
See Also
For more detailed documentation on various aspects of the procedures described here, see:
Contributors
John Gabriele jmg3000@gmail.com (original author) Sean Corfield sean@corfield.org (updated to use Clojure CLI)