Skip to content

Commit a89f90f

Browse files
authored
docs: add five-minute consumer quickstart (#351)
Fixes #344
1 parent 5fe19da commit a89f90f

5 files changed

Lines changed: 118 additions & 0 deletions

File tree

‎docs/consumer-quickstart.md‎

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Five-minute consumer quickstart
2+
3+
This is the smallest useful `base-cli` application: one public `App`, one
4+
command, one option, and the `run_app()` process boundary. It is suitable for
5+
a temporary consumer project and does not require Typer, Rich, YAML, or any
6+
private repository layout.
7+
8+
## Install and create the command
9+
10+
Use an isolated virtual environment when trying the recipe. Activate it using
11+
the command appropriate for your shell, then install the core package:
12+
13+
```bash
14+
python -m venv .venv
15+
python -m pip install base-cli
16+
```
17+
18+
Create `hello.py`:
19+
20+
```python
21+
from __future__ import annotations
22+
23+
import base_cli
24+
25+
26+
app = base_cli.App(
27+
name="hello",
28+
lifecycle_options=base_cli.LifecycleOptions(
29+
json=base_cli.LifecycleOption("--json"),
30+
),
31+
)
32+
33+
34+
@app.command()
35+
@base_cli.option("--name", default="world", show_default=True)
36+
def hello(ctx: base_cli.Context, name: str) -> int:
37+
ctx.log.info("greeting %s", name)
38+
print(f"Hello, {name}!")
39+
return base_cli.ExitCode.SUCCESS
40+
41+
42+
if __name__ == "__main__":
43+
raise SystemExit(base_cli.run_app(app))
44+
```
45+
46+
The recipe uses only the public `base_cli` facade. Click remains the parser,
47+
while the consumer owns the command and its application behavior.
48+
49+
## Run it in human mode
50+
51+
```bash
52+
python hello.py --name Ada
53+
```
54+
55+
The command prints `Hello, Ada!` on stdout. The greeting log is on stderr, so a
56+
consumer can redirect or suppress logs without corrupting command output.
57+
58+
## Run the same command as JSON
59+
60+
The recipe explicitly enables the optional lifecycle `--json` flag. Capture and
61+
parse the one JSON envelope like this:
62+
63+
```bash
64+
python hello.py --json --name Ada > result.json
65+
python -m json.tool result.json
66+
```
67+
68+
The success payload has `schema: "base-cli.output"`, `code: "ok"`, and a
69+
`details.stdout` string containing the command's human output. The `run_id` is
70+
runtime data and should not be hard-coded. Logs and diagnostics remain on
71+
stderr. See [JSON contracts](json-contracts.md) for the complete success,
72+
usage-error, and unexpected-error boundary.
73+
74+
## What to validate
75+
76+
The focused consumer checks are the two invocations above: confirm the human
77+
stdout and the JSON parse independently, and confirm that the process exit
78+
status is zero. For a repository change, run the focused documentation test
79+
with `python -m pytest tests/test_consumer_quickstart_docs.py` and run
80+
`git diff --check`.
81+
82+
The core package requires Click and Python 3.10 or newer. Install
83+
`base-cli[yaml]` only when the consumer selects YAML configuration or output;
84+
Typer and other integrations are separate optional boundaries. See
85+
[dependency support](dependency-support.md) and [output contracts](output-contracts.md)
86+
before adding those integrations.

‎docs/index.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ application.
5656

5757
- Use the [framework choice guide](framework-choice.md) to compare base-cli
5858
with the underlying parser and decide whether its lifecycle boundary fits.
59+
- Follow the [five-minute consumer quickstart](consumer-quickstart.md) for a
60+
minimal public `App`, `run_app()`, human output, and JSON invocation.
5961
- Start with the [adopter readiness guide](adopter-readiness.md) for a
6062
production evaluation.
6163
- See the [adoption and compatibility evidence guide](adoption-evidence.md)

‎mkdocs.yml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ nav:
3333
- Validation: testing.md
3434
- Getting started:
3535
- Framework choice: framework-choice.md
36+
- Consumer quickstart: consumer-quickstart.md
3637
- Adopter readiness: adopter-readiness.md
3738
- Adoption evidence: adoption-evidence.md
3839
- Compatibility dashboard: compatibility-dashboard.md

‎scripts/validate_docs.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"cache-ownership-and-layout.md",
2020
"compatibility-dashboard.md",
2121
"consumer-profiles.md",
22+
"consumer-quickstart.md",
2223
"coverage-policy.md",
2324
"dependency-support.md",
2425
"extensions.md",
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from pathlib import Path
2+
3+
ROOT = Path(__file__).parents[1]
4+
DOC = ROOT / "docs" / "consumer-quickstart.md"
5+
INDEX = ROOT / "docs" / "index.md"
6+
VALIDATOR = ROOT / "scripts" / "validate_docs.py"
7+
8+
9+
def test_consumer_quickstart_is_linked_from_the_documentation_index() -> None:
10+
assert "consumer-quickstart.md" in INDEX.read_text(encoding="utf-8")
11+
assert "consumer-quickstart.md" in VALIDATOR.read_text(encoding="utf-8")
12+
13+
14+
def test_consumer_quickstart_uses_only_public_apis_and_explains_both_modes() -> None:
15+
text = DOC.read_text(encoding="utf-8")
16+
17+
for required in (
18+
"base_cli.App",
19+
"base_cli.LifecycleOptions",
20+
'base_cli.LifecycleOption("--json")',
21+
"base_cli.run_app(app)",
22+
"python hello.py --name Ada",
23+
"python hello.py --json --name Ada",
24+
"base-cli.output",
25+
"dependency-support.md",
26+
"output-contracts.md",
27+
):
28+
assert required in text

0 commit comments

Comments
 (0)