automate - the better. We use [[https://circleci.com/][CircleCI]], [[https://github.com/features/actions][GitHub Actions]] and [[https://www.docker.com/][Docker]] to test PRs,
update/fixi documentation and exporting it to [[https://develop.spacemacs.org/]].
Most of the code is just a bunch of bash/ELisp scripts and yml files, but
some of the documentation tools are written in Clojure.
Check out [[https://github.com/syl20bnr/spacemacs/tree/develop/.circleci][CircleCI]] and [[https://github.com/syl20bnr/spacemacs/tree/develop/.github/workflows][GitHub Actions]] directories, the code is pretty much
self-explanatory but will be examined in depth below.
Code tests are handled by GitHub Actions exclusively.
The stages are:
1. Emacs installation with [[https://github.com/purcell/setup-emacs][purcell/setup-emacs]] - for UNIX and
[[https://github.com/jcs090218/setup-emacs-windows][jcs090218/setup-emacs-windows]] for Windows. The step is configured
by the job matrix. With two keys =os= and =emacs_version=. CI runs test
for every possible combination. The stage ends up seriously bloated with
repetition since the actions sometimes fail (especially for MacOS)
so I added 3 sets of retires for the both actions. Currently GitHub
[[https://github.community/t/how-to-retry-a-failed-step-in-github-actions-workflow/125880][doesn't provide a better way to implement this]].
2. Checkout - clones the repo.
3. Installation of a local ELPA mirror with packages used be the tests.
The archive is build daily in [[https://github.com/JAremko/testelpa-develop][JAremko/testelpa-develop]] repository and
configured by .spacemacs files used in test. The mirror is set as a top
priority package repository via [[https://github.com/syl20bnr/spacemacs/blob/develop/.github/workflows/scripts/dot_lock.el][Spacemacs lock file]] this way we actually
install the packages (it is important to test that the system works) and
if some packages are missing (for example, the mirror can be outdated)
then they will be installed from a remote repository.
4. Run the tests! CI run core, base and layer tests sequentially because
heaving 20+ CI results in PRs makes people ignore them. And this way
they start faster since we cut on setup time. But the tests have to
=always= clean after themselves to avoid affecting the next ones.
This job uses [[https://github.com/syl20bnr/spacemacs/blob/develop/.circleci/select_pr_changed][.circleci/select_pr_changed]] to find out what files are changed in
the tested PR and if any of them are .org files it will check that they can be
processed by exporting and validating them. The process will be explored further
in the [[#documentation-updates][Documentation updates]] section.
All updates are handled by CircleCI. There are two config files:
[[https://github.com/syl20bnr/spacemacs/blob/develop/.circleci/config.yml][.circleci/config.yml]] that injects =IS_BRANCH_UDATE= environment variable into
the second file [[https://github.com/syl20bnr/spacemacs/blob/develop/.circleci/config_tmpl.yml][.circleci/config_tmpl.yml]] - actual config that CI will use.
It has to be done this way because environment variables aren't accessible
outside workflows, but CI needs =IS_BRANCH_UDATE= to choose what workflows
to run.
[[https://github.com/syl20bnr/spacemacs/blob/develop/.circleci/config_tmpl.yml][.circleci/config_tmpl.yml]] begins with declarations of =parameters= (they
are used to configure jobs) and =spacetools= executor. Every job runs inside of
a freshly spawned =jare/spacemacs-circleci:latest= container that has Emacs and
documentation tools, hub CLI and some other stuff. Here's its [[https://github.com/JAremko/spacemacs-circleci/blob/master/Dockerfile][docker file]] and
its base image's [[https://github.com/JAremko/spacetools/blob/master/Dockerfile.noemacs][docker file]].
The middle section of the config defines jobs and their names. At the end of the
file we have workflow definitions that aggregate jobs by names. Here you can see
how =is_branch_update= parameter is used to select which workflows should be
ran. Its value is set by inlined =IS_BRANCH_UDATE= environment variable that
comes from environment variables page under CircleCI project settings.
**** How updates end up in Spacemacs repositories
Merging updates is semi-automatic. Bot (specified by =UPD_BOT_LOGIN= job
environment variable) uses GitHub token (stored in CircleCI project settings) to
push updated version of Spacemacs develop branch into its fork (=UPD_BOT_REPO=)
then it opens pull request to =PRJ_REPO= owned by =PRJ_OWNER= (the fork is based
on it). =PUBLISH= variable also used as a name for fork repo branch while
=PR_BRANCH= is the branch against which PR will be opened. See [[https://github.com/syl20bnr/spacemacs/blob/develop/.circleci/push][.circleci/push]]
and [[https://github.com/syl20bnr/spacemacs/blob/develop/.circleci/maybe_pr][.circleci/maybe_pr]] files for inner works. Most of bash variables are
configured in the [[https://github.com/syl20bnr/spacemacs/blob/develop/.circleci/shared][.circleci/shared]] file.
The setup is really simple. We have [[https://github.com/syl20bnr/spacemacs/blob/develop/.circleci/built_in/upd_built_in][.circleci/built_in/upd_built_in]] bash
script that reads [[https://github.com/syl20bnr/spacemacs/blob/develop/.ci/built_in_manifest][.ci/built_in_manifest]] file line by line and downloads every
First files are exported into [[https://github.com/edn-format/edn][edn]]. File extension is .sdn "Spacemacs
Documentation Notation" if you will, it's done to avoid collisions with config
.edn files that can be in exported directories. The exporting is done by Emacs
Lisp program based of [[https://github.com/emacsmirror/org/blob/master/lisp/ox.el][ox.el]]. [[https://github.com/JAremko/sdnize.el][Here's repository]]. The program extracts data and
perform basic validations.
The resulting .sdn files then process by [[https://github.com/JAremko/spacetools][spacetools]] (I'll work on
documentation).
The steps are:
1. parse and validate .sdn files
2. Generae LAYERS.sdn file.
3. Generate new set of .org files and replace old ones.
The tool is configured by [[https://github.com/syl20bnr/spacemacs/blob/develop/.ci/spacedoc-cfg.edn][.ci/spacedoc-cfg.edn]] file. For details on how
LAYERS.org generation works see [[https://github.com/syl20bnr/spacemacs/blob/develop/CONTRIBUTING.org#readmeorg-tags]["README.org tags" section of CONTRIBUTING.org]]
The rest of configs(and their default values) are listed [[https://github.com/JAremko/spacetools/blob/master/components/spacedoc/src/spacetools/spacedoc/config.clj][here]].
HTML generation handled by [[https://github.com/syl20bnr/spacemacs/blob/develop/core/core-documentation.el][core/core-documentation.el]] the entry function is
=spacemacs/publish-doc= all the interesting parts are in preprocessors. Search
for =Add preprocessors here= comment. Overall - pretty basic. When I finish with
documenting/refactoring =spacetools= I'll probably use it to generate HTML
similarly to how it generates .org files.
What makes this job special is that CircleCI caches EmacsLisp dependencies of
the HTML exporter script. See =save_cache= and =restore_cache= sections
in [[https://github.com/syl20bnr/spacemacs/blob/develop/.circleci/config_tmpl.yml][config file]]. Even with this export is pretty slow since it processes files
We have 2 cron(scheduled) jobs: [[https://github.com/syl20bnr/spacemacs/blob/develop/.github/workflows/stale.yml][Managing stale issues]] with [[https://github.com/actions/stale][actions/stale]] and
running built-in update job. The last one is managed by CircleCI and currently
doesn't run since CircleCI [[https://discuss.circleci.com/t/setup-workflow-and-scheduled-workflow-in-the-same-configuration/39932/6][doesn't support cron jobs with setup configs]]. Instead
built-in files are updated every time Spacemacs develop branch is pushed.
** We used to have TravisCI (3 CI providers at the same time)
We ran long running jobs there but ended up dropping the CI since TravisCI
doesn't allow collaborators to read/set environment variables anymore,
[[https://pbs.twimg.com/media/Eoq3OnWW4AIy7ih?format=jpg&name=large][the could be in some kind of trouble]] or [[https://blog.travis-ci.com/oss-announcement][maybe not]]. Anyway, when TravisCI
stopped running jobs on their old domain (as a part of the migration from
- Currently configs with setup step [[https://discuss.circleci.com/t/setup-workflow-and-scheduled-workflow-in-the-same-configuration/39932/6][don't run cron jobs]].
- We have setup config because environment variables aren't accessible at the