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 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

CONTEXT_SETTINGS

Click context settings for command line help aliases.

Functions

build_for_tag(tag, outdir, tmproot[, ...])

Create worktree for tag, run sphinx-build, save log.

build_gitlab_api_configuration(api_url, ...)

Build a GitLab API configuration from provided values and environment context.

build_gitlab_auth_headers(api_config)

Build authentication headers for GitLab API requests.

build_pdf_for_tag(tag, html_tag_dir, tmproot)

Create worktree for tag, run sphinx-build with latex builder, then make PDF.

check_multiversion_structure(outdir)

Check if multiversion structure exists (other version directories).

copy_patch_files(docs_src)

Copy patch files needed for older versions.

create_docs_zip_for_tag(outdir, tag, ...)

Create a zip archive for a built documentation version directory.

download_docs_zip_from_gitlab_generic_registry(...)

Download a documentation zip archive from the GitLab Generic Package Registry.

ensure_sphinx_build_available()

Ensure that the Sphinx Python package is available.

ensure_versions_json_exists(outdir)

Ensure versions.json exists in outdir.

extract_docs_zip_to_repo_root(zip_path[, ...])

Extract a documentation zip archive into the repository root and remove the zip.

filter_latest_micro(versions)

Keep only the latest micro version per minor (major.minor).

filter_stable_tags(tags, regex)

Filter tags based on a regular expression pattern.

filter_versions_in_range(versions, from_v, to_v)

Filter versions within an inclusive semantic-version range.

find_repo_root([start])

Find the repository root directory.

format_size(bytes_size)

Format bytes to human-readable size.

generate_pdf_index_page(html_outdir, pdf_info)

Generate an HTML page listing all available PDFs.

get_current_branch()

Get the name of the currently checked out branch.

get_directory_size(path)

Calculate total size of a directory in bytes.

get_git_tags([min_version])

Return list of (Version, tag) tuples sorted ascending.

git_rev_of(ref)

Get the git revision hash for a given reference.

is_ancestor(a, b)

Return True if commit a is ancestor of commit b (git merge-base --is-ancestor).

iter_local_mafw_docs_zips(zip_dir)

List local mafw-docs zip files in a directory.

list_mafw_docs_generic_packages(api_config)

List generic packages for mafw-docs in the GitLab Package Registry.

mirror_version(outdir, src_tag, target_tag)

Mirror a version directory from one tag to another.

normalize_registry_item(item)

Normalize a registry item into (version, file_name).

parse_mafw_docs_zip_filename(file_name)

Parse and validate a mafw-docs zip filename.

parse_sphinx_log(log_content)

Parse Sphinx build log to extract warning and error counts, and warning messages.

parse_version_tuple(tag)

Parse vX.Y.Z(.W) into tuple of ints for sorting.

prune_old_versions(outdir[, max_size_mb, ...])

Remove oldest version directories until total size is below threshold.

regenerate_versions_json_after_pruning(...)

Regenerate versions.json after pruning, excluding removed versions.

report_build_status(tag, success, log[, ...])

Report build status with warning/error summary.

resolve_mafw_docs_package_ids_by_version(...)

Resolve package IDs for mafw-docs generic packages by version.

run(cmd[, cwd])

Helper to run commands with consistent behavior.

sort_tags_semver(tags)

Sort tags using semantic versioning comparison.

upload_docs_zip_to_gitlab_generic_registry(...)

Upload a documentation zip archive to the GitLab Generic Package Registry.

write_legacy_redirect_page(outdir)

Create a legacy redirect page at the root of the output directory.

write_redirect_page(outdir, name, target_tag)

Create a redirect page for a version alias.

write_redirects_file(outdir)

Create a _redirects file for GitLab Pages.

write_root_landing_page(build_root[, ...])

Create a landing page for the project root with links to documentation and coverage.

write_versions_json(outdir, versions)

Write versions information to a JSON file.

Classes

GitlabAPIConfiguration(on_ci, api_url, ...)

Configuration needed to communicate with the GitLab API.

ServerStatusEnum(*values)

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: object

Configuration 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 (CI env 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: StrEnum

Possible 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-zip and --with-zip-file constraints.

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-file and --with-upload-zip constraints.

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 Z suffix

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:

GitlabAPIConfiguration

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 CI environment 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_URL

  • project_id (int | None) – GitLab project id, typically from CI_PROJECT_ID

  • token (str | None) – Authentication token, typically from CI_JOB_TOKEN

Returns:

Fully populated configuration

Return type:

GitlabAPIConfiguration

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-TOKEN on CI (api_config.on_ci is True) - PRIVATE-TOKEN for 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_name

The function first issues a HEAD request to determine if the file exists: - 404: the package file does not exist (cache miss) and None is returned. - 200: the file exists and is downloaded. - otherwise: a warning is printed and None is returned.

Authentication headers: - JOB-TOKEN when running on CI (api_config.on_ci is True) - PRIVATE-TOKEN for 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-docs

  • file_name (str | None) – File name to retrieve, defaults to mafw-docs-<version>.zip

  • timeout_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_versioning is 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 via hatch run dev.py<version>:multidoc on CI/CD).

Checking for the sphinx-build executable alone is not sufficient because the effective availability depends on which Python environment is executing the command. Checking the import spec for sphinx validates 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_path does not exist

  • zipfile.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.toml file 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.zip are 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/packages and filters for package_type=generic and exact name == 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_name

Authentication headers: - JOB-TOKEN when running on CI (api_config.on_ci is True) - PRIVATE-TOKEN for 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-docs

  • timeout_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_path does not exist

  • RuntimeError – 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.