Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
## Checklist

- [ ] Relevant scripts/docs stay in sync
- [ ] Image tags and data versions changed only in `versions.env`; a new doc page is in the `mkdocs.yml` nav
- [ ] Image tags and data versions changed only in `versions.env`; a new doc page is in the `zensical.toml` nav
- [ ] `shellcheck` passes for changed shell scripts
- [ ] Smoke-test assumptions were checked for changed pipeline contracts
- [ ] No personal paths, hostnames, or sample-specific defaults were introduced
Expand Down
425 changes: 425 additions & 0 deletions .github/scripts/site-check.py

Large diffs are not rendered by default.

57 changes: 38 additions & 19 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,25 @@ name: Docs
# so the source is "GitHub Actions" and there is no gh-pages branch. Until
# then the deploy job fails, which is the test that the switch happened.
#
# Pull requests that touch the docs run the strict build, so a broken link, a
# missing page or an unreachable page fails the check instead of reaching the
# site. A push to main deploys, and only after the same build has passed.
# Pull requests that touch the docs run the strict build and the site check,
# so a broken link, a missing page or an unreachable page fails the check
# instead of reaching the site. A push to main deploys, and only after the
# same build has passed.
#
# The site is published as a Pages artifact, never with `mkdocs gh-deploy`:
# no gh-pages branch, no `contents: write`, and one artifact is the whole site.
# The site is published as a Pages artifact: no gh-pages branch, no
# `contents: write`, and one artifact is the whole site.
on:
push:
branches:
- main
paths:
- 'docs/**'
- 'mkdocs.yml'
- 'zensical.toml'
- '.github/workflows/docs.yml'
- '.github/scripts/site-check.py'
# Add every file a page includes with pymdownx.snippets (for example
# docker-compose.yml, .env.example): a change to it must rebuild the
# site, and a rename must fail the build.
# The live-site demo at /demo/ is built from these (tests/demo/build_live_demo.py).
# assets/** because render_report.py also reads the gene and rule tables there.
- 'assets/**'
Expand All @@ -32,12 +37,12 @@ on:
pull_request:
workflow_dispatch:

# One run at a time per ref, and a running deploy is never cancelled. Locking
# only the deploy job is not enough: an older push whose build finishes later
# would deploy last and publish a stale site. GitHub does not promise push order
# for runs waiting on the lock, so in a rare race an older commit can still be
# published; the next push to the docs corrects it. Pull requests get their own
# group.
# One run at a time per ref, never cancelled. GitHub keeps one running and one
# pending run per group, and a run that joins later replaces the pending one.
# Runs join in the order GitHub queues them, which is not promised to be push
# order, so a newer push is likely, not certain, to deploy last.
# Locking only the deploy job is not enough: an older push whose build finishes
# later could deploy last and publish a stale site. Pull requests get their own group.
concurrency:
group: pages-${{ github.ref }}
cancel-in-progress: false
Expand All @@ -54,41 +59,55 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# This job never pushes; a persisted token is readable by pip and every MkDocs plugin.
# This job never pushes; a persisted token is readable by pip and by the build.
persist-credentials: false

- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: '3.15'
# pip's download cache only. Zensical's own build cache (.cache/) is
# never kept between runs: its docs advise against it on CI, and
# --clean below starts from nothing anyway.
cache: pip
cache-dependency-path: docs/requirements-docs.txt

- name: Install dependencies
run: pip install -r docs/requirements-docs.txt

# mkdocs.yml sets `strict: true`; the flag here keeps the build strict
# even if someone removes that line.
# zensical.toml sets `strict = true`; the flag here keeps the build strict
# even if someone removes that line. `python -m zensical`, never the bare
# `zensical` command: it puts the repo root on sys.path, which the awesome
# lists' Markdown extension needs, and every repo builds the same way.
- name: Build
run: mkdocs build --strict
run: python -m zensical build --clean --strict

# What the strict build does not check: a page in no nav entry, a nav
# entry for a missing file, a missing image, a /rooted link, a raw <title>
# in a page. Each one was proven to turn this step red (validate-zensical.sh).
- name: Check the built site
run: python -I .github/scripts/site-check.py site

# /demo/: the live site replaying an invented run of DEMO-001, the invented
# sample of the docs pictures, through the real page and plugin code
# (tests/demo/build_live_demo.py; standard library only). It is a static
# folder beside the pages, not a page of the nav.
# folder beside the pages, not a page of the nav, so it goes in after the
# site check.
- name: Add the live-site demo
run: |
python3 tests/demo/build_live_demo.py --out site/demo
test -s site/demo/runs/DEMO-001/frames.json

# Push to main only: workflow_dispatch can be run on any branch, and the
# push filter above does not apply to it. Same line as docs-pages-helm.yml.
- name: Upload the site
if: github.event_name != 'pull_request'
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
with:
path: site

deploy:
# Runs on push to main only, after the build job has passed.
if: github.event_name != 'pull_request'
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
needs: build
runs-on: ubuntu-latest
permissions:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/nextflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
run=false
while IFS= read -r f; do
case "$f" in
docs/*|*.md|mkdocs.yml|LICENSE) ;;
docs/*|*.md|zensical.toml|LICENSE) ;;
*) run=true ;;
esac
done <<<"$changed"
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ ci.config
# OMC / local agent operational state — may contain local paths or notes; never commit
.omc/

# MkDocs build output
# Docs build output
site/

# Beads / Dolt files (added by bd init)
Expand Down
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ owngenome/
nextflow.yml # Nextflow config, lint, schema and stub runs on the pinned release and the newest 26.10.x
renovate-dry-run.yml # Renovate lookups without an app, and their checks
freshness.yml # Monthly issue of pins that fell behind upstream
docs.yml # mkdocs build
docs.yml # Zensical build + site check
release.yml, stale.yml # Releases, stale issues
```

Expand Down Expand Up @@ -119,7 +119,7 @@ User's FASTQ/BAM/VCF
### Documentation Conventions
- Each pipeline step has a matching doc in `docs/XX-name.md` and script in `scripts/XX-name.sh`
- Docs must include: What it does, Why, Tool name, Docker image, Command, Output, Runtime estimate, Notes
- The category table in `docs/pipeline-overview.md` and the `nav:` of `mkdocs.yml` must stay in sync with actual docs and scripts
- The category table in `docs/pipeline-overview.md` and the `nav` of `zensical.toml` must stay in sync with actual docs and scripts
- All Docker images must include the exact tag (not floating)

### Lessons Learned
Expand All @@ -131,7 +131,7 @@ User's FASTQ/BAM/VCF
1. Add the image as one line in `versions.env` (`setup.sh` and `validate-setup.sh` read their list from it)
2. Create `scripts/NN-tool-name.sh` following script conventions
3. Create `modules/local/<tool>/main.nf` with no `container` line, add its process to the table in `scripts/ci/gen-containers-config.sh` and run it; or note in `docs/nextflow.md` why the step stays bash-only. Adding a step means a module plus, optionally, its script
4. Create `docs/NN-tool-name.md` following existing template, and add it to `nav:` in `mkdocs.yml`
4. Create `docs/NN-tool-name.md` following existing template, and add it to `nav` in `zensical.toml`
5. Add the step to the category table in `docs/pipeline-overview.md`
6. Add the module to the step list (a `plan` call) in `scripts/run-all.sh` (its `--tools` name and database parameter), so a default run includes it
7. Add a row for the image to `tests/smoke/commands.tsv`: a real command on the fixture and a check on what it wrote (an image with no row fails `container-test.yml`)
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ validate_sample "$SAMPLE"
Every pipeline step needs:
- `docs/NN-tool-name.md` — What it does, why, Docker image, command, output, runtime, notes
- `scripts/NN-tool-name.sh` — The executable script
- An entry in the `nav:` of [`mkdocs.yml`](mkdocs.yml), or the docs build fails on the orphan page
- An entry in the `nav` of [`zensical.toml`](zensical.toml), or the docs site check fails on the orphan page
- A mention in the category table of [`docs/pipeline-overview.md`](docs/pipeline-overview.md)
- Section in `docs/interpreting-results.md` if the output needs explanation

Expand Down Expand Up @@ -94,7 +94,7 @@ The CI pipeline enforces this with automated scanning.
5. **Create the Nextflow module** `modules/local/<tool>/main.nf` and wire it into the workflow, or say in [`docs/nextflow.md`](docs/nextflow.md) why the step stays bash-only. A module has no `container` line: add its process to the table in `scripts/ci/gen-containers-config.sh` and run that script.
6. **Create the documentation** `docs/NN-tool-name.md` following the existing step docs.
7. **Update these files:**
- [`mkdocs.yml`](mkdocs.yml): the page in `nav:`
- [`zensical.toml`](zensical.toml): the page in `nav`
- [`docs/pipeline-overview.md`](docs/pipeline-overview.md): the category table
- `scripts/run-all.sh`: one entry in its step list (a `plan` call), so a default run passes the module's name in `--tools` (and its database parameter when the data is under `GENOME_DIR`). A bash-only step that a default run should include gets a switch there instead, run after the pipeline
- [`tests/smoke/commands.tsv`](tests/smoke/commands.tsv): a row for the image, a real command on the fixture and a check on what the tool wrote. [`container-test.yml`](.github/workflows/container-test.yml) fails for an image with no row
Expand Down
2 changes: 1 addition & 1 deletion docs/requirements-docs.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
mkdocs-material==9.8.0
zensical==0.1.0
12 changes: 9 additions & 3 deletions docs/stylesheets/theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
* (#1c1917) and a row of base tiles in green #16a34a (A), blue #2563eb (C),
* amber #d97706 (G) and red #dc2626 (T). The header inverts the banner: the
* near-black as the surface, the cream as the text, the blue as the accent.
* mkdocs.yml sets `primary: custom` and `accent: custom`, so Material paints
* nothing until these variables exist.
* zensical.toml sets `primary: custom` and `accent: custom`, so the theme
* paints nothing until these variables exist.
*/
:root {
--md-primary-fg-color: #1c1917; /* banner wordmark, the header surface */
Expand Down Expand Up @@ -45,11 +45,17 @@
* .md-header__topic and the page title in a second one, and swaps them on
* scroll. Styling both would change every page title too. */
.md-header__topic:first-child .md-ellipsis {
color: #f6f1e7;
font-weight: 800;
letter-spacing: -0.01em;
}

/* That colour only on the dark scheme: Zensical's modern header takes the page
background, so on the light scheme it is white and a light name would vanish.
There the name keeps the default text colour. */
[data-md-color-scheme="slate"] .md-header__topic:first-child .md-ellipsis {
color: #f6f1e7;
}

/* Keep the mark and the name close, so they read as one unit. */
.md-header__button.md-logo {
padding-right: 0.2rem;
Expand Down
2 changes: 1 addition & 1 deletion docs/updating.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ This page is for maintainers. It says how a pinned version gets bumped, what che
| Python packages of the screenshot script | the `==` pins in `tests/demo/retake-screenshots.sh` | Renovate |
| Aldy, the alternative CYP2D6 caller | its version in [Cyrius](21-cyrius.md), in the prose and the `pip install` line | Renovate |
| GitHub Actions (`uses:` lines) | the workflows | Dependabot, monthly |
| MkDocs and its plugins | `docs/requirements-docs.txt` | Dependabot, monthly |
| Zensical, the docs site builder | `docs/requirements-docs.txt` | Dependabot, monthly |
| Data releases: VEP cache, PCGR bundle, pypgx bundle, AnnotSV annotations, Yleaf data, gnomAD constraint, the GRIDSS blacklist commit | the variables at the end of `versions.env` | nobody: bump them by hand, together with the image they belong to. Guard's `coupled-versions` job fails while the VEP cache, pypgx bundle, AnnotSV or Yleaf data disagrees with its image |
| GENCODE gene lines (step 8) and exons (steps 6 and 39) | `GENCODE_RELEASE` in `scripts/lib/common.sh` | nobody: it moves with a VEP major, to the GENCODE release of that Ensembl release (the VEP major minus 66). The `coupled-versions` job fails until it does |
| VerifyBamID2 marker panel (step 33) | the tag in the `VB2_PANEL_FILES` URLs of `scripts/setup.sh`, with their sha256 | nobody: it moves with `VERIFYBAMID2_IMAGE`. The `coupled-versions` job fails while the tag and the image version differ |
Expand Down
Loading