Command-line tools
Two standalone scripts under scripts/, run directly with python3, not
installed as console entry points — there is no packaging for either
(Documentation guidelines — this docset’s own
README.rst is the same way). Both take --registry explicitly rather
than defaulting to one, since these scripts ship with the engine, which has no
registry of its own.
docctl.py — controlled-document workflow
$ python3 <zdocs>/scripts/docctl.py --registry documents.yaml <command> ...
Drives the author → review → approve lifecycle of a .. doc_control:: block
(Directives and roles) by editing it in place and committing the change
with your own git identity (git config user.name/user.email). Source:
docctl.
listPrint every document id that the other subcommands can actually operate on — one resolving to a source directory containing exactly one
.. doc_control::directive. A registry entry with no such directive, an unresolvabledoc_dir, or more than one directive in its top-level files is silently excluded from this list, not reported as an error.author <document-id> [--version VERSION]Sets
:author:to your git identity and commits (Signed-off-by:only).--versionalso overwrites:version:.review <document-id> [--force]Requires
authorto have already run. Refuses if the commit that set:author:(found viagit blame) has the same committer email as you — a reviewer must be a different person — unless--force. Commits with aReviewed-by:trailer in addition toSigned-off-by:.approve <document-id> [--effective-date YYYY-MM-DD] [--force]Requires
reviewed_byto be set and backed by a real commit (not an uncommitted edit), unless--force. Sets:approved_by:and:approval_date:(today), commits with anApproved-by:trailer, and creates a signed git tag<document-id>/<version>— the same<id>/*patterndocrefs.resolve_version()matches against for the sidebar version.bump-version <document-id> [--major | --minor]Starts a new version cycle on an already-released document: bumps
:version:(--minoris the default,x.Y→x.Y+1;--majorisX.y→X+1.0, and the current version must already bemajor.minor), then removes:author:,:reviewed_by:,:approved_by:and:approval_date:outright (not blanks them), sodoc_control’s own placeholders take over again. Refused forclassification: Recorddocuments, which version by folder/edition instead. If a release tag for the old version exists, also repoints a.. git_changelog::directive’s:rev-list:at<old-tag>..HEAD— but only if the document actually has one; nothing in this engine loads thesphinx_gitextension that directive belongs to (neitherzdocs_conf.py’s extension list norsphinx/requirements-doc.txtmentions it), so a document wantinggit_changelogneeds to add the package and the extension itself.
Every commit is both -s (signed-off) and -S (GPG-signed); an
unconfigured signing key is a hard failure here, not a silent skip, since this
is a compliance action. On error, docctl prints docctl: error: ... to
stderr and exits 1; a successful run exits 0. There is no dry-run
mode.
doccheck.py — cross-reference integrity gate
$ python3 <zdocs>/scripts/doccheck.py --registry documents.yaml \
--deploy build/deploy
Wired automatically as a POST_BUILD step of all-docs by
add_doc_check (so an ordinary build already
runs it) and as the standalone doc-check target, for re-checking an
existing deploy tree without rebuilding it. Source:
doccheck.
Two checks, neither of which a green sphinx-build/doxygen log catches on
its own. Both read the built deploy tree, so --deploy is required — there
is no sources-only mode, because a run that checks nothing must not be able to
report success.
Unresolved cross-references — requires a registry
xref_smoketest:page. Parses that one rendered page’s cross-reference bullets and flags any that rendered as an empty node (a parse-time role whose target inventory was not built yet) or as plain text (the target itself is missing from this build) instead of a real link. Skipped, with a note in the final summary line, if noxref_smoketest:is configured — this docset does not currently set one, so check A does not run against it.Dead deploy links — scans every rendered
*.htmlpage’shref``s; resolves an absolute one starting with the registry's ``base_urlback into the deploy tree, a bare relative one against the page’s own directory, and skips anything that escapes the deploy tree entirely (external links,mailto:, and similar) — policing those is not this check’s job.
Exit codes: 0 clean, 1 one or more findings (printed to stderr, grouped
by check, with a final doccheck: FAILED with N finding(s) line), 2 bad
invocation (registry or deploy path does not exist). A clean run with no
xref_smoketest: configured still exits 0, but says so explicitly in its
summary rather than reporting “OK” the same way a fully-covered run does.
Note
A third check was removed from doccheck rather than fixed. It scanned
document sources for tokens shaped like a document id and reported any the
registry did not declare, to catch content still naming a deleted document.
Recognising an id by shape means hardcoding a naming convention into the
engine — the pattern was dox-/docctl-/sop- — and it cannot be
derived from the registry instead, since an id that is declared is exactly
the case the check must stay silent about. It also made documentation about
zdocs unwritable: every example id in a tutorial was a finding.