= Hacking on CIDER

This section explains the process of working with CIDER's codebase (e.g. to fix
a bug or implement some new feature). It outlines the recommended workflows when
working on the Emacs Lisp side (CIDER) and the Clojure side (`cider-nrepl`).

== Hacking on CIDER (Elisp)

=== Obtaining the source code

People typically install CIDER via `package.el`. While this gives you access to the
source code (as it's part of the package), it's always a much better idea to
simply clone the code from GitHub and use it. In general - avoid editing the
code of an installed package.

Alternatively you can simply load CIDER in your Emacs straight from its source
repo (you'll have to manually install all the packages CIDER depends on
in advance).

CIDER uses https://github.com/doublep/eldev[Eldev] for development, so
you should install the tool first.

The easiest and "purest" way to run CIDER is to execute:

[source,shell]
----
eldev emacs
----

This will start a separate Emacs process with CIDER and its
dependencies available, but _without_ your normal packages installed.
However, you can use `Eldev-local` to add some packages with
`(eldev-add-extra-dependencies 'emacs ...)` forms.  See Eldev
documentation for details.

Alternatively, if you want to load CIDER from source code in the Emacs
you use for editing:

. Generate autoloads file (that's done automatically when installing
via `package.el` but you'll have to do it manually in this case):
+
[source,shell]
----
eldev build :autoloads
----

. Add to your `.emacs`:
+
[source,lisp]
----
;; load CIDER from its source code
(add-to-list 'load-path "~/projects/cider")
(load "cider-autoloads" t t)
----

=== Changing the code

It's perfectly fine to load CIDER from `package.el` and then to start making
experiments by changing existing code and adding new code.

A very good workflow is to just open the source code you've cloned and start
evaluating the code you've altered/added with commands like `C-M-x`,
`eval-buffer` and so on.

Once you've evaluated the new code, you can invoke some interactive command that
uses it internally or open an Emacs Lisp REPL and experiment with it there. You
can open an Emacs Lisp REPL with `M-x ielm`.

You can also quickly evaluate some Emacs Lisp code in the minibuffer with `M-:`.

=== Testing the code

The code you've written should ideally be covered by specs. We use
the https://github.com/jorgenschaefer/emacs-buttercup[buttercup] library for
CIDER's specs. If you're familiar with `Jasmine` or `RSpec` you'll feel right at
home.

You can run the specs you authored/changed straight from Emacs. Consult
the
https://github.com/jorgenschaefer/emacs-buttercup/blob/master/docs/running-tests.md[buttercup documentation] for
all the details.

==== Running the tests in batch mode

If you prefer running all tests outside Emacs that's also an option.

There are two test types, `main` (unit tests) and `integration`. By
default only main tests are run.

Run all unit tests with:

 $ eldev[.bat] test
 # Or:
 $ make test-unit

Run integration tests with:

 $ eldev[.bat] test --test-type integration
 # Or:
 $ make test-integration

or all tests with:

 $ eldev[.bat] test --test-type all
 # Or:
 $ make test-all

NOTE: Tests may not run correctly inside Emacs' `shell-mode` buffers. Running
them in a terminal is recommended.

You can also check for compliance with a variety of coding standards in batch mode (including docstrings):

 $ eldev lint
 # Or:
 $ make lint

To check for byte-compilation warnings you can just compile the project with Eldev:

 $ eldev -dtT compile --warnings-as-errors
 # Or:
 # make compile

==== Running the tests in CircleCI

If you prefer to see the full CircleCI CI test suite run successfully, the easiest
way to achieve that is to create your own personal account on
https://circleci.com. Fork CIDER on GitHub, and then add your fork on CircleCI to
start building. Every time you push code to a branch, CircleCI will build it.

Subsequent pushes to your fork will generate a CircleCI build you can monitor
for success or failure.

==== Simulating the Circle CI tests locally in Docker

If you prefer not to wait for CircleCI all the time, or if you need to debug
something that fails in CircleCI but does not fail for you on your own machine,
then you can also run the CircleCI tests locally with the CircleCI CLI (that's
a mouthful!).

To do this, first https://circleci.com/docs/2.0/local-cli/#installation[install]
the CircleCI CLI, and https://docs.docker.com/install/[Docker].

Currently the CircleCI CLI https://github.com/CircleCI-Public/circleci-cli/issues/79[doesn't support local builds with version 2.1]
of the CircleCI config, so for now we need to convert it to the 2.0 format.
Make sure not to commit these changes to the `config.yml` file.

[source,shell]
----
$ circleci config process .circleci/config.yml > .circleci/config.yml.tmp && \
    mv .circleci/config.yml.tmp .circleci/config.yml
----

Now, we're finally ready to
https://circleci.com/docs/2.0/local-cli/#run-a-job-in-a-container-on-your-machine[run a CircleCI container on our machine].
Run `circleci local execute --job=<job>` where `<job>` is one of those listed
in `.circleci/config.yml`, e.g. `test-emacs-26`.

[source,shell]
----
$ circleci local execute --job=test-emacs-26
Docker image digest: sha256:65b2102646d5658f892e0ad8253b7912c676126c857c87c8c12460f0aa4f5aa1
====>> Spin up Environment
Build-agent version 1.0.8563-43047892 (2019-03-06T15:11:54+0000)
Starting container silex/emacs:26-dev
  image cache not found on this host, downloading silex/emacs:26-dev
26-dev: Pulling from silex/emacs
6cf436f81810: Already exists
987088a85b96: Already exists
e58f362a948a: Waiting
...
====>> make elpa
  #!/bin/bash -eo pipefail
make elpa
Compute dependencies
cask install
Loading package information... done
Package operations: 10 installs, 0 removals
...
Indenting region...
Indenting region...done
* Run indent-character
* Run trailing-whitespace
** ELISP-LINT: cider-overlays.el OK
Success!
----

This may take a while to download the CircleCI build agent and the build containers
the first time you run the tests locally.

=== MS-Windows compatibility

In general, CIDER code should work as well on Windows as it does on
Unix.

There are a few points to be aware of when contributing code or
writing tests.

. Absolute paths. It is a common practice to use dummy absolute paths,
such as `/tmp/a-dir` or `/docker/src, in tests,` as test inputs. These
are not valid absolute paths on Windows though, since they are missing
the initial drive letter (e.g.`c:/tmp/a-dir`), but we can wrap them
around with `expand-file-name` to make them so e.g. in tests
+
[source,emacs-lisp]
----
(let ((a-dir (expand-file-name "/tmp/a-dir"))
      (docker-src (expand-file-name "/docker/src")))
  ;; ...
  )
----

. Command-line arguments. When calling external programs, it might be
necessary to quote some long command line arguments, though quoting
rules are different on Windows (shells) than they are on Unix.  Use
`shell-quote-argument` to achieve the desired compatibility across the
different architectures.

== Hacking on cider-nrepl (Clojure)

=== Obtaining the code

Just clone it from GitHub.

=== Changing the code

Just do `cider-jack-in` within the `cider-nrepl` project and start hacking as
you would on any other Clojure project.  The only thing to keep in mind is that
you'll have to restart CIDER when you add new middleware.

The jacked-in project's definitions will take precedence over the ones you have
from a binary `cider-nrepl` installation. This means it's pretty easy to get
immediate feedback for the changes you've made.

=== Testing the code

The code you've written should ideally be covered by tests. We use the
`clojure.test` library for ``cider-nrepl``'s tests.

You can run the tests you authored/changed straight from Emacs. Consult the
xref:testing/running_tests.adoc[CIDER documentation] for all the details.

==== Running the tests in batch mode

You can also run the tests in an external shell. Running `lein test` won't run
pretty much anything, though. (perhaps we should change this?) To run the
Clojure and ClojureScript tests you should specify some profile like this:

 $ lein with-profile +1.8,+test-clj test
 $ lein with-profile +1.8,+test-cljs test

This will run all Clojure and ClojureScript tests against version 1.8 of both
languages.
