{"id":13861604,"url":"https://github.com/akirak/elinter","last_synced_at":"2025-07-14T09:32:38.501Z","repository":{"id":42566170,"uuid":"195633538","full_name":"akirak/elinter","owner":"akirak","description":"Nix-based CI and local testing framework for Emacs Lisp projects","archived":true,"fork":false,"pushed_at":"2022-03-31T18:05:54.000Z","size":912,"stargazers_count":18,"open_issues_count":9,"forks_count":2,"subscribers_count":4,"default_branch":"v4","last_synced_at":"2024-08-05T06:03:27.426Z","etag":null,"topics":["emacs-lisp","linting","nix","testing"],"latest_commit_sha":null,"homepage":"","language":"Emacs Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/akirak.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-07-07T09:33:31.000Z","updated_at":"2023-11-27T10:49:33.000Z","dependencies_parsed_at":"2022-08-23T21:30:37.667Z","dependency_job_id":null,"html_url":"https://github.com/akirak/elinter","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akirak%2Felinter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akirak%2Felinter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akirak%2Felinter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akirak%2Felinter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/akirak","download_url":"https://codeload.github.com/akirak/elinter/tar.gz/refs/heads/v4","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225968844,"owners_count":17553147,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["emacs-lisp","linting","nix","testing"],"created_at":"2024-08-05T06:01:26.040Z","updated_at":"2024-11-22T21:30:53.100Z","avatar_url":"https://github.com/akirak.png","language":"Emacs Lisp","funding_links":[],"categories":["Emacs Lisp"],"sub_categories":[],"readme":"* elinter\n*This project is soon to be replaced by [[https://github.com/emacs-twist/nomake][nomake]]. I won't develop elinter any more. Please consider nomake if you are looking for an alternative.*\n\nThis is a complete rewrite of my Emacs Lisp package checker, formerly called =emacs-package-checker= or =melpa-check=. It is still currently at an alpha stage.\n\n#+begin_html\n\u003ca href=\"https://github.com/akirak/elinter/actions?query=workflow%3A%22Tests%22\"\u003e\n\u003cimg alt=\"Build Status\" src=\"https://github.com/akirak/elinter/workflows/Tests/badge.svg\" /\u003e\n\u003c/a\u003e\n\n\u003ca href=\"https://github.com/akirak/elinter-demo/actions?query=workflow%3A%22Demo%22\"\u003e\n\u003cimg alt=\"Build Status\" src=\"https://github.com/akirak/elinter-demo/workflows/Demo/badge.svg\" /\u003e\n\u003c/a\u003e\n#+end_html\n** Table of contents\n:PROPERTIES:\n:TOC:      siblings\n:END:\n-  [[#project-goals][Project goals]]\n-  [[#planned-features-72][Planned features [72%]​]]\n-  [[#prerequisites][Prerequisites]]\n-  [[#installation][Installation]]\n-  [[#usage][Usage]]\n  -  [[#use-case-1-local-source--in-repository-recipes][Use case #1: Local source + in-repository recipes]]\n  -  [[#use-case-2-local-recipes--remote-sources][Use case #2: Local recipes + remote sources]]\n  -  [[#use-case-3-github-workflow-for-package-repositories][Use case #3: GitHub workflow for package repositories]]\n  -  [[#use-case-4-github-workflow-for-batch-linting-your-packages-on-melpa][Use case #4: GitHub workflow for batch-linting your packages on MELPA]]\n  -  [[#use-case-5-git-pre-commit-hook][Use case #5: Git pre-commit hook]]\n-  [[#technical-details][Technical details]]\n  -  [[#elinter-command][elinter command]]\n  -  [[#emacs-version-syntax][Emacs version syntax]]\n  -  [[#updating-packages][Updating packages]]\n  -  [[#sandboxing][Sandboxing]]\n-  [[#credits-inspiration-sources-and-alternatives][Credits, inspiration sources, and alternatives]]\n\n** Project goals\nThis project aims at the following goals:\n\n- Support both local use and CI\n- Comprehensive linting using various backends (trying to produce the same result as [[https://github.com/riscy/melpazoid/][melpazoid]], which is created and used by the official reviewer on [[https://melpa.org/#/][MELPA]])\n- Use [[https://nixos.org/][Nix]] to support dependencies that involve specific build procedures and/or native dependencies, e.g. =emacsql-sqlite=, =vterm=, etc.\n- Support projects containing multiple packages in the same repository\n- Allow ease of setup for new projects and ease of migration for existing projects, e.g. from Cask\n- Minimal configuration and minimal maintenance\n** Planned features [72%]\nThe following is a list of features that should be supported by this project.\nMaybe I'll announce this project officially when the progress reaches around 80%.\n\nLinting (the list mostly extracted from [[https://github.com/alphapapa/makem.sh][makem.sh]] + inspiration from [[https://github.com/gonewest818/elisp-lint][elisp-lint]]):\n\n- [X] checkdoc\n- [X] [[https://github.com/purcell/package-lint/][package-lint]]\n- [X] check-declare\n- [X] [[https://github.com/riscy/melpazoid/][melpazoid]] (sharp quotes and other experimental checks)\n- [ ] [[https://github.com/emacs-elsa/Elsa][ELSA]]\n- [ ] indentation\n- [ ] regular expressions\n- [ ] whitespace\n\nBuilding packages:\n\n- [X] Byte-compile\n- [X] Loadability testing\n- [X] Produce a package with =*-autoloads.el= file\n\nTesting:\n\n- [X] [[https://github.com/jorgenschaefer/emacs-buttercup/][buttercup]]\n- [X] [[https://github.com/jorgenschaefer/emacs-buttercup/][ert-runner]]\n- [X] ert with given test files\n- [X] Run any command in an environment with packages under test\n\nTarget project types:\n\n- [X] Multi-file packages\n- [X] Multi-package repositories\n- [ ] Source files in subdirectories\n- [ ] Native dependencies\n\nSources:\n\n- [X] Local repository\n- [X] Remote source repositories\n\nConfiguration:\n\n- [X] Allow specifying an Emacs version available in [[https://github.com/purcell/nix-emacs-ci/][nix-emacs-ci]]\n- [X] Determine Emacs versions based on the library headers of individual packages\n- [X] Read development dependencies (used for testing) from =Cask= file\n- [ ] Allow defining custom Nix package derivations\n- [X] Allow updating Nix dependencies (including [[https://github.com/nix-community/emacs-overlay/][emacs-overlay]]) locally\n- [ ] Add support for better integration with Nix flakes\n\nIntegration:\n\n- [X] CLI for local use\n- [X] Git pre-commit hook (run static checks only on modified files)\n- [X] GitHub Actions\n- [ ] GitHub workflow with the latest set of packages (probably as a Docker image)\n\nReporting:\n\n- [X] Colorizing statuses\n\nGitHub Actions:\n\n- [X] Groups on GitHub Actions\n- [X] Produce annotations that point to concrete error locations on GitHub Actions\n- [ ] Check if recipes are up to date on MELPA\n- [X] Fine-grained settings of linting options\n** Prerequisites\n=elinter= runs on UNIX-like operating systems that can run [[https://nixos.org/][Nix]] (currently Linux and macOS).\n** Installation\n=elinter= depends on Nix, so you have to install Nix first:\n\n#+begin_src sh\nbash \u003c(curl -L https://nixos.org/nix/install)\n#+end_src\n\n=elinter= can be installed using Nix:\n\n#+begin_src sh\nnix-env -if https://github.com/akirak/elinter/archive/v4.tar.gz\n#+end_src\n\nAlternatively, you can clone this repository and run\n\n#+begin_src sh\nnix-env -if .\n#+end_src\n\nOptionally, it is recommended to install [[https://github.com/cachix/cachix][cachix]] and enable cached Emacs binaries:\n\n#+begin_src sh\ncachix use emacs-ci\n#+end_src\n\nOptionally, you can use [[https://github.com/xzfc/cached-nix-shell][cached-nix-shell]] for improving =nix-shell= startup time.\nInstall the program in =PATH=, and =elinter= will automatically detect it.\n** Usage\n*** Use case #1: Local source + in-repository recipes\nFirst create package recipes in =.recipes= directory.\nThe recipe format is [[https://github.com/melpa/melpa/#recipe-format][the same as you would create for MELPA]], and each file should define exactly one package.\n\nYou can use =elinter.el=, which is included in this project, to copy existing recipes from your local copy of MELPA.\nFirst set =elinter-recipes-dir= to the =recipes= directory inside MELPA, and then use =elinter= interactive function.\nIt scans source files in the repository, import package recipes, and run lint on source files.\n\nThe below describes command line usage but also applies to =elinter= command inside Emacs.\n\nWithout arguments, it lints and compiles source files in the repository:\n\n#+begin_src sh\nelinter\n#+end_src\n\nTo enable experimental checks by [[https://github.com/riscy/melpazoid/][melpazoid]] which you would receive on MELPA PRs, add =--experimental= flag:\n\n#+begin_src sh\nelinter --experimental\n#+end_src\n\nWith =--buttercup= or =--ert-runner= flag, it also runs tests:\n\n#+begin_src sh\nelinter --buttercup\n#+end_src\n\nTo only lint packages and prevent from byte-compiling, add =-l= flag:\n\n#+begin_src sh\nelinter -l\n#+end_src\n\nTo only byte-compile source files, add =-b= flag:\n\n#+begin_src sh\nelinter -b\n#+end_src\n\nTo only run tests, run it with =-t= along with the =--buttercup=, =--ert-runner=, etc.:\n\n#+begin_src sh\nelinter -t --buttercup\n#+end_src\n\nSee [[https://github.com/akirak/elinter-demo/blob/master/.github/workflows/test.yml][elinter-demo]] and [[https://github.com/akirak/elinter-demo/actions?query=workflow%3ADemo][its status page]] for concrete examples.\n*** Use case #2: Local recipes + remote sources\nThis is like the use case 1, but it clones the remote repository specified in the recipe rather than work on source files in the working directory.\n\n=elinter= command accepts recipe files as arguments. When =-r= flag is given, it clones remote Git repositories according to the recipes.\nThis can be easily integrated into the MELPA PR workflow:\n\n#+begin_src sh\ncd ~/your-melpa-fork\nelinter -r recipes/your-package --experimental\n#+end_src\n\nThe same flags as #1 applies.\n*** Use case #3: GitHub workflow for package repositories\nThis repository also provides a GitHub action for checking individual packages on GitHub.\n\nThe following is an example workflow. Create a file in =.github/workflows=. Here is [[https://github.com/akirak/elinter/actions?query=workflow%3A%22Action+CI%22][an example output]].\n\n#+begin_src yaml\n  name: CI\n  on:\n    push:\n  jobs:\n    ci:\n      runs-on: ubuntu-latest\n      steps:\n      - uses: actions/checkout@v2\n      # Nix is required\n      - uses: cachix/install-nix-action@v10\n      # Install elinter and run lint and byte-compile\n      - uses: akirak/elinter@v4\n      # Optional step for running tests\n      - name: 'Run buttercup tests with the latest release of Emacs'\n        run: elinter -t --buttercup -e latest\n#+end_src\n*** Use case #4: GitHub workflow for batch-linting your packages on MELPA\nSince =elinter= command can take recipe files as arguments and fetch remote repositories, it is possible to add a linting workflow to your copy of [[https://github.com/melpa/melpa][MELPA]].\n\nHere is [[https://github.com/akirak/melpa/blob/internal/.github/workflows/akirak.yml][an example workflow definition]] and [[https://github.com/akirak/melpa/actions?query=workflow%3ACI][output]].\n*** Use case #5: Git pre-commit hook\nThis repository also provides a script that can be integrated into Git =pre-commit= hook.\n\nIf you run =elinter= with =-g= argument at a repository root, it installs a =pre-commit= hook that\nperforms static checks based on the recipe(s).\n\nIt uses [[https://pre-commit.com/][pre-commit]], and =.pre-commit-config.yaml= is created at the repository root.\n\nNote that byte-compilation is not performed by the hook.\n\nAlternatively, you can use [[cachix/pre-commit-hooks.nix][cachix/pre-commit-hooks.nix]] to configure the hook for multiple languages in Nix. The following is an example:\n\n#+begin_src nix\n  with builtins;\n  with (import \u003cnixpkgs\u003e {});\n  with (import (import ./nix/sources.nix).gitignore { });\n  let\n    pre-commit-hooks = import (import ./nix/sources.nix).\"pre-commit-hooks.nix\";\n\n    elinter = import (fetchTarball \"https://github.com/akirak/elinter/archive/v4.tar.gz\") { };\n\n    pre-commit-check = pre-commit-hooks.run {\n      src = gitignoreSource ../.;\n      excludes = [ \"^nix/sources\\.nix$\" ];\n      hooks = {\n        shellcheck.enable = true;\n        nix-linter.enable = true;\n        nixpkgs-fmt.enable = true;\n        elinter = {\n          enable = true;\n          name = \"elinter\";\n          description = \"Lint Emacs Lisp files\";\n          entry = \"${elinter.file-linter}/bin/elinter-lint-files\";\n          files = \"\\\\.el$\";\n        };\n      };\n    };\n  in\n  mkShell {\n    shellHook = pre-commit-check.shellHook;\n  }\n#+end_src\n\nThat is, =file-linter= Nix attribute of this repository provides =elinter-lint-files= executable\nwhich performs static checks on given files, so you can integrate it using any Git hooks manager:\n\n#+begin_src sh\n# install the script\nnix-env -if . -A file-linter\n# check source files in your repository\nelinter-lint-files hello.el hello-utils.el\n#+end_src\n** Technical details\n*** elinter command\nThe default Nix derivation provides =elinter= executable.\nIt takes recipe files as command line arguments.\n\nIt can also take package names and it refers to source files linked from the sandbox (described below).\n\nIf no recipe file or package name is given as an argument, it looks for ones in =.recipes= directory in the working directory.\n*** Emacs version syntax\n=elinter= command supports =-e= option that takes an Emacs version, e.g. =26.3= for Emacs 26.3 and =snapshot= for the latest snapshot. You can use any single version available in nix-emacs-ci.\n\nIt also supports the following abstract version specs:\n\n- =min=, the minimum version specified in the library header of each package\n- =latest=, the latest stable version\n- =all=, all versions since the minimum version including the snapshot, in descending order\n*** Updating packages\nTo update dependencies, e.g. =emacs-overlay= for Emacs packages and =nix-emacs-ci= for Emacs itself, add =-u= flag to the =elinter= command:\n\n#+begin_src sh\nelinter -u RECIPES\n#+end_src\n*** Sandboxing\n=elinter= creates symbolic links in a cache directory and operates on them, rather than lint and compile source files directly in the repository.\nThis is useful both for simplification and isolation.\nOnce symbolic links are created, they are reused across different runs for performance.\nSince they are symbolic links, file modifications are reflected, but file additions/deletions are not applied.\nAfter you create/delete a source file in the repository, you have to run =elinter= with =-c= arguments to recreate the sandbox:\n\n#+begin_src sh\nelinter -c\n#+end_src\n\nYou can use =-c= with other arguments:\n\n#+begin_src sh\nelinter -c -l --experimental\n#+end_src\n** Credits, inspiration sources, and alternatives\n=elinter= was influenced by or depends on the following projects:\n\n- [[https://github.com/nix-community/emacs-overlay/][emacs-overlay]] from the Nix community, its =emacsWithPackagesFromPackageRequires= parser by Steve Purcell, and [[https://github.com/talyz/fromElisp][fromElisp]] parser (used in [[https://github.com/akirak/nix-elisp-helpers][my Nix library]]) by Kim Lindberger\n- [[https://github.com/alphapapa/makem.sh][makem.sh]] by Adam Porter (alphapapa), for some of its linting code and the idea of extensive use of bash\n- [[https://github.com/riscy/melpazoid/][melpazoid]] by Chris Rayner (riscy), for extra linting features and the idea of sandboxing\n- [[https://github.com/conao3/keg.el/][keg.el]] by Naoya Yamashita (conao3), for its recipe-oriented configuration API\n- [[https://github.com/DamienCassou/nix-hello-world][nix-hello-world]] by Damien Cassou, for configuring Nix projects\n- [[https://gitea.petton.fr/DamienCassou/makel][makel]] by Damien Cassou, for some linting code\n\n=elinter= is an improvement upon the previous version, on which I gained help by [[https://github.com/ericdallo][Eric Dallo]] and [[https://github.com/terlar][Terje Larsen]].\n\nThe current version (v4) was contributed by the following people:\n\n- Zainab Ali ([[https://github.com/zainab-ali][@zainab-ali]]) [[https://github.com/akirak/elinter/pull/101][#101]]\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakirak%2Felinter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fakirak%2Felinter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakirak%2Felinter/lists"}