From 0da9e5bb28e44b0d3cb609fa7f6644021e2f1124 Mon Sep 17 00:00:00 2001 From: Ramesh Padmanabhaiah <22363102+codeforester@users.noreply.github.com> Date: Wed, 5 Aug 2026 20:27:40 -0700 Subject: [PATCH 1/2] docs: publish MkDocs site --- .github/workflows/docs.yml | 81 ++++++++++++++++++++++++++++ CHANGELOG.md | 5 ++ README.md | 33 ++++++------ SECURITY.md | 8 +-- docs/adopter-readiness.md | 8 +-- docs/index.md | 71 ++++++++++++++++++++++++ docs/releasing.md | 12 +++++ mkdocs.yml | 53 ++++++++++++++++++ pyproject.toml | 4 ++ scripts/validate_package_artifact.py | 3 ++ tests/validate.sh | 3 ++ 11 files changed, 258 insertions(+), 23 deletions(-) create mode 100644 .github/workflows/docs.yml create mode 100644 docs/index.md create mode 100644 mkdocs.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..75e0118 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,81 @@ +name: Documentation + +on: + push: + branches: + - main + paths: + - "README.md" + - "SECURITY.md" + - "docs/**" + - "mkdocs.yml" + - "pyproject.toml" + - "scripts/validate_docs.py" + - "tests/validate.sh" + - ".github/workflows/docs.yml" + pull_request: + paths: + - "README.md" + - "SECURITY.md" + - "docs/**" + - "mkdocs.yml" + - "pyproject.toml" + - "scripts/validate_docs.py" + - "tests/validate.sh" + - ".github/workflows/docs.yml" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: Build and validate documentation + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out source + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Set up Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.13" + + - name: Install documentation tools + run: python -m pip install ".[docs]" + + - name: Validate repository links and examples + run: python scripts/validate_docs.py + + - name: Configure GitHub Pages + uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0 + + - name: Build documentation with strict warnings + run: python -m mkdocs build --strict --site-dir site + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4.0.0 + with: + path: site + + deploy: + name: Deploy documentation site + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + needs: build + runs-on: ubuntu-latest + timeout-minutes: 10 + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + permissions: + pages: write + id-token: write + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@f33f41b675f0ab2dc5a6863c9a170fe83af3571e # v4.0.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 816cc4e..4627684 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -98,6 +98,11 @@ the API stability policy and migration guide before upgrading from `0.3.x`. ## [Unreleased] +### Added + +- Add the MkDocs documentation site configuration, strict documentation checks, + and GitHub Pages deployment workflow. + ### Changed - Reclassify the project as Beta in package metadata to reflect its documented diff --git a/README.md b/README.md index 7622f54..19a34b3 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,9 @@ Install it with: python -m pip install base-cli ``` +Read the complete documentation at +. + ## Quick start Create a small command with a consistent context, logging, and cleanup @@ -47,7 +50,7 @@ Run it with `python hello.py --name Ada`. The full lifecycle and configuration options are documented below. Release builds, TestPyPI rehearsals, and protected PyPI publication are -documented in [`docs/releasing.md`](docs/releasing.md). The package exposes +documented in [`docs/releasing.md`](https://basefoundry.github.io/base-cli/releasing/). The package exposes `base_cli.__version__`, which matches the distribution version. The package is distributed under the Apache License 2.0. Base itself remains @@ -71,33 +74,33 @@ execution, while `base_cli` provides reusable lifecycle behavior: - test helpers built on Click's `CliRunner` Typer applications can opt into the same lifecycle with the optional -`base-cli[typer]` extra. See [`docs/typer-adapter.md`](docs/typer-adapter.md) +`base-cli[typer]` extra. See [`docs/typer-adapter.md`](https://basefoundry.github.io/base-cli/typer-adapter/) for the migration path; Typer remains optional and is never imported by the core Click integration. Automation-facing JSON output, errors, and logs are opt-in through the -versioned contracts documented in [`docs/json-contracts.md`](docs/json-contracts.md). +versioned contracts documented in [`docs/json-contracts.md`](https://basefoundry.github.io/base-cli/json-contracts/). Human output and Click error behavior remain the default. The supported public facade, compatibility promises, deprecation warning mechanism, and migration requirements are documented in -[`docs/api-stability.md`](docs/api-stability.md) and -[`docs/migrations.md`](docs/migrations.md). +[`docs/api-stability.md`](https://basefoundry.github.io/base-cli/api-stability/) and +[`docs/migrations.md`](https://basefoundry.github.io/base-cli/migrations/). Security reporting, runtime trust boundaries, threat assumptions, and the release security checklist are documented in [`SECURITY.md`](SECURITY.md), -[`docs/security-threat-model.md`](docs/security-threat-model.md), and -[`docs/security-review.md`](docs/security-review.md). +[`docs/security-threat-model.md`](https://basefoundry.github.io/base-cli/security-threat-model/), and +[`docs/security-review.md`](https://basefoundry.github.io/base-cli/security-review/). Shared record renderers keep machine output stable: CSV and TSV stream one-pass iterables without headers or footers, while terminal tables account for Unicode display width and safely truncate oversized cells. See -[`docs/output-contracts.md`](docs/output-contracts.md) for the output rules and +[`docs/output-contracts.md`](https://basefoundry.github.io/base-cli/output-contracts/) for the output rules and deterministic width controls. Optional Rich tables and OpenTelemetry lifecycle spans are available through separate extras; they are never imported or required by the default install. -See [`docs/integrations.md`](docs/integrations.md) for opt-in configuration and +See [`docs/integrations.md`](https://basefoundry.github.io/base-cli/integrations/) for opt-in configuration and graceful-degradation behavior. ## Design Goals @@ -141,7 +144,7 @@ The generic profile has no manifest filename convention, no product-owned configuration directory, and no implicit history writer. Applications can provide those policies through callbacks or build their own profile. The consumer-owned adapters should supply any product-specific policies. See -[`docs/consumer-profiles.md`](docs/consumer-profiles.md) for the boundary and +[`docs/consumer-profiles.md`](https://basefoundry.github.io/base-cli/consumer-profiles/) for the boundary and migration guidance. ### Typed extension contracts @@ -190,7 +193,7 @@ can opt into `base_cli.ExtensionDiscovery`. It recognizes the documented `base_cli.commands`, `base_cli.profiles`, and `base_cli.plugins` entry-point groups. Discovery is lazy and cached, duplicate names fail explicitly, broken extensions are isolated by `load_all()`, and consumers can disable discovery or -provide an allowlist. See [`docs/extensions.md`](docs/extensions.md) for the +provide an allowlist. See [`docs/extensions.md`](https://basefoundry.github.io/base-cli/extensions/) for the entry-point contracts and deterministic ordering rules. ## Public API @@ -199,7 +202,7 @@ The supported facade is `import base_cli`. It exports the command lifecycle (`App`, `Context`, `run_app`, decorators, and logging helpers), command filters, and the structured command protocol helpers. Consumer-owned user configuration is passed through `Context.user_config`; the library does not impose a schema. -See [`docs/user-config-typing.md`](docs/user-config-typing.md) for the +See [`docs/user-config-typing.md`](https://basefoundry.github.io/base-cli/user-config-typing/) for the intentional opaque boundary and the recommended typed accessor pattern. The corresponding modules are also available as `base_cli.command_filters`, `base_cli.command_protocol`, and @@ -230,7 +233,7 @@ Typer, and automation/observability flows; each example has its own packaging, tests, completion, release, and troubleshooting guidance. Teams evaluating adoption can follow the [adopter readiness and migration -guide](docs/adopter-readiness.md) and run the three independent +guide](https://basefoundry.github.io/base-cli/adopter-readiness/) and run the three independent [downstream compatibility consumers](compatibility/README.md). ## Minimal Command @@ -538,7 +541,7 @@ Every `base_cli.App` command gets these options: - `--log-file `: write the persistent log to a specific file. - `--version`: shown when the `App` was created with a version. - `--json`: opt-in machine output, when `LifecycleOptions.json` is enabled; - emits the versioned envelopes described in [`docs/json-contracts.md`](docs/json-contracts.md). + emits the versioned envelopes described in [`docs/json-contracts.md`](https://basefoundry.github.io/base-cli/json-contracts/). `LifecycleOptions()` preserves this default set. Its `debug`, `quiet`, `environment`, `config`, `keep_temp`, `log_file`, and `version` fields are @@ -986,7 +989,7 @@ On POSIX, base-cli enforces owner-only `0600`/`0700` modes. On Windows, the default user-local cache root relies on inherited user-profile ACLs; consumers using a custom cache root must provide the appropriate ACL themselves. -See [Platform support](docs/platform-support.md) for the supported Linux, +See [Platform support](https://basefoundry.github.io/base-cli/platform-support/) for the supported Linux, WSL2, macOS, and native Windows boundaries. Native Windows support covers the generic `base-cli` framework; it does not imply native Windows support for Base or `basectl`. diff --git a/SECURITY.md b/SECURITY.md index 33ddd99..aa07523 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ `base-cli` is a library for embedding a lifecycle into Python command-line applications. We take reports about the framework, its release artifacts, and -the security controls documented in the [runtime threat model](docs/security-threat-model.md) +the security controls documented in the [runtime threat model](https://basefoundry.github.io/base-cli/security-threat-model/) seriously. ## Reporting a vulnerability @@ -40,7 +40,7 @@ changes the supported window will update this table and the changelog. | `main` | Supported for fixes merged before the next release | | `<0.3` | Upgrade strongly recommended; best effort only | -The [API stability policy](docs/api-stability.md) explains the pre-1.0 +The [API stability policy](https://basefoundry.github.io/base-cli/api-stability/) explains the pre-1.0 compatibility boundary. A security fix may require an emergency breaking change when leaving a vulnerable behavior in place would expose users. @@ -68,6 +68,6 @@ The framework protects the lifecycle data it owns: argv redaction, private runtime files, fail-closed temporary cleanup, bounded JSON contracts, and opt-in telemetry with a safe attribute set. It does not sandbox consumer callbacks, third-party plugins, Python dependencies, shell commands, or the -operating system. Consumers must review the [threat model](docs/security-threat-model.md) -and complete the [security review checklist](docs/security-review.md) for their +operating system. Consumers must review the [threat model](https://basefoundry.github.io/base-cli/security-threat-model/) +and complete the [security review checklist](https://basefoundry.github.io/base-cli/security-review/) for their own profile, plugins, paths, history writer, and telemetry exporter. diff --git a/docs/adopter-readiness.md b/docs/adopter-readiness.md index 9e0bf19..6da2b4d 100644 --- a/docs/adopter-readiness.md +++ b/docs/adopter-readiness.md @@ -29,7 +29,7 @@ box below: - [ ] Publish an owner, escalation path, and a redacted support bundle format. The maintainable downstream fixtures in -[`compatibility/consumers`](../compatibility/README.md) are the executable +[compatibility consumers](https://github.com/basefoundry/base-cli/tree/main/compatibility/consumers) are the executable version of this checklist. ## Migration path @@ -58,13 +58,13 @@ version of this checklist. For public API and deprecation rules, see [`api-stability.md`](api-stability.md) and [`migrations.md`](migrations.md). The four framework reference applications -show copy-pasteable packaging patterns in [`examples/README.md`](../examples/README.md). +show copy-pasteable packaging patterns in the [reference application catalog](https://github.com/basefoundry/base-cli/blob/main/examples/README.md). ## Support channel -Use the repository's [Adoption support issue template](../.github/ISSUE_TEMPLATE/support.md) +Use the repository's [Adoption support issue template](https://github.com/basefoundry/base-cli/blob/main/.github/ISSUE_TEMPLATE/support.md) for migration questions, compatibility failures, and redacted reproductions. -Security reports must follow [`SECURITY.md`](../SECURITY.md), not a public issue. +Security reports must follow [`SECURITY.md`](https://github.com/basefoundry/base-cli/blob/main/SECURITY.md), not a public issue. Include the framework version, Python/platform, installed dependency versions, command shape (with secrets removed), exit code, and a support bundle path. Maintainers triage adoption issues during normal project work and link any diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..b768bc9 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,71 @@ +# base-cli + +`base-cli` is a small, consumer-neutral Python framework for writing +professional command-line applications. It gives commands a consistent +lifecycle, context, logging, cleanup, configuration, and test boundary while +leaving application policy in the consuming project. + +## Quick start + +Install the package: + +```bash +python -m pip install base-cli +``` + +Create a command: + +```python +from __future__ import annotations + +import base_cli + + +app = base_cli.App(name="hello", version="0.1.0") + + +@app.command() +@base_cli.option("--name", default="world", show_default=True) +def hello(ctx: base_cli.Context, name: str) -> int: + ctx.log.info("greeting %s", name) + print(f"Hello, {name}!") + return base_cli.ExitCode.SUCCESS + + +if __name__ == "__main__": + raise SystemExit(base_cli.run_app(app)) +``` + +Run it with: + +```bash +python hello.py --name Ada +``` + +The command receives a context with structured logging, per-run paths, +configuration, environment metadata, and deterministic cleanup. The same +lifecycle can be attached to an existing Click tree or an optional Typer +application. + +## Choose a path + +- Start with the [adopter readiness guide](adopter-readiness.md) for a + production evaluation. +- Read [API stability](api-stability.md) and the [migration guide](migrations.md) + before upgrading across a compatibility boundary. +- Follow [consumer profiles](consumer-profiles.md) when your application owns + project discovery or configuration policy. +- Use the [Typer adapter](typer-adapter.md) to bring an existing Typer command + tree under the same lifecycle. +- Review the [JSON contracts](json-contracts.md) and [output contracts](output-contracts.md) + before building automation around command output. + +## Design principles + +`base-cli` is intentionally thin: Click owns parsing and command execution, +while the framework supplies reusable lifecycle behavior. It avoids import-time +filesystem writes, keeps logs on stderr, preserves application-owned state, +and treats optional integrations as explicit extras. + +See the [repository README](https://github.com/basefoundry/base-cli#readme) for +the full API overview, reference applications, and installation examples. diff --git a/docs/releasing.md b/docs/releasing.md index 819fc79..8cc9e1c 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -31,6 +31,18 @@ cleanup. The publish job downloads that same reviewed artifact; it does not rebuild during publication. +## Documentation site + +The Documentation workflow builds this site with `mkdocs build --strict` and +publishes the reviewed site to GitHub Pages after changes land on `main`. The +canonical URL is and is exposed in +the PyPI project metadata as the `Documentation` link. + +Repository administrators should enable GitHub Pages for the repository using +the GitHub Actions source and approve the `github-pages` environment the first +time the workflow deploys. Pull requests run the strict build and repository +link checks without publishing. + ## TestPyPI rehearsal 1. Dispatch **Package** from the branch or tag to be rehearsed and choose diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..8a41d82 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,53 @@ +site_name: base-cli +site_description: A small, consumer-neutral Python framework for professional command-line applications. +site_url: https://basefoundry.github.io/base-cli/ +repo_name: basefoundry/base-cli +repo_url: https://github.com/basefoundry/base-cli +edit_uri: edit/main/docs/ + +theme: + name: material + features: + - navigation.sections + - navigation.top + - search.highlight + - search.share + icon: + repo: fontawesome/brands/github + +plugins: + - search + +markdown_extensions: + - admonition + - attr_list + - pymdownx.highlight + - pymdownx.superfences + - pymdownx.tabbed: + alternate_style: true + - toc: + permalink: true + +nav: + - Home: index.md + - Getting started: + - Adopter readiness: adopter-readiness.md + - Platform support: platform-support.md + - Consumer profiles: consumer-profiles.md + - API and contracts: + - API stability: api-stability.md + - Migration guide: migrations.md + - Output contracts: output-contracts.md + - JSON contracts: json-contracts.md + - Typed user configuration: user-config-typing.md + - Entry-point extensions: extensions.md + - Integrations: + - Typer adapter: typer-adapter.md + - Optional integrations: integrations.md + - Operations and security: + - Local configuration: local-config.md + - Cache ownership and layout: cache-ownership-and-layout.md + - Performance: performance.md + - Runtime threat model: security-threat-model.md + - Security release review: security-review.md + - Releasing base-cli: releasing.md diff --git a/pyproject.toml b/pyproject.toml index ae9a162..adc372c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,11 +60,15 @@ quality = [ "pytest-cov>=5,<7", "ruff>=0.8,<1", ] +docs = [ + "mkdocs-material>=9.5,<10", +] [project.urls] Homepage = "https://github.com/basefoundry/base-cli" Repository = "https://github.com/basefoundry/base-cli" Issues = "https://github.com/basefoundry/base-cli/issues" +Documentation = "https://basefoundry.github.io/base-cli/" [tool.setuptools] package-dir = {"" = "lib/python"} diff --git a/scripts/validate_package_artifact.py b/scripts/validate_package_artifact.py index d43b3df..de1cabb 100644 --- a/scripts/validate_package_artifact.py +++ b/scripts/validate_package_artifact.py @@ -17,6 +17,7 @@ IMPORT_NAME = "base_cli" MINIMUM_PYTHON = ">=3.10" REQUIRED_DEPENDENCIES = ("click>=8.1", "PyYAML>=6.0") +DOCUMENTATION_URL = "Documentation, https://basefoundry.github.io/base-cli/" ALLOWED_WHEEL_DIST_INFO_FILES = frozenset({"METADATA", "RECORD", "WHEEL", "top_level.txt", "entry_points.txt"}) ALLOWED_SDIST_FILES = frozenset( { @@ -88,6 +89,8 @@ def validate_wheel(path: Path, expected_version: str, package_files: set[str]) - for dependency in REQUIRED_DEPENDENCIES: if dependency not in dependencies: fail(f"{path.name} is missing runtime dependency {dependency!r}") + if DOCUMENTATION_URL not in metadata.get_all("Project-URL", []): + fail(f"{path.name} is missing the canonical Documentation project URL") if f"{IMPORT_NAME}/py.typed" not in names: fail(f"{path.name} does not contain {IMPORT_NAME}/py.typed") diff --git a/tests/validate.sh b/tests/validate.sh index 8b63b60..925c781 100755 --- a/tests/validate.sh +++ b/tests/validate.sh @@ -8,7 +8,9 @@ required_files=( CONTRIBUTING.md .github/pull_request_template.md .github/base-project.yml + .github/workflows/docs.yml LICENSE + mkdocs.yml base_manifest.yaml .github/workflows/issue-branch-policy.yml .github/workflows/project-intake.yml @@ -18,6 +20,7 @@ required_files=( .github/workflows/compatibility.yml .github/ISSUE_TEMPLATE/support.md docs/releasing.md + docs/index.md docs/api-stability.md docs/user-config-typing.md docs/migrations.md From 666141c66f67316306777450379a0d2dd93577c0 Mon Sep 17 00:00:00 2001 From: Ramesh Padmanabhaiah <22363102+codeforester@users.noreply.github.com> Date: Wed, 5 Aug 2026 20:29:21 -0700 Subject: [PATCH 2/2] ci: configure Pages only during deployment --- .github/workflows/docs.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 75e0118..1c86ab4 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -52,9 +52,6 @@ jobs: - name: Validate repository links and examples run: python scripts/validate_docs.py - - name: Configure GitHub Pages - uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0 - - name: Build documentation with strict warnings run: python -m mkdocs build --strict --site-dir site @@ -76,6 +73,9 @@ jobs: pages: write id-token: write steps: + - name: Configure GitHub Pages + uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0 + - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@f33f41b675f0ab2dc5a6863c9a170fe83af3571e # v4.0.0