轻轻松松给 Emacs 项目加上 CI 测试

TLDR:新建 .github/workflows/test.yml,写入下面内容就完了,用不着写任何测试:

name: CI

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        emacs_version:
          - 25.1
          - 25.3
          - 26.1
          - 26.3
          - snapshot
    steps:
    - uses: purcell/setup-emacs@master
      with:
        version: ${{ matrix.emacs_version }}
    - uses: actions/checkout@v1
    - name: Run tests
      run: 'emacs -Q --batch -L . -f batch-byte-compile *.el'

光检查 byte compile 失败与否就够了吗?

不够,但比压根就不检查强。大多数 Emacs Lisp 项目没有 CI,有信心想支持的 Emacs 版本都能 byte compile 成功?本来轻轻松松就能有,为什么不考虑加上呢?

如何处理 byte compile 的 warning?

光有 warning 而没 error,batch-byte-compile 并不会失败(exit code 依旧是 0),所以 CI 体现不出来。如果要 warning 也失败,用:

emacs -Q --batch --eval "(setq byte-compile-error-on-warn t)" -f batch-byte-compile *.el

注意 byte-compile-error-on-warn 这个变量在 Emacs 26.1 之前不太靠谱,Emacs 25.3 及以前版本即使设置了,有的 warning 依旧不报错:

如果我有测试呢?

太好了,大多数 Emacs 项目没有任何测试。把你的测试加上,比如你的 ERT 测试写在 foo-tests.el 中:

emacs -Q --batch -L . -l foo-tests -f ert-run-tests-batch-and-exit

如果我的项目有依赖呢?

手动安装,用 git clone 或者 curl。绝大多数 Emacs 包都只有一个 el 文件,curl 下载就行了,顺便也 byte compile:

curl -O https://raw.githubusercontent.com/jrblevin/markdown-mode/master/markdown-mode.el
emacs -Q --batch -L -f batch-byte-compile markdown-mode.el
14 个赞

很好很实用的介绍! :+1:

扩展的质量其实很影响生态的发展,这也是我一直坚持实用 melpa 的原因之一。melpa 有各种问题,但是本身也有一些优势和特点,比如便捷性、大小、速度等。最关键一点比起一些 blog 或者 wiki 上的包质量又要好那么一些,至少第一次申请有审核(虽然不是那么严格,但总比没有强)。挑选包其实是一个大工程,很耗时间的。从以前的 emacswiki 到现在的elpa,Emacs 一直在进步,但是还是比不上 VSCode 甚至 Atom、Sublime 的速度。最重要一点就是 Emacs 的扩展太多太分散,缺乏稳定性和扩展性,也就是说质量不高。其中最重要一点就是缺乏测试,这也是开源项目的通病,毕竟大家不是以这个赚钱的。这时候 CI 就很有必要了,自动做一些测试会让包的可维护性和稳定性提高很多。Emacs 生态立最重要最有名的几个包都是有自己的 CI,比如 magit、flycheck、

在开发 Centaur 和 doom-modeline 的过程中,我也加入了 CI。不过选择的方案是 evm+Cask,也很好用。除了 byte-compile,还可以考虑 lint和ERT。不同的项目会有不同的用例。其他项目因为比较简单,有时间陆续加上。感兴趣的可以去看看。

6 个赞

关于用travis的解决方案

nix-emacs-ci

GitHub - purcell/nix-emacs-ci: Emacs builds for continuous integration

实际上purcell的setup-emacs是从这个改的。

evm

更传统的方案是用evm. 在.travis.yml里写入

language: emacs-lisp
env:
  - EVM_EMACS=emacs-26.1-travis
  - EVM_EMACS=emacs-git-snapshot-travis

install:
  - sudo apt-get update
  - sudo apt-get install sqlite3
  - git clone https://github.com/rejeep/evm.git $HOME/.evm
  - export PATH=$HOME/.evm/bin:$HOME/.cask/bin:$PATH

  - evm config path /tmp
  - evm install $EVM_EMACS --use --skip

可以自行添加更多的版本。


更好的方式是引用Cask,在Cask文件里写入

(depends-on "dep")

(development (depends-on "devel-dep"))

对于Github Action, 再引用 GitHub - cask/setup-cask: Install Cask for Github Actions workflow

对于travis,在install里加入

  - curl -fsSkL https://raw.githubusercontent.com/cask/cask/master/go | python
  - cask install
1 个赞

测试非常必要。

不是每个人都如远古大神一般硬核,两根电话线就能碰擦出一个操作系统(雾)

测试对我来说,就是一道安全保障,使得我这样的菜鸟不至于错得太离谱。但是我也没啥好的实践,基本上就是写完一个功能,再写个测试来验证,或者解决一个问题,就写个测试把漏洞补上,以免再犯。

也曾有打算要写一个包,用来创建新项目测试模版,也可以给旧项目增加测试文件:

⋊> [~/.repos/emacs-ert-cask-boilerplate/] tree .
.
├── Cask
├── Makefile
├── cask-bootstrap.el
├── ert-cask-boierplate.el
└── templates
    ├── Cask
    ├── Makefile
    └── cask-bootstrap.el

不过由于我的兴趣点转移,这个项目停了很久了😅 我有不少项目就是这样凉掉的。

1 个赞

以前也用 Travis CI,GitHub Action 直接就能用,不需要再注册、打开一个网站。

这两个我看都挺麻烦。当然如果你已经用上了,能够接收得了就 OK。

我弄个了 GitHub 模版,点击绿色的「使用这个模版」按钮就能从这个模版新建一个仓库。

3 个赞

好主意 :+1:

竟然还有这种操作

感谢各位大神的方案,我也选了一个,在我的上面加起来,挺方便的。

感谢,用上了。

test.yml 具体的说明在哪里可以找到?有一项 uses: actions/checkout@v1 没明白是什么作用,暂时只找到到 Set up Emacs · Actions · GitHub Marketplace · GitHub 这个。

好东西,正好需要

查看 GitHub Action 文档

checkout 出你的项目代码,见:

好像现在应该用 v2 了。

1 个赞

像emacs rime这种,我需要在 linux mac windows上测试构建,但是又要用到各自的包管理器,该怎么做呢?比如 homebrew。还有一些东西安装成本很高,比如 librime 应该怎么做呢。

多平台构建 build matrix:

runs-on: ${{ matrix.os }}
strategy:
  matrix:
    os: [ubuntu-16.04, ubuntu-18.04]
    node: [6, 8, 10]

Github 也提供 Windows 和 macOS。

依赖安装就放在 steps: 下面,可能也要 matrix。如果依赖的东西不是很偏,可以考虑用 nixpkgs 代替 homebrew,消除部分差异。

我 fork 了一个基于 cookiecutter 的模版项目,做了一点小改动(CircleCI -> Github Actions,Straight -> Cask):

用法:

⋊> [~/workspace] pip3 install cookiecutter
⋊> [~/workspace] cookiecutter gh:twlz0ne/emacs-package-template

然后根据提示回答问题,如果一直回车,将得到如下目录结构的项目:

⋊> [~/workspace] tree -a batman-mode/
batman-mode/
├── .github
│   └── workflows
│       └── test.yml
├── .gitignore
├── Cask
├── LICENSE
├── README.org
├── batman-mode.el
└── test
    └── batman-mode-test.el

3 directories, 7 files

生成的骨架项目基本完备,无需删除样例文件或代码。

还可以在CI里加上拼写检查,

compile会把el编译成elc,如果不需要这个副作用的话,可以参考flymake的写法(需要emacs 26),

(defun lazyflymake-elisp-init ()
  "Emacs Lisp syntax linter for flymake."
  (let* ((program-name (expand-file-name invocation-name invocation-directory))
         (code-file (lazyflymake-sdk-code-file))
         (common-args '("-Q" "--batch"))
         rlt)
    (when code-file
      (setq rlt (list program-name
                      (append common-args
                              (list "--eval"
                                    (prin1-to-string
                                     (quote
                                      (dolist (file command-line-args-left)
                                        (with-temp-buffer
                                          (insert-file-contents file)
                                          (condition-case data
                                              (scan-sexps (point-min) (point-max))
                                            (scan-error
                                             (goto-char(nth 2 data))
                                             (princ (format "%s:%s: error: Unmatched bracket or quote\n"
                                                            file (line-number-at-pos)))))))))
                                    code-file)))))
    (if lazyflymake-debug (message "lazyflymake-elisp-init called. return %s" rlt))
    rlt))

在ci里用了wucuo,非常好 GitHub - ShuguangSun/rutils.el: R utilities with transient

但是有个问题,不知道是wucuo的问题,还是aspell的问题。已经将 nil 加入 .aspell.en.pws,但是仍然会报错

/home/runner/work/rutils.el/rutils.el/rutils.el:64: typo ’nil’ at 2080 is found
/home/runner/work/rutils.el/rutils.el/rutils.el:64: typo ’nil’ at 2084 is found
/home/runner/work/rutils.el/rutils.el/rutils.el:64: typo ’nil’ at 2088 is found

不知道怎么让样emacs-rime通过测试?我目前是直接通过文件路径排除Emacs-rime参与CI测试了。

有没有可以直接上手使用的 gitlab-ci 模板呢?或是 docker 镜像?现在我是用 ubuntu 的镜像然后每次手写一个 ci.el 去跑。