فهرست منبع

fix(cli): restore click dependency and Typer context handling

xcad 3 هفته پیش
والد
کامیت
214682eb9b
9فایلهای تغییر یافته به همراه6 افزوده شده و 486 حذف شده
  1. 2 0
      .gitignore
  2. 0 63
      AGENTS.md
  3. 2 4
      cli/__main__.py
  4. 1 4
      cli/core/module/helpers.py
  5. 0 93
      docs/architecture.md
  6. 0 56
      docs/display.md
  7. 0 109
      docs/libraries.md
  8. 0 157
      docs/templates.md
  9. 1 0
      pyproject.toml

+ 2 - 0
.gitignore

@@ -1,6 +1,8 @@
 # Ignore local development files
 # Ignore local development files
 **/.vscode
 **/.vscode
 **/.DS_Store
 **/.DS_Store
+/AGENTS.md
+/docs
 
 
 # Docker Secrets, Environment Files
 # Docker Secrets, Environment Files
 **/secret.*
 **/secret.*

+ 0 - 63
AGENTS.md

@@ -1,63 +0,0 @@
-# AGENTS.md
-
-Guidance for AI coding agents working in this repository.
-
-## Project
-
-Project name: Boilerplates CLI
-
-A Python CLI for managing infrastructure boilerplates, template libraries, template rendering, and validation. Built with Typer and Jinja2.
-
-## Scope and precedence
-
-- This file applies to the repository tree rooted at the directory containing this `AGENTS.md` file.
-- More deeply nested `AGENTS.md` files may add or override instructions for their subtrees.
-- Before GitHub-facing work such as issues, branches, PRs, merges, tags, or releases, read this file and the relevant docs listed below.
-- For release-related work, always read `RELEASE.md` first.
-
-## Repository map
-
-- Source: `cli/` - main CLI application and core runtime code.
-- Tests: `tests/` - automated tests, fixtures, and test utilities.
-- Contribution guide: `CONTRIBUTING.md` - setup, validation, GitHub workflow, and command overview.
-- Docs: `docs/` - developer documentation and architecture notes.
-- Release process: `RELEASE.md` - release PR, version, changelog, tag, and publish workflow.
-- Scripts: `scripts/` - installer and helper scripts.
-- GitHub automation: `.github/` - workflows, issue/PR templates, and repository scripts.
-- Legacy library: `library/` - backward-compatibility template content for versions older than `0.2.0`; not the canonical modern template library.
-
-## Documentation
-
-Project documentation lives in `docs/`.
-
-Agents should read the relevant docs before making changes and update docs when behavior, configuration, or workflows change.
-
-### Documentation map
-
-- `docs/architecture.md` - repository layout, module system, and core runtime components
-- `docs/templates.md` - template format, variables, rendering, and validation behavior
-- `docs/libraries.md` - library configuration and canonical external template library guidance
-- `docs/display.md` - DisplayManager and CLI output rules
-
-## Validation
-
-Default checks before finishing code changes:
-
-```bash
-ruff check --fix .
-ruff format .
-python3 -m pytest
-```
-
-See `CONTRIBUTING.md` for setup and workflow details.
-
-## Project conventions
-
-- Follow existing project structure, naming, and patterns before introducing new ones.
-- Keep changes focused on the requested task; avoid unrelated refactors or broad rewrites.
-- When adding or changing behavior, update relevant docs and tests where practical.
-- Do not commit secrets, tokens, private keys, or environment-specific credentials.
-- Use custom exceptions from `cli/core/exceptions.py` for user-facing errors where applicable.
-- Use `DisplayManager` for user-facing command output; never print directly from command, module, config, repository, validation, or template-rendering code. See `docs/display.md`.
-- Do not treat `library/` as the canonical source for current template work. For `0.2.0+`, active templates live in the separate `boilerplates-library` repository. See `docs/libraries.md`.
-- When answering which template kinds are supported, prefer registered modules in `cli/modules/` over legacy library contents.

+ 2 - 4
cli/__main__.py

@@ -14,7 +14,7 @@ from pathlib import Path
 
 
 import click
 import click
 from rich.console import Console
 from rich.console import Console
-from typer import Option, Typer
+from typer import Context, Option, Typer
 from typer.core import TyperGroup
 from typer.core import TyperGroup
 
 
 import cli.modules
 import cli.modules
@@ -79,6 +79,7 @@ def setup_logging(log_level: str = "WARNING") -> None:
 
 
 @app.callback(invoke_without_command=True)
 @app.callback(invoke_without_command=True)
 def main(
 def main(
+    ctx: Context,
     _version: bool | None = Option(
     _version: bool | None = Option(
         None,
         None,
         "--version",
         "--version",
@@ -104,9 +105,6 @@ def main(
         # Silence all logging (including third-party) unless user explicitly requests it
         # Silence all logging (including third-party) unless user explicitly requests it
         logging.disable(logging.CRITICAL)
         logging.disable(logging.CRITICAL)
 
 
-    # Get context without type annotation (compatible with all Typer versions)
-    ctx = click.get_current_context()
-
     # Store log level in context for potential use by other commands
     # Store log level in context for potential use by other commands
     ctx.ensure_object(dict)
     ctx.ensure_object(dict)
     ctx.obj["log_level"] = log_level
     ctx.obj["log_level"] = log_level

+ 1 - 4
cli/core/module/helpers.py

@@ -194,10 +194,7 @@ def apply_cli_overrides(template, var: list[str] | None, ctx=None) -> None:
 
 
     # Get context if not provided (compatible with all Typer versions)
     # Get context if not provided (compatible with all Typer versions)
     if ctx is None:
     if ctx is None:
-        try:
-            ctx = click.get_current_context()
-        except RuntimeError:
-            ctx = None
+        ctx = click.get_current_context(silent=True)
 
 
     extra_args = list(ctx.args) if ctx and hasattr(ctx, "args") else []
     extra_args = list(ctx.args) if ctx and hasattr(ctx, "args") else []
     cli_overrides = parse_var_inputs(var or [], extra_args)
     cli_overrides = parse_var_inputs(var or [], extra_args)

+ 0 - 93
docs/architecture.md

@@ -1,93 +0,0 @@
-# Architecture Notes
-
-## Repository layout
-
-- `cli/` - Python CLI application source code
-  - `cli/core/` - core runtime packages
-  - `cli/modules/` - technology-specific module registrations
-  - `cli/__main__.py` - CLI entry point; discovers modules and registers commands
-- `tests/` - automated tests
-- `docs/` - developer documentation
-- `scripts/` - helper scripts, including installer tooling
-- `library/` - legacy in-repo template content for versions older than `0.2.0`; do not treat it as the canonical template library for modern work
-- `.github/` - workflows, templates, and repository automation
-
-## Supported kinds
-
-The supported kinds are the registered modules in `cli/modules/`. Prefer this code-level list over legacy content in `library/`.
-
-Current kinds:
-
-- `ansible`
-- `bash`
-- `compose`
-- `helm`
-- `kubernetes`
-- `packer`
-- `python`
-- `static`
-- `swarm`
-- `terraform`
-
-## Module system
-
-Modules subclass `Module` from `cli/core/module/` and register themselves with the central registry.
-
-Minimal module example:
-
-```python
-from ...core.module import Module
-from ...core.registry import registry
-
-
-class ExampleModule(Module):
-    name = "example"
-    description = "Manage example templates"
-
-
-registry.register(ExampleModule)
-```
-
-Discovery and registration flow:
-
-1. `cli/__main__.py` imports module packages/files from `cli/modules/`.
-2. Each module calls `registry.register(ModuleClass)` at import time.
-3. The registry stores module classes by module name.
-4. The CLI framework creates standard commands for every registered module.
-5. Modules are instantiated on demand when commands run.
-
-Benefits:
-
-- No central manual registration for new kinds
-- Modules are self-contained
-- Registry validation catches invalid module classes early
-
-## Core components
-
-Important packages/files:
-
-- `cli/core/module/` - base module class and standard command implementations
-- `cli/core/template/` - template manifest parsing, variable normalization, rendering, and validation
-- `cli/core/config/` - user configuration loading, saving, validation, and migration
-- `cli/core/library.py` - template discovery across git/static libraries
-- `cli/core/repo.py` - repository/library management commands
-- `cli/core/registry.py` - module registry
-- `cli/core/display/` - centralized CLI output rendering; see `docs/display.md`
-- `cli/core/validation/` - dependency matrix and kind-specific rendered-file validators
-- `cli/core/validators.py` - generic content validators such as YAML and Docker Compose validation
-- `cli/core/exceptions.py` - custom exceptions; prefer these for user-facing errors
-
-## Prompt/input flow
-
-Interactive prompting is implemented with Rich-based input helpers under `cli/core/input/`.
-
-Prompt support includes:
-
-- text input
-- password/secret input
-- yes/no confirmation
-- numbered choice selection
-- defaults from template/config/CLI sources
-- autogenerated secret placeholders
-
-Use `--no-interactive` to skip prompts and use defaults, config values, CLI overrides, or empty values as appropriate.

+ 0 - 56
docs/display.md

@@ -1,56 +0,0 @@
-# Display and Output Rules
-
-## Critical rule
-
-User-facing command output should go through `DisplayManager` or one of the display classes under `cli/core/display/`.
-
-Do not:
-
-- call `console.print()` from command, module, config, repository, validation, or template-rendering code
-- import `Console` from `rich.console` for general command output outside display classes or `cli/__main__.py`
-- use direct emojis or icons in feature code
-- bypass display helpers for status, errors, warnings, tables, or template output
-
-Do:
-
-- use `module_instance.display` in module/command code
-- use `DisplayManager()` when standalone core command code needs output
-- add or adjust display helpers in `cli/core/display/` when new output patterns are needed
-- add shortcode/icon mappings in the display/icon layer
-
-## Rationale
-
-Centralized display handling keeps CLI output consistent and makes it easier to manage:
-
-- formatting standards
-- quiet/verbose behavior
-- stderr/stdout routing
-- icon and Nerd Font usage
-- table rendering
-- error/warning/success styles
-
-## Display architecture
-
-`DisplayManager` acts as a facade over focused display components.
-
-Current responsibilities include:
-
-- variable rendering and variable tables
-- template metadata and file-tree rendering
-- status, error, warning, success, and info messages
-- data/status/config tables
-- markdown/description rendering
-
-External code should call facade methods on `DisplayManager`. Internally, the facade delegates to specialized display classes.
-
-Example:
-
-```python
-display = DisplayManager()
-display.success("Template generated")
-display.error("Validation failed", details="Missing variable")
-```
-
-If a needed display method does not exist, add one to the display layer instead of printing directly from feature code.
-
-Prompt/input internals under `cli/core/input/` may use Rich prompt primitives directly when implementing interactive input behavior. Keep regular command output in the display layer.

+ 0 - 109
docs/libraries.md

@@ -1,109 +0,0 @@
-# Library and Configuration Notes
-
-## Canonical template library
-
-The canonical template library does **not** live in this repository for modern development.
-
-- The checked-in `library/` directory is legacy/backward-compatibility content for versions older than `0.2.0`.
-- For `0.2.0+`, active template work belongs in the separate GitHub repository `boilerplates-library`.
-
-When answering questions about supported kinds or current template behavior, prefer code under `cli/modules/` and runtime logic under `cli/core/` over legacy `library/` content.
-
-## LibraryManager
-
-`LibraryManager` loads configured libraries and discovers templates by kind.
-
-Responsibilities:
-
-- load library configuration
-- resolve git and static library paths
-- discover template directories containing `template.json`
-- normalize template IDs from manifest slugs
-- handle duplicate template IDs
-- preserve library priority order
-
-Git libraries are stored under:
-
-```text
-~/.config/boilerplates/libraries/{name}/
-```
-
-Git-based libraries use sparse checkout to avoid cloning unrelated repository content where possible.
-
-## Library types
-
-### Git libraries
-
-Git libraries require:
-
-- `name`
-- `type: git`
-- `url`
-- `branch`
-- `directory`
-
-### Static libraries
-
-Static libraries require:
-
-- `name`
-- `type: static`
-- `path`
-
-Static library paths may be absolute or relative to the config file location. Some config entries may include backward-compatible dummy `url`, `branch`, and `directory` fields.
-
-## Priority and duplicate handling
-
-Library priority is determined by config order. Earlier entries have higher priority.
-
-Duplicate behavior:
-
-- duplicate IDs within the same library raise a duplicate-template error
-- duplicate IDs across libraries can be addressed with qualified IDs
-- simple IDs resolve to the highest-priority library
-- qualified IDs target a specific library, for example `alloy.default` or `alloy.local`
-
-Example:
-
-```bash
-boilerplates compose show alloy
-boilerplates compose show alloy.local
-```
-
-## Config location
-
-User config is stored at:
-
-```text
-~/.config/boilerplates/config.yaml
-```
-
-Example library config:
-
-```yaml
-libraries:
-  - name: default
-    type: git
-    url: https://github.com/user/templates.git
-    branch: main
-    directory: library
-  - name: local
-    type: static
-    path: ~/my-templates
-    url: ''
-    branch: main
-    directory: .
-```
-
-## Repository commands
-
-Common library commands:
-
-```bash
-boilerplates repo list
-boilerplates repo update
-boilerplates repo add local --type static --path ~/my-templates
-boilerplates repo remove local
-```
-
-Use `DisplayManager` for all output in repository/config code. Do not print directly.

+ 0 - 157
docs/templates.md

@@ -1,157 +0,0 @@
-# Template Authoring Notes
-
-Templates are directory-based. Each template directory contains `template.json` plus a required `files/` directory with renderable content.
-
-## Template loading and rendering flow
-
-1. `LibraryManager` finds template directories containing `template.json`.
-2. `Template` loads and validates manifest metadata.
-3. Manifest variables are normalized into the runtime variable collection shape.
-4. Defaults are merged from template, user config, var-files, and CLI overrides.
-5. Sections are sorted and dependency constraints are validated.
-6. Variables are resolved dynamically according to `needs` constraints.
-7. Files under `files/` render through the custom-delimiter Jinja environment.
-8. Rendered output is sanitized.
-9. Optional semantic or kind-specific validation runs.
-
-## Template structure
-
-Minimal `template.json` shape:
-
-```json
-{
-  "slug": "my-template",
-  "kind": "compose",
-  "metadata": {
-    "name": "My Template",
-    "description": "A template description.",
-    "version": {
-      "name": "v1.0.0"
-    }
-  },
-  "variables": [
-    {
-      "name": "general",
-      "title": "General",
-      "items": [
-        {
-          "name": "service_name",
-          "type": "str",
-          "title": "Service name",
-          "default": "demo"
-        }
-      ]
-    }
-  ]
-}
-```
-
-## Template delimiters
-
-For `0.2.0+`, templates use custom Jinja-like delimiters:
-
-- Variables: `<< variable_name >>`
-- Blocks: `<% if condition %> ... <% endif %>`
-- Comments: `<# comment #>`
-
-Default Jinja delimiters such as `{{ variable }}` are intentionally left untouched so downstream tools like Ansible can use them literally.
-
-Legacy `.j2` behavior is no longer supported for new `template.json` templates. Renderable content lives under `files/`, and output paths match the relative paths under `files/`.
-
-## Metadata versioning
-
-`metadata.version` is a structured object and may be partial. Supported fields include:
-
-- `name`
-- `source_dep_name`
-- `source_dep_version`
-- `source_dep_digest`
-- `upstream_ref`
-- `notes`
-
-This separates the user-facing template version label from tracked upstream dependency metadata.
-
-## Application versions
-
-Application/image versions should generally be hardcoded in template files, for example:
-
-```yaml
-image: nginx:1.25.3
-```
-
-Do not create variables such as `nginx_version` unless there is a strong technical reason, such as multi-component version pinning. Hardcoding tested versions avoids mismatches between variables and validated template output.
-
-## Variables
-
-Variable precedence, lowest to highest:
-
-1. Template defaults from `template.json`
-2. User config defaults
-3. Var-file values
-4. CLI `--var` overrides
-
-Variable types:
-
-- `str`
-- `int`
-- `float`
-- `bool`
-- `email`
-- `url`
-- `hostname`
-- `enum`
-- `secret`
-
-Common variable properties:
-
-- `default` - default value
-- `title` - prompt/display title
-- `description` - description/help text
-- `required` - require non-empty value
-- `needs` - conditional visibility constraint
-- `config.options` - enum options
-- `config.placeholder` - input placeholder
-- `config.autogenerated` - secret autogeneration settings
-
-## Sections and dependencies
-
-Variable groups become sections. Sections can define:
-
-- `toggle` - auto-created boolean variable that enables/disables the section
-- `needs` - section dependency by section key
-
-Variable-level `needs` constraints use this format:
-
-- `var_name=value`
-- `var_name!=value`
-- `var1=value1;var2=value2`
-- `network_mode=bridge,macvlan` where comma means OR
-
-Dependency validation detects missing dependencies, circular dependencies, and self-dependencies.
-
-## Validation
-
-Template validation includes:
-
-- manifest shape validation
-- custom-delimiter Jinja syntax validation
-- undeclared variable detection
-- rendering validation
-
-Generic semantic validation is provided by `cli/core/validators.py`, including YAML and Docker Compose-oriented checks where applicable.
-
-Kind-specific validation lives under `cli/core/validation/` and can be enabled with module validation options such as `--kind` or matrix validation where supported.
-
-## Docker Compose notes
-
-When using Traefik with Docker Compose and multiple networks, include the Traefik network label so Traefik routes through the intended network:
-
-```yaml
-traefik.docker.network: << traefik_network >>
-```
-
-For Swarm/Compose-specific label placement, follow existing template patterns before introducing new ones.
-
-## Shortcodes
-
-Template descriptions may use emoji-style shortcodes such as `:warning:`, `:info:`, or `:docker:`. Display code maps these to Nerd Font icons. Add new shortcodes in the display/icon layer, not directly in template rendering code.

+ 1 - 0
pyproject.toml

@@ -23,6 +23,7 @@ dependencies = [
     "python-frontmatter>=1.0.0",
     "python-frontmatter>=1.0.0",
     "Jinja2>=3.0",
     "Jinja2>=3.0",
     "email-validator>=2.0.0",
     "email-validator>=2.0.0",
+    "click==8.1.4",
 ]
 ]
 
 
 [project.optional-dependencies]
 [project.optional-dependencies]