Skip to content
Merged
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
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -132,17 +132,17 @@ docs-trees: ## Regenerate tree blocks in documentation
uv run python scripts/gen_tree_docs.py

docs: ensure-docs-coverage-report ## Build documentation
uv run mkdocs build --config-file=config/mkdocs.yml
uv run properdocs build --config-file=config/mkdocs.yml

docs-serve: ensure-docs-coverage-report ## Serve documentation locally
uv run mkdocs serve --config-file=config/mkdocs.yml
uv run properdocs serve --config-file=config/mkdocs.yml

docs-serve-open: ensure-docs-coverage-report ## Serve documentation and open in default browser
@(sleep 2 && uv run python -m webbrowser "http://127.0.0.1:8000") &
uv run mkdocs serve --config-file=config/mkdocs.yml
uv run properdocs serve --config-file=config/mkdocs.yml

docs-check: ensure-docs-coverage-report ## Check documentation for issues
uv run mkdocs build --config-file=config/mkdocs.yml --strict
uv run properdocs build --config-file=config/mkdocs.yml --strict

check-docs: docs-check ## Alias for docs-check

Expand Down
1 change: 1 addition & 0 deletions config/coverage.ini
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ omit =
src/repoman/__init__.py
src/repoman/__main__.py
src/repoman/main_template/*
src/repoman/cpp_template/template/*
tests/__init__.py
tests/conftest.py

Expand Down
17 changes: 10 additions & 7 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@ repoman inspect --path ./my-project --answers ./my-project/custom-answers.yml

### create

Create a new Python project using the repoman template. For the default (interactive or answers-based) flow, use options; project name is passed with `--project_name` / `-pn`. Alternatively, use a subcommand (e.g. `create cli`) and pass the project name as a positional argument.
Create a new project using a bundled repoman template. For the default (interactive or answers-based) flow, use options; project name is passed with `--project_name` / `-pn`. Alternatively, use a subcommand (e.g. `create cli`) and pass the project name as a positional argument.

```bash
repoman create [OPTIONS]
# or with a preset subcommand (positional project name):
repoman create cli PROJECT_NAME [OPTIONS]
repoman create cli cli PROJECT_NAME [OPTIONS]
```

**Options (default create)**
Expand All @@ -79,7 +79,7 @@ repoman create cli PROJECT_NAME [OPTIONS]
| `--template` | `-t` | Path to custom template (defaults to bundled main template) |
| `--output` | `-o` | Output directory (defaults to current directory) |
| `--answers` | `-a` | Path to answers file for non-interactive use |
| `--preset` | `-p` | Use a preset: `cli`, `docs-only`, `library`, `fastapi` (non-interactive) |
| `--preset` | `-p` | Use a preset: `cli`, `cpp`, `docs-only`, `library`, `fastapi` (non-interactive) |
| `--force` | `-f` | Force overwrite of existing files |
| `--dry-run` | | Show what would be created without creating |

Expand All @@ -90,6 +90,7 @@ repoman create --project_name my-new-project
repoman create -pn my-app --output /path/to/parent --force
repoman create --project_name my-app --answers .copier-answers.yml --dry-run
repoman create -pn my-app --preset cli
repoman create -pn my-lib --preset cpp
```

**Create subcommands (preset-based, positional project name)**
Expand All @@ -99,17 +100,19 @@ Each subcommand creates a project using a preset and takes the project name as a
| Subcommand | Preset | Description |
| ---------- | -------- | -------------------------------------------------------- |
| `create cli` | cli | Plain CLI project (no FastAPI or dataset) |
| `create cpp` | cpp | Meson-based C++ library project |
| `create docs` | docs_only| Documentation-only project |
| `create library` | library | Library-style project (no CLI entry point) |
| `create fastapi` | fastapi | Project with FastAPI enabled |

**Examples (subcommands)**

```bash
repoman create cli my-cli-app
repoman create library my-lib --dry-run
repoman create docs docs-project --output /path/to/parent
repoman create fastapi my-api
repoman create cli cli my-cli-app
repoman create cpp cpp my-cpp-lib
repoman create library library my-lib --dry-run
repoman create docs docs-only docs-project --output /path/to/parent
repoman create fastapi fastapi my-api
```

### update
Expand Down
2 changes: 1 addition & 1 deletion docs/concepts/generated-project.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Generated projects typically include:

- `src/<package>/` for the main Python package
- `tests/` for pytest-based tests
- `config/` for Ruff, MyPy, pytest, MkDocs, and related config
- `config/` for Ruff, MyPy, pytest, ProperDocs, and related config
- `docs/` for project documentation
- `make_cmds/` for Makefile fragments
- `pyproject.toml` for package metadata and dependencies
Expand Down
2 changes: 1 addition & 1 deletion docs/development/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Welcome to the repoman development environment! This guide will help you set up
- **[Code Quality](code-quality.md)** — Linting (Ruff), type checking (MyPy)
- **[CLI messages](cli-messages.md)** — Centralized error/warning message text and panels
- **[Config validation](config-validation.md)** — Pydantic-based answers validation flow
- **[Documentation](documentation.md)** — MkDocs, Material theme, building docs
- **[Documentation](documentation.md)** — ProperDocs, Material for MkDocs theme, building docs
- **[CI](ci.md)** — Continuous integration and local simulation
- **[Debugging](debugging.md)** — Common issues and debug tools
- **[Performance Tips](performance-tips.md)** — Fast development workflow
Expand Down
2 changes: 1 addition & 1 deletion docs/development/additional-resources.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
- **[uv Documentation](https://docs.astral.sh/uv/)**: uv package manager guide
- **[Pytest Documentation](https://docs.pytest.org/)**: Testing framework guide
- **[Ruff Documentation](https://docs.astral.sh/ruff/)**: Linting and formatting guide
- **[MkDocs Documentation](https://www.mkdocs.org/)**: Static site generator guide
- **[ProperDocs Documentation](https://properdocs.org/)**: Static site generator guide
- **[Material for MkDocs](https://squidfunk.github.io/mkdocs-material/)**: Theme documentation
- **[mkdocstrings Documentation](https://mkdocstrings.github.io/)**: API documentation generator

Expand Down
6 changes: 3 additions & 3 deletions docs/development/documentation.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Documentation

The project uses **MkDocs** with the **Material theme** for documentation. This provides a modern, responsive documentation site with excellent features like search, navigation, and code highlighting.
The project uses **ProperDocs** with the **Material for MkDocs theme** for documentation. This provides a modern, responsive documentation site with excellent features like search, navigation, and code highlighting.

## Documentation Structure

Expand Down Expand Up @@ -59,7 +59,7 @@ docs
```
<!-- TREE_END -->

MkDocs is configured in `config/mkdocs.yml` (in the repo root). The `docs_dir` points to this `docs/` folder.
ProperDocs is configured in `config/mkdocs.yml` (in the repo root). The `docs_dir` points to this `docs/` folder.

## Documentation map

Expand Down Expand Up @@ -104,7 +104,7 @@ flowchart LR
update --> troubleshooting
```

## MkDocs Configuration
## ProperDocs Configuration

The documentation is configured in `config/mkdocs.yml` with the following features:

Expand Down
10 changes: 5 additions & 5 deletions docs/development/tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,10 @@ format:
uv run ruff format src/ tests/

docs:
uv run mkdocs build --config-file=config/mkdocs.yml
uv run properdocs build --config-file=config/mkdocs.yml

docs-serve:
uv run mkdocs serve --config-file=config/mkdocs.yml
uv run properdocs serve --config-file=config/mkdocs.yml

clean:
rm -rf build/ dist/ *.egg-info/ .pytest_cache/ htmlcov/ site/
Expand All @@ -130,11 +130,11 @@ To add documentation commands to your Makefile, add these lines:
# Documentation #
#######################
docs: ## Build documentation
uv run mkdocs build --config-file=config/mkdocs.yml
uv run properdocs build --config-file=config/mkdocs.yml

docs-serve: ## Serve documentation locally
uv run mkdocs serve --config-file=config/mkdocs.yml
uv run properdocs serve --config-file=config/mkdocs.yml

docs-check: ## Check documentation for issues
uv run mkdocs build --config-file=config/mkdocs.yml --strict
uv run properdocs build --config-file=config/mkdocs.yml --strict
```
15 changes: 15 additions & 0 deletions docs/template-prompts.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,18 @@ When `dataset_enabled` is true, at least one dataset modality must be selected.
## Where answers are stored

Generated projects store answers in `.copier-answers.yml`. Repoman uses that file for `repoman update` and for non-interactive workflows.

## C++ template prompts

The bundled C++ template lives in `src/repoman/cpp_template/` and is selected
with `--preset cpp` or `repoman create cpp cpp`. In addition to project, author,
repository, and license metadata, it prompts for:

| Prompt | Description | Default |
| -------------------- | -------------------------------------- | ------------------------- |
| `cpp_namespace` | C++ namespace and public include dir | project name with `_` |
| `cpp_library_name` | Meson library target name | project name with `_` |
| `cpp_standard` | C++ language standard | `c++17` |
| `cpp_build_cli` | Build the example CLI executable | `true` |
| `cpp_build_examples` | Build example programs | `true` |
| `cpp_build_tests` | Build test executables | `true` |
18 changes: 18 additions & 0 deletions docs/template-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- **Datasets:** If `dataset_enabled` is true, the template generates `config/dataset_config.json`, `src/{{ python_package_import_name }}/config/dataset_config.py`, and the selected dataset loaders/adapters under `src/{{ python_package_import_name }}/datasets/`.
- **Docs-only:** If `docs_only` is true, source package and test files are omitted.
- **Notebooks:** If `python_notebooks` is true, the template generates a `notebooks/` folder.
- **C++:** The bundled `cpp_template` is a separate Meson-based template with `include/`, `src/`, `tests/`, `examples/`, Doxygen hooks, and the same repoman Make target names used by CI.

## High-level generated layout

Expand Down Expand Up @@ -40,3 +41,20 @@ my_project/
- **`src/<package>/datasets/`** contains the selected dataset loaders and helpers when dataset support is enabled.

For prompt-level details, see [Template prompts](template-prompts.md). For generated behavior, see [Template architecture](concepts/template-architecture.md).

## C++ generated layout

The `cpp` preset and `create cpp cpp` subcommand use `src/repoman/cpp_template/`.
The generated project looks like:

```text
my_cpp_library/
├── config/
├── docs/
├── examples/
├── include/
│ └── <namespace>/
├── scripts/
├── src/
└── tests/
```
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,11 @@ docs = [
"mkdocs-literate-nav>=0.6.1",
"mkdocs-minify-plugin>=0.8.0",
"mkdocs-jupyter>=0.24.8",
"mkdocs>=1.6.1",
"mkdocstrings[python]>=1.0.0",
"mkdocs-table-reader-plugin>=3.1.0",
"mkdocs-charts-plugin>=0.0.13",
"pymdown-extensions>=10.12",
"mkdocs-material>=9.7.6",
"properdocs>=1.6.7",
]


31 changes: 20 additions & 11 deletions src/repoman/cli/commands/create/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from repoman.cli.commands.create._shared import run_create
from repoman.cli.commands.create.cli_only import app as cli_only_app
from repoman.cli.commands.create.cpp import app as cpp_app
from repoman.cli.commands.create.docs_only import app as docs_only_app
from repoman.cli.commands.create.fastapi_mvc import app as fastapi_mvc_app
from repoman.cli.commands.create.library import app as library_app
Expand All @@ -18,6 +19,7 @@
app = Typer(add_completion=True)

app.add_typer(cli_only_app, name="cli")
app.add_typer(cpp_app, name="cpp")
app.add_typer(docs_only_app, name="docs")
app.add_typer(library_app, name="library")
app.add_typer(fastapi_mvc_app, name="fastapi")
Expand Down Expand Up @@ -59,7 +61,7 @@ def create(
Option(
"--preset",
"-p",
help="Use a preset: cli, docs-only, library, fastapi",
help="Use a preset: cli, cpp, docs-only, library, fastapi",
),
] = None,
dry_run: Annotated[
Expand All @@ -69,12 +71,14 @@ def create(
) -> None:
"""Create a new Python project using the repoman template.

Use a preset, a typed subcommand (cli, docs, library, fastapi), or an answers file.
Use a preset, a typed subcommand (cli, cpp, docs, library, fastapi), or an answers file.

Examples:
repoman create -pn my-app --preset cli
repoman create -pn my-lib --preset cpp
repoman create -pn my-app --preset fastapi -o ~/projects
repoman create cli cli my-app
repoman create cpp cpp my-lib
repoman create fastapi fastapi my-app --force
repoman create -pn my-app -a ./my-answers.yml
"""
Expand All @@ -93,16 +97,11 @@ def create(
)
raise Exit(1) from None

if template_path is None:
current_file = Path(__file__)
template_path_obj = current_file.parent.parent.parent.parent
logger.info(f"Using main template at {template_path_obj}")
else:
template_path_obj = Path(template_path)

output_dir_base = Path.cwd() if output_dir is None else Path(output_dir)

if answers_file is not None:
template_path_obj = Path(__file__).parent.parent.parent.parent if template_path is None else Path(template_path)
logger.info(f"Using main template at {template_path_obj}")
answers_path = Path(answers_file).resolve()
if not answers_path.exists():
console.print(error_panel(answers_file_not_found(answers_path), console=console))
Expand All @@ -112,17 +111,27 @@ def create(
data = yaml.safe_load(f) or {}
elif preset is not None:
preset_key = preset.replace("-", "_") # docs-only -> docs_only
valid = ("cli", "docs_only", "library", "fastapi")
valid = ("cli", "cpp", "docs_only", "library", "fastapi")
if preset_key not in valid:
console.print(
error_panel(
f"Invalid preset '{preset}'. Choose from: cli, docs-only, library, fastapi",
f"Invalid preset '{preset}'. Choose from: cli, cpp, docs-only, library, fastapi",
console=console,
)
)
raise Exit(1) from None
if template_path is None and preset_key == "cpp":
template_path_obj = Path(__file__).parent.parent.parent.parent / "cpp_template"
logger.info(f"Using C++ template at {template_path_obj}")
else:
template_path_obj = (
Path(__file__).parent.parent.parent.parent if template_path is None else Path(template_path)
)
logger.info(f"Using main template at {template_path_obj}")
data = build_preset_data(preset_key, project_name)
else:
template_path_obj = Path(__file__).parent.parent.parent.parent if template_path is None else Path(template_path)
logger.info(f"Using main template at {template_path_obj}")
data = None

run_create(
Expand Down
58 changes: 58 additions & 0 deletions src/repoman/cli/commands/create/cpp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"""C++ create subcommand: Meson-based C++ library."""

from pathlib import Path
from typing import Annotated

from typer import Argument, Option, Typer

from repoman.cli.commands.create._shared import run_create
from repoman.copier import build_preset_data

app = Typer(
add_completion=True,
help="""Create a Meson-based C++ library project.

Examples:

repoman create cpp cpp my-lib
repoman create cpp cpp my-lib -o ./libs --dry-run
""",
)


def _default_template_path() -> Path:
"""Return the bundled C++ template path."""
current_file = Path(__file__)
return current_file.parent.parent.parent.parent / "cpp_template"


@app.command(no_args_is_help=True)
def cpp(
project_name: str = Argument(..., help="Name of the project to create"),
template_path: Annotated[
str | None,
Option(
"--template",
"-t",
help="Path to custom template (defaults to bundled C++ template)",
),
] = None,
output_dir: Annotated[
str | None,
Option("--output", "-o", help="Output directory (defaults to current directory)"),
] = None,
force: bool = Option(False, "--force", "-f", help="Overwrite existing files"),
dry_run: bool = Option(False, "--dry-run", help="Show what would be created without creating"),
) -> None:
"""Create a Meson-based C++ library project."""
template_path_obj = _default_template_path() if template_path is None else Path(template_path)
output_dir_base = Path.cwd() if output_dir is None else Path(output_dir)
data = build_preset_data("cpp", project_name)
run_create(
project_name=project_name,
output_dir=output_dir_base,
template_path=template_path_obj,
data=data,
force=force,
dry_run=dry_run,
)
Loading