# `alidistlint` - code linter for [alidist][] recipes
`alidistlint` runs [shellcheck][] on the scripts in [alidist][] recipes and [yamllint][] on their YAML headers, in addition to its own validation and checks on the YAML header.
## Usage
Run `alidistlint -h` to get more information about its arguments.
```
usage: alidistlint [-h] [-S] [-Y] [-H] [-f FORMAT] RECIPE [RECIPE ...]
```
You can disable individual checkers using `-S`/`--no-shellcheck`, `-Y`/`--no-yamllint` and `-H`/`--no-headerlint` (internal YAML header linting).
By default, all checkers are run.
Optionally, select the output format of errors using `-f`/`--format`.
Finally, pass one or multiple files to be checked to `alidistlint`. You can use `-` for the standard input here.
Errors and warnings will be printed to standard output in the format you selected.
If any messages with "error" severity were produced, `alidistlint` exits with a non-zero exit code.
## Shellcheck validation
The main build recipe (after the `---` line) is passed to `shellcheck`.
Currently, toplevel keys ending in `_recipe` or `_check` (such as `incremental_recipe`) are also checked using `shellcheck`.
This does not work for such keys specified in `overrides` yet.
There is a known issue with the checking of the above keys: if they do not start on a new line (using e.g. `key: |`), the reported line numbers for shellcheck errors will be off by one.
## Internal YAML header validation
The following error codes are produced by the internal linter (which can be switched off using `-H`/`--no-headerlint`).
There is currently no way to disable individual checks.
- `ali:empty`: The YAML header was not found.
It must be terminated by a `\n`-terminated line containing nothing but three dashes (`---`).
- `ali:parse`: The YAML header could not be parsed as YAML. This is produced when PyYAML's `yaml.load` raises an error.
- `ali:toplevel-nondict`: The YAML header was not parsed as a dictionary. `key: value` pairs should be provided.
- `ali:schema`: The YAML header did not conform to its schema. See the error message for more details.
- `ali:key-order`: The `package`, `version` and `tag` keys were not found in the correct order.
These keys should be the first in the file, in the above order (if present).
Additionally, the `requires` key must come before `build_requires`.
## GitHub Actions integration
You can run `alidistlint` as part of a GitHub Action using `-f github`. In that case, `alidistlint` will annotate files with the errors found in them.
`alidistlint` will exit with a non-zero exit code if any errors were found, which will cause the Action to fail.
## Vim integration
Put the following in your `.vimrc`:
```vim
autocmd BufNewFile,BufRead *alidist/*.sh set makeprg=alidistlint\ -f\ gcc\ % errorformat=%f:%l:%c:\ %t%*[a-z]:\ %m
" If you want to automatically re-run the linter on every save:
autocmd BufWritePost *alidist/*.sh make
```
Then you can use `:make` to run the linter, `:cl` to see the error list, and navigate from one error to another using `:cp` (previous), `:cc` (current) and `:cn` (next).
## Emacs integration
Here is a simple Flycheck checker using `alidistlint`.
You can set this to check alidist recipes.
```elisp
(require 'flycheck)
(flycheck-def-executable-var alidist "alidistlint")
(flycheck-define-checker alidist
"A syntax checker and linter for alidist recipes."
;; `flycheck-alidist-executable' automatically overrides the car of the
;; :command list if set and non-nil.
:command ("alidistlint" "--format=gcc" source)
:error-patterns
((error line-start (file-name) ":" line ":" column ": error: " (message)
" [" (id (minimal-match (one-or-more not-newline))) "]" line-end)
(warning line-start (file-name) ":" line ":" column ": warning: " (message)
" [" (id (minimal-match (one-or-more not-newline))) "]" line-end)
(info line-start (file-name) ":" line ":" column ": note: " (message)
" [" (id (minimal-match (one-or-more not-newline))) "]" line-end)))
(add-to-list 'flycheck-checkers 'alidist)
```
[alidist]: https://github.com/alisw/alidist
[shellcheck]: https://www.shellcheck.net/
[yamllint]: https://yamllint.readthedocs.io/