Testing babashka scripts

For testing babashka scripts, you can write your own test runner from scratch, which is easy enough:

(ns my-test.runner
   [clojure.test :as t]))

(def test-namespaces '[my-test])

(defn -main [& _]
  (doseq [test-ns test-namespaces] (require test-ns))
  (let [{:keys [fail error]}
        (apply t/run-tests test-namespaces)]
    (when (and fail error (pos? (+ fail error)))
      (System/exit 1))))

and then run it with bb -m my-test.runner.

Not too bad, but still, it's work and boilerplate and even more so when you want to make a runner with CLI argument parsing to support running a subset of your tests. Since a year or so, you can use the cognitect-labs/test-runner with babashka. But this required a fork of tools namespace to be on your babashka classpath (using :deps in your bb.edn file).

No more! Since babashka version 1.0.166 you can use org.clojure/tools-namespace unmodified. The fix for this was to add the clojure.tools.reader namespace with the read function in babashka as a built-in. Babashka doesn't support the whole clojure.tools.reader namespace yet, but this is a good start to make it compatible with tools.namespace and now also the cognitect test runner.

To use it with babashka, add the following to your bb.edn.

 {test:bb {:extra-paths ["test"]
           :extra-deps {io.github.cognitect-labs/test-runner
                        {:git/tag "v0.5.1" :git/sha "dfb30dd"}}
           :task (exec 'cognitect.test-runner.api/test)
           :exec-args {:dirs ["test"]}
           :org.babashka/cli {:coerce {:nses [:symbol]
                                       :vars [:symbol]}}}}}

The exec function call, :exec-args and :org.babashka/cli coercion is there so we can call a Clojure function from the command line. See Babashka tasks meets babashka CLI for more details.

Now create a test file in test/my_test.clj:

(ns my-test
  (:require [clojure.test :refer [deftest is testing]]))

(deftest my-first-test
  (testing "equality works"
    (is (= 1 1))))

(deftest my-second-test
  (testing "equality still works"
    (is (= 2 2))))

And run the tests:

$ bb test:bb

Running tests in #{"test"}

Testing my-test

Ran 2 tests containing 2 assertions.
0 failures, 0 errors.

To run a single test you can specify the name of a var:

$ bb test:bb --vars my-test/my-second-test

Running tests in #{"test"}

Testing my-test

Ran 1 tests containing 1 assertions.
0 failures, 0 errors.

$ bb test:bb --vars my-test/my-first-test my-test/my-second-test

Running tests in #{"test"}

Testing my-test

Ran 2 tests containing 2 assertions.
0 failures, 0 errors.

Perhaps this will come in handy for Advent of Code 2022!

Discuss this post here.

Published: 2022-11-24

Tagged: clojure babashka

OSS updates of September - October 2022

In this post I'll give updates about open source I worked on during September and October 2022.


But first off, I'd like to thank all the sponsors and contributors that make this work possible! Top sponsors:

If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work via the following organizations. Thank you!



Native, fast starting Clojure interpreter for scripting.

Squint and Cherry

Squint and cherry are two flavors of the same CLJS compiler.

Squint is a CLJS syntax to JS compiler for use case where you want to write JS, but do it using CLJS syntax and tooling instead. Squint comes with a standard library that resembles CLJS but is built on bare JS ingredients. As such, squint comes with the usual JS caveats, but we can still have our parens and enjoy a slim bundle size.

Cherry comes with the CLJS standard library and is as such much closer to the normal ClojureScript, but the minimal amount of JS is a little bigger.

I've working on unifying the compiler code of cherry and squint into one code base, which is still in progress. I've also worked on REPL code.

I've also given a presentation on squint and cherry at the Dutch Clojure Days. The video will appear online in the future!


Static analyzer and linter for Clojure code that sparks joy

Two new releases with many fixes and improvements. Check the changelogs for details.

Among several new linters, there is a new :unused-value linter which detects unused values, which is particularly helpful for detecting unused transient operation results which can lead to bugs.

Clj-kondo configs

Library configurations as dependencies for clj-kondo.

The idea of this repository is that you can add configuration for libraries as a dependency to your deps.edn or project.clj. If you invoke the right command or if you are using Clojure LSP, then the configuration is written into your .clj-kondo directory and clj-kondo will understand custom constructs in your library. Normally you can provide these configurations as part of your library, but this is not always an option, so the remaining configurations can live over here.


Configurable Clojure interpreter suitable for scripting and Clojure DSLs.

This is the workhorse that powers babashka, nbb, Joyride, and many other projects.

Several bugfixes and enhancements were made in the last two months in two new releases. Performance of let bindings are now up to 8x faster, as already mentioned in the babashka entry of this post.

See changelogs for more details.


Scripting in Clojure on Node.js using SCI

The first 1.0 version was released.

Many small bugfixes and improvements in the last two months. See changelogs.


In the past two month, I became one of the maintainers, together with @lread, of clj-yaml. Clj-yaml is a built-in library of babashka.


A faithful port of the clojure CLI bash script to Clojure

A lot of Windows improvements in the last two months. Deps.clj is now also available as part of an MSI installer that installs deps.exe as clj.exe. This installer might form the basis for an official Clojure MSI installer.


Upload artifacts to Github releases idempotently

This tool has been in use within babashka, clj-kondo and other projects to automate uploading release artifacts from various CI systems to Github releases, idempotently. It is now open source and ready to be used by others.


CLI to transform between JSON, EDN, YAML and Transit, powered with a minimal query language.

The latest release adds support for YAML (by using clj-yaml), thanks to @qdzo.

Babashka CLI

Turn Clojure functions into CLIs!

See changelogs.


Clojure library for shelling out / spawning subprocesses

Minor updates and fixes. See changelogs.


Quickdoc is a tool to generate documentation from namespace/var analysis done by clj-kondo. It's fast and spits out an API.md file in the root of your project, so you can immediately view it on Github. It has undergone significant improvements in the last two months. I'm using quickdoc myself in several projects. In the last two months, there have been improvements in the table of contents linking and linking to source code.


File system utility library for Clojure.

Minor updates and fixes. See changelogs.


Carve out the essentials of your Clojure app by removing unused vars

Version 0.2.0 was released, after a long hiatus, with an updated version of clj-kondo and some minor fixes.


Grep Clojure code using clojure.spec regexes.

I use this tool to analyze code patterns to make informed choices for e.g. SCI and clj-kondo. E.g. see this example that shows how many let bindings are typically used. See the example in action here.

A new version was released with minor fixes.


Utility lib on top of rewrite-clj with common operations to update EDN while preserving whitespace and comments.

Minor fixes and enhancements. Repeated usage of assoc is now a safe operation. Thanks to @lread for the improvements.


Lein to deps.edn converter

This new little tool can convert a project.edn file to a deps.edn file. It even supports Java compilation and evaluation of code within project.clj.


A CLI to add common aliases and features to deps.edn-based projects.

Neil now comes with a dep upgrade command, thanks to @teodorlu and @russmatney, together with other improvements.


Finally, after 4 years, a new release of respeced, a testing library for clojure.spec fdefs.


Light-weight static blog engine for Clojure and babashka

Small improvements. See changelog. The blog you're currently reading is made with quickblog.


A collection of ready to be used SCI configs

Added a doseq macro in promesa which also is available via this configuration. Sci.configs is used in Clerk, nbb, Joyride and other SCI-based CLJS projects.

Discuss this post here.

Published: 2022-10-31

Tagged: clojure oss updates

Deploying a Clojure project with neil and tools.build

In a previous blog post, I described how you can kick off a Clojure project with neil.

Today I want to show you how easy it is how to deploy a Clojure project to Clojars with neil.

Assuming you already have a deps.edn, but you don't yet have a build.clj, you can run:

$ neil add build

This creates a tools.build build.clj file with functions you typically need for building and deploying a Clojure project.

The build.clj looks for the project name and version in your deps.edn under [:aliases :neil :project].

You can set the project name and version like this:

{:deps {}
 :paths ["resources"]
 {:neil {:project {:name io.github.clj-kondo/config-rum-rum
                   :version "1.0.0"}}
  :build ;; added by neil
  {:deps {io.github.clojure/tools.build {:git/tag "v0.8.3" :git/sha "0d20256"}
          slipset/deps-deploy {:mvn/version "0.2.0"}}
   :ns-default build}}}

Now all you have to do to deploy your project is run clojure -T:build deploy. This runs the deploy function in build.clj which uses deps-deploy.

Whenever you want to bump your patch version, you can run:

$ neil version patch

or set the version manually using:

$ neil version set 1.0.1

and then deploy again.

The neil version command is similar to NPM's version command.

For a full project that uses this setup, check out this one that I just created today in a couple of keystrokes.

Happy deploying!

Discuss this post here.

Published: 2022-10-22

Tagged: clojure neil