NoMake is a framework that runs various checks against Emacs Lisp packages. It is an alternative to Cask, makem.sh, melpazoid, emake, makel, etc., but Nix-oriented and based on twist. It is yet a new iteration of elinter (a.k.a. emacs-package-checker, melpa-check, etc.).
It is primarily developed for emacs-twist org and my other Emacs Lisp packages.
NoMake heavily depends on Nix flakes, and you will need an understanding of flakes to use it.
The following is a list of checks I plan to support:
- [X] package-lint
- [X] byte-compile with multiple Emacs versions
- [X] check-declare
- [ ] checkdoc with custom settings
- [ ] ELSA with custom rules
I wish to support the following checks as well, but they are not available as an Emacs Lisp library at the time of writing:
- [ ] Experimental checks of melpazoid
- [ ] Indentation
NoMake requires Nix with flakes enabled.
Because nomake depends on nix-emacs-ci even locally, it is recommended to enable its binary cache:
cachix use emacs-ci
These steps are necessary for any nomake project.
To add nomake to an existing Emacs Lisp project, you can use nix flake init
command:
nix flake init -t github:emacs-twist/nomake
If your package is already on MELPA, you can skip this subsubsection.
Whether you plan on releasing your package to MELPA or not, you will need to put the recipe for your package in a branch.
Fork the repository of MELPA, create a new branch from master, add a recipe (see the format), and push it to GitHub (or any code hosting service).
Edit flake.nix to point the melpa
to your branch:
{
description = "...";
inputs = {
melpa = {
url = "github:OWNER/melpa/BRANCH";
flake = false;
};
# More inputs
};
}
In the outputs
section of flake.nix, set localPackages
to a list of packages in the repository:
nomake.lib.mkFlake {
src = ./.;
localPackages = [
# The name of your package
"nice-mode"
];
}
You may sometimes want to explicitly install a particular package.
This applies if you depend on packages such as org
and project
.
They are shipped with Emacs but also actively developed, so older versions of Emacs ship outdated versions of packages.
In this situation, you should list them in extraPackages
:
nomake.lib.mkFlake {
src = ./.;
localPackages = [
"nice-mode"
];
extraPackages = [
# Explicitly install org packages rather than depending on the built-in
# version
"org"
];
}
This subsection describes how to use nomake locally during development.
First generate lock files for your package dependencies:
nix run .#lock --impure
The dependencies are inspected from the library header of your package. You should run this command every time you add a new dependency.
For byte-compiling, a snapshot version of nix-emacs-ci is used. The following command runs all checks (currently package-lint and byte-compiling):
nix run .#nomake -- PACKAGE
PACKAGE
should be the name of the package.
To run tests, you have to define a script. Scripts are a feature that lets you run a shell script in a development environment. In scripts, you can run Emacs with package(s) under test. It is also possible to add extra packages for testing.
To define a script, edit flake.nix and add scripts
attribute:
nomake.lib.mkFlake {
src = ./.;
localPackages = [
"nice-mode"
];
scripts = {
test = {
description = "Run buttercup tests";
compile = true;
extraPackages = [ "buttercup" ];
runtimeInputsFromPkgs = pkgs: [
pkgs.hello
];
text = ''
emacs -batch -l buttercup -L . -f buttercup-run-discover
'';
};
};
};
In the example shown above, test
script is defined, and buttercup is added for running the tests.
compile = true;
means that the user package is byte-compiled when the script is run.
Tests are discovered from the working directory.
To run the script, you can use nix run
:
nix run .#test
The application name (test
in this case) is the same as the name of the script defined in the flake.
By adding runtimeInputsFromPkgs
, you can specify executables which will become available in the runtime environment of the script.
Note that you can specify extraPackages
either as a sibling of localPackages
or inside a script block.
Wherever you define extra packages, it has the same effect.
If you define multiple extraPackages
attributes in different places, they are merged.
It is possible to run a script with different versions of Emacs. You can pick a version available from nix-emacs-ci, but only required executables are downloaded from the binary cache. The minimum Emacs version is determined from the library header of your local package.
To check a list of Emacs versions for your package, run the following command (test
should be the name of your script):
nix eval .#packages.x86_64-linux.test.matrix --apply builtins.attrNames
To run the tests with Emacs 26.2, run the following command:
nix run .#test.matrix.emacs-26-2
This subsection provides an instruction for setting up CI for Emacs Lisp projects. At present, only GitHub Actions is supported.
While it is possible to run Nix for linting your package on CI, it is slow when binary cache is unavailable.
Instead, you can use an experimental feature of nomake to generate GitHub workflows.
The generated workflows uses setup-emacs and installs latest packages using package.el
.
This is a fairly standard setup in the Emacs community.
It does not always produce the same result as Nix, and it also does not support multi-package repositories well, but it is even better for submission to MELPA.
To generate workflows, run the following command:
nix build .#github-workflows
The workflow files are available in result
directory.
To copy the files to the designated directory, you can use the following command:
install -m 644 result/*.* .github/workflows
See comparisons by the author of makem.
At present, nomake doesn’t have as many features as makem, nor is it mature. The goal of this project is to provide a framework for consistent quality control over Emacs Lisp library code. Consistency does not always mean the most strict or supporting as many as checks as possible.
Compared to the previous iteration, it avoids impure Nix code for maintainability.
Some of the Emacs Lisp code in this repository are based on the following projects:
- makem.sh by Adam Porter (a.k.a. alphapapa)
- Linting code for package-lint by Steve Purcell
Because this repository contains some linting code from GPL 3.0-licensed repositories, the entire repository is licensed under GPL v3. You will have to license your projects under GPL too.