diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..62416da --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,63 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Commands + +```sh +make deps # Install dev dependencies (uv sync --dev --frozen) +make check # Full check: fmt + lint + test + test-e2e +make check-static # fmt + lint only +make fmt # Run ruff formatter +make lint # Run mypy + ruff + uv lock check +make lint-mypy # Type check only (args= supported) +make test # Run unit tests (args= supported) +make test-e2e # Run e2e tests (requires tool installed) +make docs-watch # Local docs server +``` + +Run a single test: +```sh +uv run --frozen pytest tests/path/to/test_file.py::test_name +``` + +Run CLI during development: +```sh +uv run nava-platform +``` + +## Architecture + +Entry point: `nava/platform/cli/__main__.py` → `cli/main.py` builds a `typer.Typer` with two sub-apps: `infra` and `app`. + +**Layer structure:** + +- `nava/platform/cli/` — CLI layer (typer commands, context, console, logging, config) + - `commands/infra/` — `install`, `update`, `add-app`, `info`, `migrate-from-legacy` subcommands + - `commands/app.py` — app-level subcommands +- `nava/platform/templates/` — core template logic + - `template.py` — `Template` class wraps copier; handles copy/update against a project + - `infra_template.py` — infra-specific template operations + - `state.py` — reads/writes `.nava` answer files that track installed template versions + - `template_name.py` — parses template name from URI +- `nava/platform/projects/` — project/app abstractions (`Project`, `InfraProject`) +- `nava/platform/copier_worker.py` — `NavaWorker` extends copier's `Worker` to support `src_exclude` filtering _before_ template rendering (upstream only filters after) +- `nava/platform/util/` — git helpers, wrappers, collections + +**Key data flow:** CLI command → `CliContext` (log, console, output level) → `Template`/`InfraTemplate` → `NavaWorker` (wraps copier) → writes files to project dir + updates `.nava` state files. + +**State tracking:** Installed template versions are stored in `.nava/` answer files within target projects, not in this repo. + +**Copier pin:** `copier` is pinned to a specific git commit in `pyproject.toml` because a later commit breaks `NavaWorker`'s `src_exclude` setup. + +## Testing + +- Unit tests: `tests/` — mirrors `nava/` package structure +- E2e tests: `tests-e2e/` — shell scripts requiring the tool to be installed; `bin/test-e2e` orchestrates them +- `conftest.py` at `tests/` root contains shared fixtures + +## Linting + +- `ruff` for formatting and linting (line length 100, Google docstring convention) +- `mypy` in strict mode with `local_partial_types = true`; tests exempt from typed def requirements +- In CI, `make fmt` runs with `--check` and `make lint` runs without `--fix` diff --git a/README.md b/README.md index ce4d7cd..2faf531 100644 --- a/README.md +++ b/README.md @@ -218,6 +218,7 @@ nava-platform infra install ./just-a-test For comprehensive guides on using the platform CLI with existing projects: - [Getting Started Guide](./docs/getting-started/index.md) - [New Project Setup](./docs/getting-started/new-project.md) +- [Working with an Existing Template](./docs/getting-started/working-with-existing-template.md) - [Migrating from Legacy Template](./docs/getting-started/migrating-from-legacy-template.md) ### Shell Completion diff --git a/docs/getting-started/.pages b/docs/getting-started/.pages index 2fbd1b6..0e1eeab 100644 --- a/docs/getting-started/.pages +++ b/docs/getting-started/.pages @@ -2,3 +2,4 @@ nav: - index.md - migrating-from-legacy-template.md - new-project.md + - working-with-existing-template.md diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md index 7056e8f..3c9ec75 100644 --- a/docs/getting-started/index.md +++ b/docs/getting-started/index.md @@ -3,4 +3,6 @@ For projects using the legacy install/update scripts, see [Migrating old templates to Nava Platform CLI](./migrating-from-legacy-template.md). -For starting a new project, see [Starting a new project](./new-project.md) +For starting a new project, see [Starting a new project](./new-project.md). + +For developing or testing changes to an app template locally, see [Working with an existing template](./working-with-existing-template.md). diff --git a/docs/getting-started/working-with-existing-template.md b/docs/getting-started/working-with-existing-template.md new file mode 100644 index 0000000..f7ebec1 --- /dev/null +++ b/docs/getting-started/working-with-existing-template.md @@ -0,0 +1,131 @@ +# Working with an existing app template + +This guide covers how to develop and test changes to an app template (e.g., `template-application-rails`, `template-application-flask`) and apply those changes to a project using the Platform CLI. + +## How template versioning works + +The Platform CLI uses [Copier](https://copier.readthedocs.io/en/stable/) under the hood, which relies on **Git tags** for version resolution. When you run an `install` or `update` command, the CLI clones the template repository and **checks out the latest tagged version** by default — not `main` or any other branch. + +This means: + +- **Tags are the source of truth.** The CLI will not pick up commits on `main` unless those commits are included in a tagged release. +- **A new tag must be created** in the template repository for the CLI to recognize and install new changes. +- Tags should follow [PEP 440](https://peps.python.org/pep-0440/) versioning (e.g., `v0.1.0`, `v0.2.0`). Non-compliant tags are ignored during version resolution. + +> [!IMPORTANT] +> Simply merging changes to `main` in a template repository is **not sufficient** for those changes to be picked up by the CLI. A new version tag must be pushed to the repository. + +### Example: releasing a new template version + +After merging your changes to the template's `main` branch: + +```sh +# In the template repository +git tag v0.3.0 +git push origin v0.3.0 +``` + +Projects can then pick up this version: + +```sh +nava-platform app update . myapp +``` + +## Developing with a local template + +When working on template changes, you don't need to push to a remote or create tags. The CLI supports pointing directly at a **local directory** and a specific **branch or ref**, which is ideal for development and testing. + +### Setting up a local checkout + +Clone the app template repository (or use an existing clone): + +```sh +git clone https://github.com/navapbc/template-application-rails ~/templates/template-application-rails +``` + +Create a branch for your changes: + +```sh +cd ~/templates/template-application-rails +git checkout -b my-feature-branch +``` + +Make your template changes and commit them. + +> [!NOTE] +> Template changes must be committed to your local branch. Copier works from Git history, so uncommitted changes will not be applied. + +### Using a Git worktree (alternative) + +If you'd rather keep your default branch intact, you can use a [Git worktree](https://git-scm.com/docs/git-worktree) instead of a new clone: + +```sh +cd ~/templates/template-application-rails +git worktree add ../template-application-rails-feature my-feature-branch +``` + +This creates a separate working directory at `../template-application-rails-feature` checked out to `my-feature-branch`, while leaving your original clone on its current branch. + +### Installing from a local template + +Use `--template-uri` to point to your local checkout, and `--version` to specify the branch: + +```sh +nava-platform app install \ + --template-uri ~/templates/template-application-rails \ + --version my-feature-branch \ + --commit \ + . myapp +``` + +### Updating from a local template + +Similarly, to update an existing project using your local template changes: + +```sh +nava-platform app update \ + --template-uri ~/templates/template-application-rails \ + --version my-feature-branch \ + --commit \ + . myapp +``` + +> [!TIP] +> Use `--version HEAD` to always apply the latest commit on the default branch of your local checkout, regardless of tags. + +### Key CLI options for local development + +| Option | Description | +|---|---| +| `--template-uri` | Path or URL to the template source. Can be a local path (e.g., `~/templates/template-application-rails`) or a remote URL. | +| `--version` | Template version to use. Accepts a branch name, tag, commit hash, or `HEAD`. Defaults to the latest tag. | +| `--template-name` | Override the template name if your local directory has a different name than the upstream repository (e.g., if your worktree folder is named differently). | +| `--commit` | Automatically commit the generated changes with a standard message. | + +## Infra template local development + +The infra template works the same way. The default `--template-uri` for `infra` commands is `https://github.com/navapbc/template-infra`, but you can override it: + +```sh +nava-platform infra install \ + --template-uri ~/templates/template-infra \ + --version my-feature-branch \ + --commit \ + . myapp +``` + +```sh +nava-platform infra update \ + --template-uri ~/templates/template-infra \ + --version my-feature-branch \ + . +``` + +## Summary + +| Scenario | What to do | +|---|---| +| Use the latest released template version | Just run `install` or `update` — the CLI defaults to the latest tag. | +| Release a new template version for all projects | Tag a new version in the template repo and push it. | +| Test local template changes during development | Use `--template-uri` pointed at your local clone and `--version` set to your branch. | +| Always use the latest commit (skip tag resolution) | Pass `--version HEAD`. |