Working on the deck
For changing the deck; none of this is needed to use it.
The gate
tools/check-all.sh runs every check CI runs, in CI's order, continues past a failure and ends with "the gate is green" or the list of failed steps. The checks one by one:
tools/check-shared.sh # shared files match the template
jennifer fmt -l src/*.j examples/*.j # formatting
jennifer lint src/*.j examples/*.j # lint
tools/check-headers.sh # SPDX pair and engine floor, against deck.yaml
tools/check-overlays.sh # every module has a co-located overlay
tools/check-src.sh # src/ holds only .j files
tools/check-coverage.sh # every export is called from an overlay
tools/check-docs.sh # docs, signatures and docblocks match the code
tools/check-identity.sh # no template placeholder left
for suite in src/*_test.j; do jennifer test "$suite"; done
tools/check-examples.sh # every example still runsfmt -l lists unformatted files and exits 1 if there are any; lint exits 1 on a warning and 0 on info. The scripts catch drift neither tool sees:
check-headers.shreads the licence and the engine floor fromdeck.yamland checks every.jheader states both.jennifer lintrejects a malformed pragma but not a missing one.check-overlays.shrequires aMODULE_test.jbeside every module and a module beside every overlay. This is jvc's publish gate, checked at push time instead of publish time.check-docs.shcompares the cheatsheet and every deck-module call in the docs with the code: names, parameter names, arity, struct fields, enum variants, constant values and docblock tags.docs/.cheatsheet-todo, when present, lists tolerated older gaps; it only shrinks.check-coverage.shfails when an export is never called from an overlay;tools/.coverage-todois its backlog. The remaining entry,source.createGzip, can only be exercised by spawninggzip.check-examples.shbuilds a FASTQ/BED/GFF3/SAM/VCF fixture set in.ci-fixtures/inside the checkout, runs each example against it with relative paths, and removes it.examples/pipeline.jdrives external aligners and is only parse-checked.
The tools/ scripts other than check-examples.sh are shared byte-for-byte with the other deck repositories. tools/deck-lib.sh discovers the manifest (deck.toml, deck.yaml, deck.yml or deck.json), the deck's identity and whether it is a set of modules or a module with included topics.
Tests
jennifer test src/qc_test.j # one suite; there is no finer filter
for suite in src/*_test.j; do jennifer test "$suite"; doneThere are 172 tests in twelve overlays. They cover gzip round-trips through the FIFO, interval operations against bedtools semantics, coordinate conversion in both directions, parser edge cases (minimal records, symbolic VCF alleles, ##FASTA sections, partial adapters), QC values against hand-computed counts, and concurrency in runParallel.
MODULE_test.j is a white-box overlay of MODULE.j: it calls exported and private functions by their bare names and inherits the module's imports, so re-importing one of them is an alias collision.
In CI jennifer runs in a container that mounts only the checkout. A test that needs files creates them under .ci-fixtures/ (git-ignored) and passes relative paths. Tests that read standard input only open and close it; on a host where it cannot be reopened (a socket) they check nothing.
Building the book
The manual is the Markdown in docs/, with docs/SUMMARY.md as its outline and grimoire.toml as its configuration. It is built by Grimoire, which ships as a container:
docker run --rm --user "$(id -u):$(id -g)" -v "$PWD:/work" \
ghcr.io/jennifer-language/grimoire:latest build # -> site/From a Grimoire checkout, with a live preview on :8080:
/path/to/grimoire/bin/grimoire build
/path/to/grimoire/bin/grimoire serve --watchA chapter in SUMMARY.md with no file behind it fails the build. The book is published as a site only ([pdf] enabled = false in grimoire.toml).
CI
Three workflows, byte-identical across the deck repositories:
| workflow | when | what |
|---|---|---|
test.yml | push, PR | the gate above |
docs.yml | push, PR | builds the book; publishes to Pages from main |
release.yml | version tag | re-runs the gate, then cuts the release |
Tests and docs run in containers, so a runner needs nothing installed. tools/deck-lib.sh picks the interpreter image from the floor: a floor at or below the newest release (0.25) runs on that release's image, here ghcr.io/jennifer-language/jennifer:0.25; a newer floor runs on :dev, which bypasses the floor check. JENNIFER_IMAGE overrides the choice. The book uses ghcr.io/jennifer-language/grimoire:latest.
test.yml has a tiny job that runs only when the manifest lists jennifer-tiny under engines. This deck does not, since streaming gzip and pipeline need exec.
Publishing the book needs GitHub Pages set to Build and deployment > Source > GitHub Actions in the repository settings.
Cutting a release
Tag the commit with the version in deck.yaml, written plain (0.2.0, no v). release.yml refuses any other tag.
tools/pack.sh builds the archive in the shape the deck spec describes: deckyard-ngs-<version>.tar.gz, one wrapping directory holding src/ and, beside it, the manifest, licence and README. jvc vendors src/ and ignores the rest. Two forms of the digest go with it: a sha256sum -c file and the sha256:<hex> the registry records as its integrity pin.
Installing and importing shows how to vendor the archive by hand.