Skip to content

build: build the documentation in CI - #67

Merged
cigamit merged 1 commit into
ctrliq:mainfrom
blaipr:build/build-the-docs-in-ci
Sep 13, 2026
Merged

cigamit merged 1 commit into
ctrliq:mainfrom
blaipr:build/build-the-docs-in-ci

Conversation

@blaipr

@blaipr blaipr commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Nothing built these docs, so a change to the CLI parser or to a cross-reference could break them and no check would notice. #40 recorded why: reference.rst is generated by sphinxcontrib-autoprogram from the parser in cli/sphinx.py, and render() builds that parser by issuing an HTTP OPTIONS request per resource against a running Ascender. There is no static command table to fall back on, since the CLI discovers its own commands the same way.

That is one page out of seven. The other six are plain reStructuredText and need nothing at all, so this builds those and leaves the generated one out.

What changes

  • conf.py drops reference.rst when neither CONTROLLER_HOST nor TOWER_HOST is set. A build with credentials still produces the complete documentation, unchanged.
  • tox.ini gains a docs environment, with the credentials passed through so the full build is one command away.
  • ci.yml gains a Docs job running the same sphinx-build invocation.
  • docs/README.md described only the server-backed build, which is no longer the common case. It now covers both and explains which page needs a server and why.

Two decisions worth flagging

-W is the point. Warnings as errors is what makes this worth running: a dead cross-reference or a malformed directive fails rather than rendering wrong. Verified by pointing a :ref: at a label that does not exist, which fails with undefined label: 'nope' [ref.ref] and exit 1.

Gating, not advisory, unlike the type checker in #42. That one started with 136 diagnostics to work through, so blocking on it would have blocked everything. This build is clean today, and an advisory job that always passes protects nothing.

The tidier way to exclude the page would have been an only directive around the toctree entry. That does not work: toctree entries resolve while the source is read and only is evaluated later, so the warning fires regardless. It is suppressed by name instead, with the reasoning written next to it in conf.py.

Verification

  • sphinx-build -b html -W --keep-going ascenderkit/cli/docs/source <out> with no credentials in the environment: build succeeded, exit 0, producing index, usage, authentication, output, examples, install, plus genindex and search. No reference.html, as intended.
  • The same command with a :ref: to a nonexistent label: exit 1.
  • ruff format --check, ruff check and the unit suite all pass. The suite reports 366 rather than 363 passing, because installing the docs extra un-skips the three tests in tests/unit/cli/test_sphinx.py that refactor: build the Sphinx parser on access, not at import #49 added.
  • yamllint reports nothing new on ci.yml; the folded run: resolves to the single intended command.

One risk to name: the docs extra pins nothing, so a future Sphinx release could introduce a warning unrelated to any change here and turn this red on an unrelated day. If that happens the fix is to pin sphinx the way lint pins ruff and typecheck pins ty.

Nothing built these docs, so a change to the CLI parser or to a cross-reference
could break them and no check would notice. ctrliq#40 recorded the reason: reference.rst
is generated by sphinxcontrib-autoprogram from the parser in cli/sphinx.py, and
render() builds that parser by issuing an HTTP OPTIONS request per resource
against a running Ascender. There is no static command table to fall back on,
since the CLI discovers its own commands the same way.

That is one page out of seven. The other six are plain reStructuredText and need
nothing, so conf.py now drops reference.rst when no credentials are present and
the rest build offline. A build with CONTROLLER_HOST set still produces the
complete documentation, unchanged.

The job runs with -W, which is what earns its keep: a dead cross-reference or a
malformed directive fails rather than rendering wrong. Verified by pointing a
:ref: at a label that does not exist, which fails the build with
`undefined label ... [ref.ref]` and exit 1.

Moving the toctree entry behind an `only` directive was the tidier option and
does not work: toctree entries resolve while the source is read and `only` is
evaluated later, so the warning fires anyway. It is suppressed by name instead,
with the reasoning in conf.py next to it.

Gating rather than advisory, unlike the type checker in ctrliq#42. That one started
with 136 diagnostics to work through, so blocking on it would have blocked
everything; this build is clean today, and an advisory job that always passes
protects nothing.
@ciq-it-service-account

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@cigamit cigamit self-assigned this Sep 13, 2026
@cigamit cigamit added the enhancement New feature or request label Sep 13, 2026
@cigamit
cigamit merged commit 93e3320 into ctrliq:main Sep 13, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Development

Successfully merging this pull request may close these issues.

3 participants