Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ and versions are tracked in the repo-root `VERSION` file.

- Initialized the repository with the Base-managed repo baseline.
- Added the Northstar reference consumer with nested status and release commands.
- Added a five-minute scenario-driven learning path with CI-checked command examples.
22 changes: 13 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,33 @@ after its dependencies are installed.
From a fresh checkout:

```bash
python3 -m venv .venv
$ python3 -m venv .venv
. .venv/bin/activate
python -m pip install .
northstar --help
northstar --quiet status
$ python -m pip install .
$ northstar --help
$ northstar --quiet status
```

The default environment is `dev`. Select another fixture environment with the
framework lifecycle option:

```bash
northstar --quiet --environment staging status
northstar --quiet --environment dev status --format json
northstar --quiet --environment dev release plan --version 2.5.0
northstar --quiet --environment dev --dry-run release reconcile --version 2.5.0 --format json
$ northstar --quiet --environment staging status
$ northstar --quiet --environment dev status --format json
$ northstar --quiet --environment dev release plan --version 2.5.0
$ northstar --quiet --environment dev --dry-run release reconcile --version 2.5.0 --format json
```

Base-CLI also provides the optional versioned lifecycle envelope:

```bash
northstar --quiet --environment dev --json status --format json
$ northstar --quiet --environment dev --json status --format json
```

For a guided five-minute walkthrough with expected output and the framework
boundary explained beside each scenario, see the
[scenario-driven learning path](docs/learning-path.md).

## What this demonstrates

- `northstar status` reads consumer-owned, deterministic service fixtures.
Expand Down
118 changes: 118 additions & 0 deletions docs/learning-path.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Five-minute Base-CLI learning path

Northstar is a small, offline reference consumer. The goal of this guide is
to show where an application uses Base-CLI and where the application keeps its
own domain behavior.

The examples use the published `base-cli` dependency declared by this
repository. They do not require Base, Docker, cloud credentials, or network
access after installation.

## 1. Install the consumer

From a fresh checkout, create an environment and install the demo with its
development checks:

```console
$ python3 -m venv .venv
$ . .venv/bin/activate
$ python -m pip install ".[dev]"
```

The package exposes the `northstar` command. Confirm that the nested command
tree and lifecycle options are available:

```console
$ northstar --help
Usage: northstar [OPTIONS] COMMAND [ARGS]...
```

The help text also lists `status`, `release`, `--environment`, `--dry-run`,
and the other lifecycle options.

## 2. Run a human-oriented snapshot

Start with the default `dev` fixture environment:

```console
$ northstar --quiet status
orders-api ready 2.4.0 commerce
billing-worker ready 1.8.2 finance
web degraded 3.1.0 commerce
```

The service records and their schema are Northstar behavior. Base-CLI supplies
the invocation lifecycle, context, logging, runtime directory, cleanup, and
output boundary around that behavior.

## 3. Request automation-friendly output

The `--format` option is consumer-owned, while rendering is delegated to the
public Base-CLI output API:

```console
$ northstar --quiet --environment staging release plan --service orders-api --version 2.5.0 --format json
[{"environment":"staging","service":"orders-api","current_version":"2.3.9","target_version":"2.5.0","action":"update"}]
```

Use `--format csv`, `--format tsv`, `--format yaml`, or `--format ndjson` for
other automation boundaries. The command stays deterministic because its
input is the packaged local fixture.

## 4. Explore a nested workflow safely

`release reconcile` represents a state-changing workflow without performing
an external change. Add the Base-CLI lifecycle flag to see the dry-run
contract explicitly:

```console
$ northstar --quiet --environment dev --dry-run release reconcile --version 2.5.0 --format json
[{"environment":"dev","services":3,"target_version":"2.5.0","action":"would-reconcile","external_changes":false}]
```

The same command without `--dry-run` reports `"action":"reconciled"`, but it
still changes no external system. This is a teaching fixture, not a cloud
provider adapter.

## 5. See the lifecycle envelope

Automation can opt into the versioned Base-CLI success/error envelope:

```console
$ northstar --quiet --environment dev --json status --format json
{"schema_version":1,"schema":"base-cli.output","code":"ok",...}
```

The `run_id` is unique for each invocation, so it is intentionally abbreviated
above. The stable fields are the schema name, success code, exit code, and the
consumer command's serialized stdout. Use the unwrapped `--format json` form
when an integration needs only the command records.

## Read the boundary in the code

Open `src/base_cli_demo/cli.py` while following the examples:

- `cli`, `status`, `release`, `plan`, and `reconcile` are the consumer-owned
Click command tree.
- `_load_services` and `_services_for_environment` define the local fixture
model and selection policy.
- `base_cli.App`, `base_cli.CliProfile.generic()`,
`base_cli.LifecycleOptions`, `base_cli.get_current_context()`, and
`base_cli.render_records` are the public framework boundary.
- The demo does not import private Base-CLI modules and does not make Base
repository conventions mandatory.

For deeper framework context, continue with the Base-CLI
[API reference](https://github.com/basefoundry/base-cli/blob/main/docs/api-reference.md),
[consumer profiles](https://github.com/basefoundry/base-cli/blob/main/docs/consumer-profiles.md),
[output contracts](https://github.com/basefoundry/base-cli/blob/main/docs/output-contracts.md),
[JSON contracts](https://github.com/basefoundry/base-cli/blob/main/docs/json-contracts.md),
and [testing guide](https://github.com/basefoundry/base-cli/blob/main/docs/testing.md).

## Current behavior and future scope

Everything demonstrated here is available in the released `base-cli` line
declared in `pyproject.toml`. Future Base-CLI ecosystem capabilities such as
Catalog discovery, cross-CLI metadata, and universal multi-language
conformance are deliberately not part of this learning path. They should be
documented here only after their contracts are released and documented.
37 changes: 37 additions & 0 deletions tests/test_documentation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from __future__ import annotations

import re
import shlex
import tempfile
from pathlib import Path

import base_cli
import pytest

from base_cli_demo.cli import command


COMMAND_PATTERN = re.compile(r"^\$\s+(northstar(?:\s+.*)?)$")
DOCUMENTS = (Path("README.md"), Path("docs/learning-path.md"))


def documented_commands() -> list[tuple[str, list[str]]]:
examples: list[tuple[str, list[str]]] = []
for document in DOCUMENTS:
for line in document.read_text(encoding="utf-8").splitlines():
match = COMMAND_PATTERN.match(line)
if match:
examples.append((str(document), shlex.split(match.group(1))))
return examples


@pytest.mark.parametrize(
("document", "args"), documented_commands(), ids=lambda value: str(value)
)
def test_documented_northstar_commands_are_executable(
document: str, args: list[str]
) -> None:
with tempfile.TemporaryDirectory() as directory:
result = base_cli.testing.invoke(command, args[1:], home=Path(directory))

assert result.exit_code == 0, f"{document}: {args!r}\n{result.output}"
Loading