mafw.scripts.doc_versioning
Helper tool for the generation of versioned documentation files.
Build Sphinx docs for every stable tag (excluding rc/alpha/beta), label highest tag as “stable”, optionally label current branch as “dev” if it’s ahead. Generates a versions.json and creates redirect index pages for stable/dev. Now with optional PDF generation!
- Requirements:
Git with worktree support
sphinx-build available on PATH (install Sphinx in the env)
For PDF: latexmk and pdflatex (TeX Live or similar)
multiversion-doc
Build and manage versioned documentation.
Usage
multiversion-doc [OPTIONS] COMMAND [ARGS]...
build
Build multiversion documentation.
- param outdir:
Output directory for built documentation
- type outdir:
Path
- param include_dev:
Whether to include dev alias if current branch is ahead
- type include_dev:
bool
- param min_vers:
Minimum version to consider
- type min_vers:
str
- param keep_temp:
Whether to keep temporary files
- type keep_temp:
bool
- param use_latest_conf:
Whether to use latest conf.py for all builds
- type use_latest_conf:
bool
- param build_pdf:
Whether to also build PDF versions
- type build_pdf:
bool
- param project_name:
Project name for PDF index page
- type project_name:
str
- param use_symlinks:
Whether to use symlinks instead of copying
- type use_symlinks:
bool
- param max_size:
Maximum artifact size in MB (0 = no limit)
- type max_size:
int
- param zip_filepath:
Directory where per-tag zip archives are written
- type zip_filepath:
Path
- param with_zip_file:
Whether to create per-tag zip archives for stable tags
- type with_zip_file:
bool
- param with_upload_zip:
Whether to upload per-tag zip archives to the GitLab Generic Package Registry
- type with_upload_zip:
bool
- param with_cached_packages:
Whether to use cached documentation zip packages from the GitLab Generic Package Registry
- type with_cached_packages:
bool
- param gitlab_api_url:
GitLab API v4 base URL (typically from
CI_API_V4_URL)- type gitlab_api_url:
str | None
- param gitlab_project_id:
GitLab project numeric id (typically from
CI_PROJECT_ID)- type gitlab_project_id:
int | None
- param gitlab_token:
GitLab token value (typically from
CI_JOB_TOKEN)- type gitlab_token:
str | None
Usage
multiversion-doc build [OPTIONS]
Options
- -o, --outdir <outdir>
Output directory (docs/build/doc)
- --include-dev, --no-include-dev
If true and current branch is ahead of stable, create dev redirect. (True)
- --min-vers <min_vers>
Minimum version to consider (default: v1.0.0).
- --keep-temp, --no-keep-temp
Do not remove temp dir (for debugging).
- --use-latest-conf, --no-use-latest-conf
Use the latest conf.py for all builds. (True)
- --build-pdf, --no-build-pdf
Also build PDF versions. (False)
- --project-name <project_name>
Project name for PDF index page.
- --use-symlinks, --no-use-symlinks
Use symlinks for stable/dev aliases instead of copying. (True)
- -s, --max-size <max_size>
Maximum artifact size in MB. If exceeded, prune old versions (0 = no limit)
- --zip-filepath <zip_filepath>
Directory where per-tag zip archives are written when –with-zip-file is enabled. (.)
- --with-zip-file, --without-zip-file
Create a per-tag zip archive (mafw-docs-<tag>.zip) for each stable tag under –outdir.
- --with-upload-zip, --without-upload-zip
Upload the per-tag documentation zip to the GitLab Generic Package Registry. Implies –with-zip-file.
- --with-cached-packages, --without-cached-packages
Use cached documentation zip packages from the GitLab Generic Package Registry instead of rebuilding tags.
- --gitlab-api-url <gitlab_api_url>
GitLab API v4 base URL (env: CI_API_V4_URL).
- --gitlab-project-id <gitlab_project_id>
GitLab project numeric id (env: CI_PROJECT_ID).
- --gitlab-token <gitlab_token>
GitLab token value (env: CI_JOB_TOKEN).
Environment variables
- CI_API_V4_URL
Provide a default for
--gitlab-api-url
- CI_PROJECT_ID
Provide a default for
--gitlab-project-id
- CI_JOB_TOKEN
Provide a default for
--gitlab-token
clean
Clean the output directory. TARGET can be ‘all’ (remove everything) or ‘latest’ (remove only latest folder).
- param target:
What to clean - ‘all’ or ‘latest’
- type target:
str
- param outdir:
Output directory to clean
- type outdir:
Path
Usage
multiversion-doc clean [OPTIONS] [[all|latest]]
Options
- -o, --outdir <outdir>
Output directory to clean
Arguments
- TARGET
Optional argument
current
Build documentation only for the current working tree (no git worktrees). Places output in the ‘latest’ folder.
- param outdir:
Output directory for built documentation
- type outdir:
Path
- param build_pdf:
Whether to also build PDF version
- type build_pdf:
bool
- param project_name:
Project name for PDF
- type project_name:
str
- param yes:
Whether to automatically answer yes to prompts
- type yes:
bool
- param from_scratch:
Whether to remove output and generated folders before building
- type from_scratch:
bool
Usage
multiversion-doc current [OPTIONS]
Options
- -o, --outdir <outdir>
Output directory (docs/build/doc)
- --build-pdf, --no-build-pdf
Also build PDF versions. (False)
- -y, --yes
Automatically answer yes to all questions.
- --from-scratch
Remove output and generated folders before building.
landing
Generate root landing page for project.
- param build_root:
Build root directory
- type build_root:
Path
- param project_name:
Project name
- type project_name:
str
Usage
multiversion-doc landing [OPTIONS]
Options
- -b, --build-root <build_root>
Build root directory containing doc/ subdirectory
- --project-name <project_name>
Project name for the landing page
prune
Prune old documentation versions to stay within size limit.
This command removes the oldest version directories (keeping stable, latest, dev) until the total size is below the specified threshold.
- param outdir:
Output directory to prune
- type outdir:
Path
- param max_size:
Maximum size in megabytes
- type max_size:
int
- param dry_run:
Whether to do a dry run
- type dry_run:
bool
- param auto_prune:
Whether to prune automatically without confirmation
- type auto_prune:
bool
Usage
multiversion-doc prune [OPTIONS]
Options
- -o, --outdir <outdir>
Output directory to check
- -s, --max-size <max_size>
Maximum size in MB (default: 100)
- --dry-run, --no-dry-run
Show what would be removed without actually removing
- --auto-prune, --no-auto-prune
Automatically prune without confirmation
redirects
Generate _redirects file for GitLab Pages.
- param outdir:
Output directory for _redirects file
- type outdir:
Path
- param old_pdf_path:
Old PDF URL path to redirect from
- type old_pdf_path:
Path
- param new_pdf_path:
New PDF downloads page to redirect to
- type new_pdf_path:
Path
- param redirect_root:
Whether to redirect /doc/ root to stable
- type redirect_root:
bool
Usage
multiversion-doc redirects [OPTIONS]
Options
- -o, --outdir <outdir>
Output directory for _redirects file
- --old-pdf-path <old_pdf_path>
Old PDF URL path to redirect from
- --new-pdf-path <new_pdf_path>
New PDF downloads page to redirect to
- --redirect-root, --no-redirect-root
Redirect /doc/ root to stable
registry
Interact with the GitLab Generic Package Registry for mafw-docs packages.
The GitLab API configuration is collected from CLI options (or CI env vars) and built lazily by subcommands.
- param ctx:
Click context
- type ctx:
click.Context
- param gitlab_api_url:
GitLab API v4 base URL
- type gitlab_api_url:
str | None
- param gitlab_project_id:
GitLab project numeric id
- type gitlab_project_id:
int | None
- param gitlab_token:
GitLab token value
- type gitlab_token:
str | None
Usage
multiversion-doc registry [OPTIONS] COMMAND [ARGS]...
Options
- --gitlab-api-url <gitlab_api_url>
GitLab API v4 base URL (env: CI_API_V4_URL).
- --gitlab-project-id <gitlab_project_id>
GitLab project numeric id (env: CI_PROJECT_ID).
- --gitlab-token <gitlab_token>
GitLab token value (env: CI_JOB_TOKEN).
Environment variables
- CI_API_V4_URL
Provide a default for
--gitlab-api-url
- CI_PROJECT_ID
Provide a default for
--gitlab-project-id
- CI_JOB_TOKEN
Provide a default for
--gitlab-token
delete
Delete mafw-docs package versions from the registry.
Usage
multiversion-doc registry delete [OPTIONS]
Options
- -f, --file <items>
Version(s) or zip file name(s) to delete (repeatable).
- --all
Delete all mafw-docs versions from the registry.
- --from <from_v>
Delete versions from this tag (inclusive).
- --to <to_v>
Delete versions up to this tag (inclusive).
download
Download documentation zip files from the registry.
Usage
multiversion-doc registry download [OPTIONS]
Options
- --zip-filepath <zip_filepath>
Directory where downloaded zip files are stored. (.)
- -f, --file <items>
Version(s) or zip file name(s) to download (repeatable).
- --all
Download all mafw-docs versions from the registry.
- --from <from_v>
Download versions from this tag (inclusive).
- --to <to_v>
Download versions up to this tag (inclusive).
upload
Upload local documentation zip files to the registry.
Usage
multiversion-doc registry upload [OPTIONS]
Options
- --zip-filepath <zip_filepath>
Directory containing zip files to upload. (.)
- -f, --file <files>
Zip file(s) to upload (repeatable).
- --all
Upload all matching zip files from –zip-filepath.
- --from <from_v>
Upload versions from this tag (inclusive).
- --to <to_v>
Upload versions up to this tag (inclusive).
server
Manage a local web server for browsing documentation over HTTP.
Usage
multiversion-doc server [OPTIONS] COMMAND [ARGS]...
restart
Restart the local documentation server.
Usage
multiversion-doc server restart [OPTIONS]
start
Start a local documentation server (python -m http.server).
Usage
multiversion-doc server start [OPTIONS]
Options
- -b, --bind <address>
IP address to bind (default: 127.0.0.1).
- -p, --port <port>
Port number where to listen (default: 8000).
- -d, --directory <directory>
Folder to serve (default: docs/build).
- -l, --log-file <log_file>
Log file for server output (default: doc-server.log).
- -f, --force-restart
Force restart if already running.
status
Show the current status of the local documentation server.
Usage
multiversion-doc server status [OPTIONS]
stop
Stop the local documentation server.
Usage
multiversion-doc server stop [OPTIONS]
Module Attributes
Click context settings for command line help aliases. |
Functions
|
Create worktree for tag, run sphinx-build, save log. |
|
Build a GitLab API configuration from provided values and environment context. |
|
Build authentication headers for GitLab API requests. |
|
Create worktree for tag, run sphinx-build with latex builder, then make PDF. |
|
Check if multiversion structure exists (other version directories). |
|
Copy patch files needed for older versions. |
|
Create a zip archive for a built documentation version directory. |
Download a documentation zip archive from the GitLab Generic Package Registry. |
|
Ensure that the Sphinx Python package is available. |
|
|
Ensure versions.json exists in outdir. |
|
Extract a documentation zip archive into the repository root and remove the zip. |
|
Keep only the latest micro version per minor (major.minor). |
|
Filter tags based on a regular expression pattern. |
|
Filter versions within an inclusive semantic-version range. |
|
Find the repository root directory. |
|
Format bytes to human-readable size. |
|
Generate an HTML page listing all available PDFs. |
Get the name of the currently checked out branch. |
|
|
Calculate total size of a directory in bytes. |
|
Return list of (Version, tag) tuples sorted ascending. |
|
Get the git revision hash for a given reference. |
|
Return True if commit a is ancestor of commit b (git merge-base --is-ancestor). |
|
List local mafw-docs zip files in a directory. |
|
List generic packages for mafw-docs in the GitLab Package Registry. |
|
Mirror a version directory from one tag to another. |
|
Normalize a registry item into (version, file_name). |
|
Parse and validate a mafw-docs zip filename. |
|
Parse Sphinx build log to extract warning and error counts, and warning messages. |
|
Parse vX.Y.Z(.W) into tuple of ints for sorting. |
|
Remove oldest version directories until total size is below threshold. |
Regenerate versions.json after pruning, excluding removed versions. |
|
|
Report build status with warning/error summary. |
Resolve package IDs for mafw-docs generic packages by version. |
|
|
Helper to run commands with consistent behavior. |
|
Sort tags using semantic versioning comparison. |
Upload a documentation zip archive to the GitLab Generic Package Registry. |
|
|
Create a legacy redirect page at the root of the output directory. |
|
Create a redirect page for a version alias. |
|
Create a _redirects file for GitLab Pages. |
|
Create a landing page for the project root with links to documentation and coverage. |
|
Write versions information to a JSON file. |
Classes
|
Configuration needed to communicate with the GitLab API. |
|
Possible status values for the multiversion-doc local documentation server. |
- class mafw.scripts.doc_versioning.GitlabAPIConfiguration(on_ci: bool, api_url: str, project_id: int, token_type: Literal['job_token', 'api_token'], token: str)[source]
Bases:
objectConfiguration needed to communicate with the GitLab API.
The configuration is typically populated from CI-provided environment variables, but it can also be supplied explicitly when running locally.
- Parameters:
on_ci (bool) – True when the script is running in GitLab CI (
CIenv var set)api_url (str) – Base GitLab API v4 URL (e.g.
https://gitlab.example/api/v4)project_id (int) – GitLab project numeric ID
token_type (Literal['job_token', 'api_token']) – Token kind used for authentication
token (str) – Authentication token value
- class mafw.scripts.doc_versioning.ServerStatusEnum(*values)[source]
Bases:
StrEnumPossible status values for the multiversion-doc local documentation server.
- Variables:
running – The server process exists, matches the expected signature and responds over HTTP.
stale – The server process exists and matches the expected signature, but does not respond over HTTP.
stopped – The recorded PID does not exist or does not match the expected signature.
unknown – The metadata file is missing, so no status can be determined.
- static _generate_next_value_(name, start, count, last_values)
Return the lower-cased version of the member name.
- mafw.scripts.doc_versioning._coerce_with_upload_zip(ctx: Context, param: Parameter, value: bool) bool[source]
Coerce
--with-upload-zipand--with-zip-fileconstraints.If upload is enabled, zip creation is automatically enabled.
- Parameters:
ctx (click.Context) – Click context
param (click.Parameter) – Click parameter being processed
value (bool) – Parsed option value
- Returns:
Option value (possibly coerced)
- Return type:
bool
- mafw.scripts.doc_versioning._coerce_with_zip_file(ctx: Context, param: Parameter, value: bool) bool[source]
Coerce
--with-zip-fileand--with-upload-zipconstraints.If zip creation is disabled, uploading must also be disabled.
- Parameters:
ctx (click.Context) – Click context
param (click.Parameter) – Click parameter being processed
value (bool) – Parsed option value
- Returns:
Option value (possibly coerced)
- Return type:
bool
- mafw.scripts.doc_versioning._format_started_at_utc(now: datetime) str[source]
Format a timestamp for server metadata.
- Parameters:
now (datetime) – A datetime instance (timezone-aware is preferred)
- Returns:
UTC ISO-8601 timestamp with
Zsuffix- Return type:
str
- mafw.scripts.doc_versioning._get_server_status(directory: Path) Tuple[ServerStatusEnum, dict[str, Any] | None][source]
Determine the current server status from metadata and process/HTTP checks.
- Parameters:
directory (Path) – Served directory used to locate the metadata file
- Returns:
Tuple of (status, metadata). Metadata is None when missing.
- Return type:
Tuple[ServerStatusEnum, dict[str, Any] | None]
- mafw.scripts.doc_versioning._http_probe(address: str, port: int, timeout_s: float = 1.0) bool[source]
Probe whether the server responds at the given address:port.
- Parameters:
address (str) – Server address
port (int) – Server port
timeout_s (float) – Timeout in seconds
- Returns:
True if a GET to the server root returns HTTP 200
- Return type:
bool
- mafw.scripts.doc_versioning._import_psutil() Any[source]
Import psutil and provide a user-facing error if it is missing.
The local documentation server management commands rely on psutil for portable process introspection.
- Returns:
Imported psutil module
- Return type:
Any
- Raises:
click.ClickException – If psutil is not installed
- mafw.scripts.doc_versioning._process_matches_http_server(proc: Any, address: str, port: int, directory: Path) bool[source]
Check whether a process resembles the expected http.server invocation.
This function is intentionally tolerant across platforms: it matches based on essential command line tokens rather than requiring an exact list.
- Parameters:
proc (Any) – psutil Process instance
address (str) – Expected bind address
port (int) – Expected port
directory (Path) – Expected served directory
- Returns:
True when the process signature matches
- Return type:
bool
- mafw.scripts.doc_versioning._read_server_metadata(directory: Path) dict[str, Any] | None[source]
Read local documentation server metadata if available.
- Parameters:
directory (Path) – Served directory to locate metadata under
- Returns:
Parsed metadata, or None when the metadata file is missing
- Return type:
dict[str, Any] | None
- Raises:
click.ClickException – If the metadata file exists but cannot be parsed
- mafw.scripts.doc_versioning._registry_build_api_config(ctx: Context) GitlabAPIConfiguration[source]
Build the GitLab API configuration from values stored in the Click context.
- Parameters:
ctx (click.Context) – Click context
- Returns:
GitLab API configuration
- Return type:
- Raises:
click.ClickException – If the configuration is missing
- mafw.scripts.doc_versioning._registry_validate_selection(files: Tuple[str, ...], all_entries: bool, from_v: str | None, to_v: str | None) None[source]
Validate that exactly one selection mode is used for registry commands.
- Parameters:
files (Tuple[str, ...]) – Repeated -f/–file items
all_entries (bool) – Whether –all was provided
from_v (str | None) – Range start
to_v (str | None) – Range end
- Raises:
click.ClickException – If selection is invalid
- mafw.scripts.doc_versioning._server_default_directory() Path[source]
Return the default directory served by the local documentation server.
The default is resolved from the current working directory (typically the repository root).
- Returns:
Default documentation build directory
- Return type:
Path
- mafw.scripts.doc_versioning._server_metadata_path(directory: Path) Path[source]
Return the metadata path associated to a served directory.
- Parameters:
directory (Path) – Served directory
- Returns:
Metadata JSON file path
- Return type:
Path
- mafw.scripts.doc_versioning._server_start_impl(address: str, port: int, directory: Path, log_file: Path, force_restart: bool) None[source]
Implementation for starting a local documentation server.
- Parameters:
address (str) – IP address to bind the server to
port (int) – TCP port number
directory (Path) – Directory to serve over HTTP
log_file (Path) – Log file path for server stdout/stderr
force_restart (bool) – Whether to stop an already running/stale server first
- mafw.scripts.doc_versioning._server_stop_by_metadata(directory: Path, require_metadata: bool) None[source]
Stop the server based on metadata found under a served directory.
- Parameters:
directory (Path) – Served directory used to locate metadata
require_metadata (bool) – If True, missing metadata is treated as an error
- Raises:
click.ClickException – If metadata is required but missing
- mafw.scripts.doc_versioning._write_server_metadata(directory: Path, metadata: dict[str, Any]) None[source]
Write local documentation server metadata.
- Parameters:
directory (Path) – Served directory where metadata is stored
metadata (dict[str, Any]) – Metadata dictionary to serialize as JSON
- Raises:
click.ClickException – If the metadata file cannot be written
- mafw.scripts.doc_versioning.build_for_tag(tag: str, outdir: Path, tmproot: Path, use_latest_conf: bool = False, keep_tmp: bool = False) Tuple[bool, str][source]
Create worktree for tag, run sphinx-build, save log. Returns (success, log_contents).
- Parameters:
tag (str) – Git tag to build documentation for
outdir (Path) – Output directory for built documentation
tmproot (Path) – Root temporary directory
use_latest_conf (bool) – Whether to use latest conf.py, defaults to False
keep_tmp (bool) – Whether to keep temporary files, defaults to False
- Returns:
Tuple of (success, log_contents)
- Return type:
Tuple[bool, str]
- mafw.scripts.doc_versioning.build_gitlab_api_configuration(api_url: str | None, project_id: int | None, token: str | None) GitlabAPIConfiguration[source]
Build a GitLab API configuration from provided values and environment context.
The script detects CI execution by checking the
CIenvironment variable. When running on CI, the token is expected to be a job token.Expected CI environment variables: -
CI_API_V4_URL(API base URL) -CI_PROJECT_ID(project numeric id) -CI_JOB_TOKEN(job token)- Parameters:
api_url (str | None) – API base URL, typically from
CI_API_V4_URLproject_id (int | None) – GitLab project id, typically from
CI_PROJECT_IDtoken (str | None) – Authentication token, typically from
CI_JOB_TOKEN
- Returns:
Fully populated configuration
- Return type:
- Raises:
ValueError – If required values are missing
- mafw.scripts.doc_versioning.build_gitlab_auth_headers(api_config: GitlabAPIConfiguration) dict[str, str][source]
Build authentication headers for GitLab API requests.
This helper uses: -
JOB-TOKENon CI (api_config.on_ciis True) -PRIVATE-TOKENfor local execution- Parameters:
api_config (GitlabAPIConfiguration) – GitLab API configuration
- Returns:
Authentication headers dictionary
- Return type:
dict[str, str]
- mafw.scripts.doc_versioning.build_pdf_for_tag(tag: str, html_tag_dir: Path, tmproot: Path, use_latest_conf: bool = False, keep_tmp: bool = False) Tuple[bool, str, Path | None][source]
Create worktree for tag, run sphinx-build with latex builder, then make PDF. Places PDF in the same directory as the HTML output for that tag. Returns (success, log_contents, pdf_path).
- Parameters:
tag (str) – Git tag to build PDF for
html_tag_dir (Path) – Directory containing HTML output for the tag
tmproot (Path) – Root temporary directory
use_latest_conf (bool) – Whether to use latest conf.py, defaults to False
keep_tmp (bool) – Whether to keep temporary files, defaults to False
- Returns:
Tuple of (success, log_contents, pdf_path)
- Return type:
Tuple[bool, str, Path | None]
- mafw.scripts.doc_versioning.check_multiversion_structure(outdir: Path) bool[source]
Check if multiversion structure exists (other version directories).
- Parameters:
outdir (Path) – Output directory to check
- Returns:
True if other versions exist
- Return type:
bool
- mafw.scripts.doc_versioning.copy_patch_files(docs_src: Path) None[source]
Copy patch files needed for older versions.
- Parameters:
docs_src (Path) – Path to documentation source directory
- mafw.scripts.doc_versioning.create_docs_zip_for_tag(outdir: Path, tag: str, zip_filepath: Path) Path[source]
Create a zip archive for a built documentation version directory.
The built docs are expected under
outdir / tag(e.g.docs/build/doc/vX.Y.Z). The produced zip is laid out so that extracting it from the repository root recreates the original directory structure (e.g.docs/build/doc/vX.Y.Z/...).The zip file is created at
zip_filepath / f"mafw-docs-{tag}.zip".Notes
Symlinks are skipped to avoid ambiguous extraction behavior across platforms.
- param outdir:
Output directory that contains the built docs
- type outdir:
Path
- param tag:
Version tag (e.g.
v2.1.0)- type tag:
str
- param zip_filepath:
Directory where the zip file is written
- type zip_filepath:
Path
- return:
Path to the created zip archive
- rtype:
Path
- raises FileNotFoundError:
If the built docs directory does not exist
- raises NotADirectoryError:
If the built docs path is not a directory
- mafw.scripts.doc_versioning.download_docs_zip_from_gitlab_generic_registry(api_config: GitlabAPIConfiguration, package_version: str, download_dir: Path, package_name: str = 'mafw-docs', file_name: str | None = None, timeout_s: float = 60.0) Path | None[source]
Download a documentation zip archive from the GitLab Generic Package Registry.
The equivalent GitLab API endpoint is:
GET /projects/:id/packages/generic/:package_name/:package_version/:file_nameThe function first issues a HEAD request to determine if the file exists: - 404: the package file does not exist (cache miss) and
Noneis returned. - 200: the file exists and is downloaded. - otherwise: a warning is printed andNoneis returned.Authentication headers: -
JOB-TOKENwhen running on CI (api_config.on_ciis True) -PRIVATE-TOKENfor local execution- Parameters:
api_config (GitlabAPIConfiguration) – GitLab API configuration
package_version (str) – Package version (typically the git tag, e.g.
v2.1.0)download_dir (Path) – Directory where the downloaded zip is stored
package_name (str) – Generic package name, defaults to
mafw-docsfile_name (str | None) – File name to retrieve, defaults to
mafw-docs-<version>.ziptimeout_s (float) – Request timeout in seconds, defaults to 60.0
- Returns:
Path to the downloaded zip archive, or None if it does not exist or cannot be retrieved
- Return type:
Path | None
- mafw.scripts.doc_versioning.ensure_sphinx_build_available() None[source]
Ensure that the Sphinx Python package is available.
doc_versioningis a development helper shipped with MAFw. The script is typically executed from the optional[dev]environment (either by activating the development environment and using the console entry point, or viahatch run dev.py<version>:multidocon CI/CD).Checking for the
sphinx-buildexecutable alone is not sufficient because the effective availability depends on which Python environment is executing the command. Checking the import spec forsphinxvalidates that the correct optional dependencies are installed for the running interpreter.- Raises:
click.ClickException – If Sphinx is not available.
- mafw.scripts.doc_versioning.ensure_versions_json_exists(outdir: Path) bool[source]
Ensure versions.json exists in outdir. If not, try to copy from another version.
- Parameters:
outdir (Path) – Output directory that should contain versions.json
- Returns:
True if versions.json exists or was successfully copied
- Return type:
bool
- mafw.scripts.doc_versioning.extract_docs_zip_to_repo_root(zip_path: Path, repo_root: Path | None = None) None[source]
Extract a documentation zip archive into the repository root and remove the zip.
The zip archive is expected to contain paths rooted at the repository (e.g.
docs/build/doc/vX.Y.Z/...) so that extraction recreates the same structure as a normal documentation build.- Parameters:
zip_path (Path) – Zip archive to extract
repo_root (Path | None) – Repository root directory, defaults to auto-detection
- Raises:
FileNotFoundError – If
zip_pathdoes not existzipfile.BadZipFile – If the archive is invalid
- mafw.scripts.doc_versioning.filter_latest_micro(versions: List[Tuple[Version, Any]]) List[Tuple[Version, Any]][source]
Keep only the latest micro version per minor (major.minor).
- Parameters:
versions (List[Tuple[Version, Any]]) – List of (Version, tag) tuples
- Returns:
Filtered list of (Version, tag) tuples
- Return type:
List[Tuple[Version, Any]]
- mafw.scripts.doc_versioning.filter_stable_tags(tags: List[str], regex: str) List[str][source]
Filter tags based on a regular expression pattern.
- Parameters:
tags (List[str]) – List of tag strings to filter
regex (str) – Regular expression pattern to match against
- Returns:
Filtered list of matching tags
- Return type:
List[str]
- mafw.scripts.doc_versioning.filter_versions_in_range(versions: List[str], from_v: str | None, to_v: str | None) List[str][source]
Filter versions within an inclusive semantic-version range.
- Parameters:
versions (List[str]) – Input versions list
from_v (str | None) – Range start (inclusive)
to_v (str | None) – Range end (inclusive)
- Returns:
Filtered versions list
- Return type:
List[str]
- Raises:
ValueError – If range bounds are invalid
- mafw.scripts.doc_versioning.find_repo_root(start: Path | None = None) Path[source]
Find the repository root directory.
The root is detected by walking upwards until a
pyproject.tomlfile is found. If no such file is found, the starting directory is returned.- Parameters:
start (Path | None) – Directory from which to start searching, defaults to current working directory
- Returns:
Resolved repository root directory
- Return type:
Path
- mafw.scripts.doc_versioning.format_size(bytes_size: float) str[source]
Format bytes to human-readable size.
- Parameters:
bytes_size (int) – Size in bytes
- Returns:
Formatted size string
- Return type:
str
- mafw.scripts.doc_versioning.generate_pdf_index_page(html_outdir: Path, pdf_info: List[dict[str, str]], project_name: str = 'Documentation') None[source]
Generate an HTML page listing all available PDFs. This page will be placed in the root html_versions directory. Order: stable first, then latest, then other releases sorted by version (newest first).
- Parameters:
html_outdir (Path) – Output directory for HTML files
pdf_info (List[dict[str, str]]) – List of dictionaries containing PDF information
project_name (str) – Name of the project for the page title, defaults to ‘Documentation’
- mafw.scripts.doc_versioning.get_current_branch() str[source]
Get the name of the currently checked out branch.
- Returns:
Name of the current branch
- Return type:
str
- mafw.scripts.doc_versioning.get_directory_size(path: Path) int[source]
Calculate total size of a directory in bytes.
- Parameters:
path (Path) – Directory path
- Returns:
Total size in bytes
- Return type:
int
- mafw.scripts.doc_versioning.get_git_tags(min_version: str | None = None) List[Tuple[Version, Any]][source]
Return list of (Version, tag) tuples sorted ascending.
- Parameters:
min_version (str | None) – Minimum version to consider, defaults to None
- Returns:
List of (Version, tag) tuples
- Return type:
List[Tuple[Version, Any]]
- mafw.scripts.doc_versioning.git_rev_of(ref: str) str[source]
Get the git revision hash for a given reference.
- Parameters:
ref (str) – Git reference (tag, branch, commit hash)
- Returns:
Git revision hash
- Return type:
str
- Raises:
RuntimeError – If git rev-list fails
- mafw.scripts.doc_versioning.is_ancestor(a: str, b: str) bool[source]
Return True if commit a is ancestor of commit b (git merge-base –is-ancestor).
- Parameters:
a (str) – First commit reference
b (str) – Second commit reference
- Returns:
True if a is ancestor of b
- Return type:
bool
- mafw.scripts.doc_versioning.iter_local_mafw_docs_zips(zip_dir: Path) List[Tuple[str, Path]][source]
List local mafw-docs zip files in a directory.
Only files matching
mafw-docs-vX.Y.Z.zipare returned.- Parameters:
zip_dir (Path) – Directory to scan
- Returns:
List of (version, file_path) tuples
- Return type:
List[Tuple[str, Path]]
- mafw.scripts.doc_versioning.list_mafw_docs_generic_packages(api_config: GitlabAPIConfiguration, package_name: str = 'mafw-docs') List[dict[str, Any]][source]
List generic packages for mafw-docs in the GitLab Package Registry.
Uses the Packages API:
GET /projects/:id/packagesand filters forpackage_type=genericand exactname == package_name.- Parameters:
api_config (GitlabAPIConfiguration) – GitLab API configuration
package_name (str) – Package name, defaults to
mafw-docs
- Returns:
List of package dictionaries from the API
- Return type:
List[dict[str, Any]]
- mafw.scripts.doc_versioning.mirror_version(outdir: Path, src_tag: str, target_tag: str, use_symlink: bool = True) None[source]
Mirror a version directory from one tag to another. Can use symlinks for efficiency or copy for compatibility.
- Parameters:
outdir (Path) – Output directory containing version directories
src_tag (str) – Source tag directory name
target_tag (str) – Target tag directory name
use_symlink (bool) – Whether to use symlink instead of copying, defaults to True
- mafw.scripts.doc_versioning.normalize_registry_item(item: str) Tuple[str, str][source]
Normalize a registry item into (version, file_name).
The item can be either: - a version string:
vX.Y.Z- a file name:mafw-docs-vX.Y.Z.zip- Parameters:
item (str) – Input item
- Returns:
Tuple of (version, file_name)
- Return type:
Tuple[str, str]
- Raises:
ValueError – If the item cannot be normalized
- mafw.scripts.doc_versioning.parse_mafw_docs_zip_filename(file_name: str) Tuple[str, str] | None[source]
Parse and validate a mafw-docs zip filename.
The accepted filename pattern is:
mafw-docs-vX.Y.Z.zip.- Parameters:
file_name (str) – File name to parse
- Returns:
Tuple of (version, normalized_file_name) if valid, otherwise None
- Return type:
Tuple[str, str] | None
- mafw.scripts.doc_versioning.parse_sphinx_log(log_content: str) Tuple[int, int, List[str]][source]
Parse Sphinx build log to extract warning and error counts, and warning messages.
Only three warnings are reported
- Parameters:
log_content (str) – Sphinx build log
- Returns:
Tuple of warning, error count, warning messages
- Return type:
Tuple[int, int, List[str]]
- mafw.scripts.doc_versioning.parse_version_tuple(tag: str) Tuple[int, ...][source]
Parse vX.Y.Z(.W) into tuple of ints for sorting.
- Parameters:
tag (str) – Version tag string
- Returns:
Tuple of integers representing the version
- Return type:
Tuple[int, …]
- mafw.scripts.doc_versioning.prune_old_versions(outdir: Path, max_size_mb: int = 100, dry_run: bool = False) Tuple[List[str], int][source]
Remove oldest version directories until total size is below threshold. Always keeps ‘stable’, ‘latest’, and ‘dev’ (if present).
- Parameters:
outdir (Path) – Output directory containing version directories
max_size_mb (int) – Maximum size in megabytes
dry_run (bool) – If True, only report what would be deleted
- Returns:
Tuple of (list of removed versions, final size in bytes)
- Return type:
Tuple[List[str], int]
- mafw.scripts.doc_versioning.regenerate_versions_json_after_pruning(outdir: Path, removed_versions: List[str]) None[source]
Regenerate versions.json after pruning, excluding removed versions.
- Parameters:
outdir (Path) – Output directory containing version directories
removed_versions (List[str]) – List of version names that were removed
- mafw.scripts.doc_versioning.report_build_status(tag: str, success: bool, log: str, build_type: str = 'HTML') None[source]
Report build status with warning/error summary.
- Parameters:
tag (str) – Version tag being built
success (bool) – Whether build succeeded
log (str) – Build log content
build_type (str) – Type of build (HTML or PDF)
- mafw.scripts.doc_versioning.resolve_mafw_docs_package_ids_by_version(api_config: GitlabAPIConfiguration, package_name: str = 'mafw-docs') dict[str, int][source]
Resolve package IDs for mafw-docs generic packages by version.
- Parameters:
api_config (GitlabAPIConfiguration) – GitLab API configuration
package_name (str) – Package name, defaults to
mafw-docs
- Returns:
Mapping from version string to package id
- Return type:
dict[str, int]
- mafw.scripts.doc_versioning.run(cmd: List[str], cwd: Path | None = None) CompletedProcess[str][source]
Helper to run commands with consistent behavior.
- Parameters:
cmd (List[str]) – Command to execute as a list of strings
cwd (Path | None) – Working directory for command execution, defaults to None
- Returns:
Completed process result
- Return type:
subprocess.CompletedProcess[str]
- mafw.scripts.doc_versioning.sort_tags_semver(tags: List[str]) List[str][source]
Sort tags using semantic versioning comparison.
- Parameters:
tags (List[str]) – List of tag strings to sort
- Returns:
Sorted list of tag strings
- Return type:
List[str]
- mafw.scripts.doc_versioning.upload_docs_zip_to_gitlab_generic_registry(api_config: GitlabAPIConfiguration, package_version: str, zip_path: Path, package_name: str = 'mafw-docs', timeout_s: float = 60.0) bool[source]
Upload a documentation zip archive to the GitLab Generic Package Registry.
The equivalent GitLab API endpoint is:
PUT /projects/:id/packages/generic/:package_name/:package_version/:file_nameAuthentication headers: -
JOB-TOKENwhen running on CI (api_config.on_ciis True) -PRIVATE-TOKENfor local execution- Parameters:
api_config (GitlabAPIConfiguration) – GitLab API configuration
package_version (str) – Package version (typically the git tag, e.g.
v2.1.0)zip_path (Path) – Path to the zip file to upload
package_name (str) – Generic package name, defaults to
mafw-docstimeout_s (float) – Request timeout in seconds, defaults to 60.0
- Returns:
True if the file was uploaded, False if the upload was skipped because the target already exists
- Return type:
bool
- Raises:
FileNotFoundError – If
zip_pathdoes not existRuntimeError – If the upload fails (non-2xx response)
- mafw.scripts.doc_versioning.write_legacy_redirect_page(outdir: Path) None[source]
Create a legacy redirect page at the root of the output directory.
- Parameters:
outdir (Path) – Output directory for the redirect page
- mafw.scripts.doc_versioning.write_redirect_page(outdir: Path, name: str, target_tag: str) None[source]
Create a redirect page for a version alias.
- Parameters:
outdir (Path) – Output directory for the redirect page
name (str) – Name of the redirect alias (e.g., ‘stable’, ‘dev’)
target_tag (str) – Tag that the redirect should point to
- mafw.scripts.doc_versioning.write_redirects_file(outdir: Path) None[source]
Create a _redirects file for GitLab Pages.
- Parameters:
outdir (Path) – Output directory for the redirects file
- mafw.scripts.doc_versioning.write_root_landing_page(build_root: Path, project_name: str = 'MAFw') None[source]
Create a landing page for the project root with links to documentation and coverage.
- Parameters:
build_root (Path) – Root build directory (should contain ‘doc’ subdirectory)
project_name (str) – Project name for the page title
- mafw.scripts.doc_versioning.write_versions_json(outdir: Path, versions: List[dict[str, str]]) None[source]
Write versions information to a JSON file.
- Parameters:
outdir (Path) – Output directory for the JSON file
versions (List[dict[str, str]]) – List of version information dictionaries
- mafw.scripts.doc_versioning.CONTEXT_SETTINGS = {'help_option_names': ['-h', '--help']}
Click context settings for command line help aliases.