|
|
@@ -6,282 +6,96 @@ Guidance for AI Agents working with this repository.
|
|
|
|
|
|
A sophisticated collection of infrastructure templates (boilerplates) with a Python CLI for management. Supports Terraform, Docker, Ansible, Kubernetes, etc. Built with Typer (CLI) and Jinja2 (templating).
|
|
|
|
|
|
-## Repository Structure
|
|
|
-
|
|
|
-- `cli/` - Python CLI application source code
|
|
|
- - `cli/core/` - Core functionality (app, config, commands, logging)
|
|
|
- - `cli/modules/` - Technology-specific modules (terraform, docker, compose, config, etc.)
|
|
|
-- `library/` - Template collections organized by module
|
|
|
- - `library/ansible/` - Ansible playbooks and configurations
|
|
|
- - `library/compose/` - Docker Compose configurations
|
|
|
- - `library/docker/` - Docker templates
|
|
|
- - `library/kubernetes/` - Kubernetes deployments
|
|
|
- - `library/packer/` - Packer templates
|
|
|
- - `library/terraform/` - OpenTofu/Terraform templates and examples
|
|
|
-
|
|
|
## Development Setup
|
|
|
|
|
|
-### Running the CLI
|
|
|
+### Running and Testing
|
|
|
|
|
|
```bash
|
|
|
-# List available commands
|
|
|
+# Run the CLI application
|
|
|
python3 -m cli
|
|
|
-
|
|
|
-# List templates for a module
|
|
|
-python3 -m cli compose list
|
|
|
-
|
|
|
-# Debugging commands
|
|
|
+# Debugging and Testing commands
|
|
|
python3 -m cli --log-level DEBUG compose list
|
|
|
-
|
|
|
-# Generate template to directory named after template (default)
|
|
|
-python3 -m cli compose generate nginx
|
|
|
-
|
|
|
-# Generate template to custom directory
|
|
|
-python3 -m cli compose generate nginx my-nginx-server
|
|
|
-
|
|
|
-# Generate template interactively (default - prompts for variables)
|
|
|
-python3 -m cli compose generate authentik
|
|
|
-
|
|
|
-# Generate template non-interactively (skips prompts, uses defaults and CLI variables)
|
|
|
-python3 -m cli compose generate authentik my-auth --no-interactive
|
|
|
-
|
|
|
-# Generate with variable overrides (non-interactive)
|
|
|
-python3 -m cli compose generate authentik my-auth \
|
|
|
- --var service_name=auth \
|
|
|
- --var ports_enabled=false \
|
|
|
- --var database_type=postgres \
|
|
|
- --no-interactive
|
|
|
-
|
|
|
-# Show template details
|
|
|
-python3 -m cli compose show authentik
|
|
|
-
|
|
|
-# Managing default values
|
|
|
-python3 -m cli compose defaults set service_name my-app
|
|
|
-python3 -m cli compose defaults get
|
|
|
-python3 -m cli compose defaults list
|
|
|
-
|
|
|
-# Managing library repositories
|
|
|
-python3 -m cli repo list
|
|
|
-python3 -m cli repo update
|
|
|
-python3 -m cli repo add my-lib https://github.com/user/templates --directory library --branch main
|
|
|
-python3 -m cli repo remove my-lib
|
|
|
-```
|
|
|
-
|
|
|
-## Common Development Tasks
|
|
|
-
|
|
|
-## Release Management
|
|
|
-
|
|
|
-**Process:** Tag-based workflow via `.github/workflows/release.yaml`. Push a semver tag (e.g., `v1.2.3`) to trigger.
|
|
|
-
|
|
|
-**Workflow Steps:**
|
|
|
-1. Extracts version from tag
|
|
|
-2. Auto-updates `pyproject.toml` and `cli/__main__.py` with version
|
|
|
-3. Recreates tag pointing to version bump commit
|
|
|
-4. Builds wheel/tarball
|
|
|
-5. Creates GitHub release (marks alpha/beta/rc as pre-release)
|
|
|
-
|
|
|
-**Important:** Never manually edit version numbers - they're placeholders (`0.0.0`) that get auto-updated.
|
|
|
-
|
|
|
-**User Installation:**
|
|
|
-```bash
|
|
|
-# Latest
|
|
|
-curl -fsSL https://raw.githubusercontent.com/christianlempa/boilerplates/main/scripts/install.sh | bash
|
|
|
-
|
|
|
-# Specific version
|
|
|
-curl -fsSL https://raw.githubusercontent.com/christianlempa/boilerplates/main/scripts/install.sh | bash -s -- --version v1.2.3
|
|
|
-```
|
|
|
-
|
|
|
-The `install.sh` script downloads the release tarball and installs via pipx. PyPI publishing is currently disabled.
|
|
|
-
|
|
|
-## Library System
|
|
|
-
|
|
|
-### Git-Based Libraries
|
|
|
-
|
|
|
-Templates are stored in git repositories and synced locally:
|
|
|
-
|
|
|
-- **Location**: `~/.config/boilerplates/libraries/{name}/`
|
|
|
-- **Config**: Stored in `~/.config/boilerplates/config.yaml`
|
|
|
-- **Sync**: Uses sparse-checkout to clone only template directories
|
|
|
-
|
|
|
-### Library Configuration
|
|
|
-
|
|
|
-Libraries are defined in the config file:
|
|
|
-
|
|
|
-```yaml
|
|
|
-libraries:
|
|
|
- - name: default
|
|
|
- url: https://github.com/christianlempa/boilerplates.git
|
|
|
- branch: refactor/boilerplates-v2
|
|
|
- directory: library # Directory within repo containing templates
|
|
|
- enabled: true
|
|
|
-```
|
|
|
-
|
|
|
-**Properties:**
|
|
|
-- `name`: Unique identifier for the library
|
|
|
-- `url`: Git repository URL
|
|
|
-- `branch`: Git branch to use (default: `main`)
|
|
|
-- `directory`: Path within repo where templates are located (use `.` for root)
|
|
|
-- `enabled`: Whether library is active
|
|
|
-
|
|
|
-### Sparse-Checkout
|
|
|
-
|
|
|
-The system uses git sparse-checkout (non-cone mode) to clone only the specified `directory`, avoiding unnecessary files:
|
|
|
-
|
|
|
-```bash
|
|
|
-# Only clones library/ directory, not root files
|
|
|
-git sparse-checkout init --no-cone
|
|
|
-git sparse-checkout set library/*
|
|
|
```
|
|
|
|
|
|
-### Library Manager
|
|
|
-
|
|
|
-`LibraryManager` loads libraries from config and provides template discovery:
|
|
|
-
|
|
|
-- **Priority**: Libraries are searched in config order (first = highest priority)
|
|
|
-- **Deduplication**: Duplicate template IDs are resolved by priority
|
|
|
-- **Path Resolution**: Automatically handles `directory` config to locate templates
|
|
|
-
|
|
|
-### Config Manager
|
|
|
-
|
|
|
-`ConfigManager` handles all configuration:
|
|
|
-
|
|
|
-- **Location**: `~/.config/boilerplates/config.yaml`
|
|
|
-- **Atomic Writes**: Uses temp file + rename for safety
|
|
|
-- **Validation**: Comprehensive validation of all config fields
|
|
|
-- **Migration**: Auto-migrates old configs to add new sections
|
|
|
-
|
|
|
-**Main Sections:**
|
|
|
-- `defaults`: Per-module default variable values
|
|
|
-- `preferences`: User preferences (editor, output_dir, etc.)
|
|
|
-- `libraries`: Git repository configurations
|
|
|
-
|
|
|
-### Display Manager
|
|
|
-
|
|
|
-`DisplayManager` (`cli/core/display.py`) is the **centralized interface** for ALL CLI output rendering.
|
|
|
-
|
|
|
-**Design Principles:**
|
|
|
-- **Single Responsibility**: All display logic goes through DisplayManager
|
|
|
-- **Encapsulation**: IconManager is ONLY used internally by DisplayManager
|
|
|
-- **Consistency**: External code should NEVER directly call `IconManager` or `console.print`
|
|
|
-- **Standardization**: Provides unified methods for all display types
|
|
|
-
|
|
|
-**Categories of Methods:**
|
|
|
-
|
|
|
-1. **Status Messages:**
|
|
|
- - `display_success(message, context)` - Success messages with check icon
|
|
|
- - `display_error(message, context)` - Error messages with error icon
|
|
|
- - `display_warning(message, context)` - Warning messages with warning icon
|
|
|
- - `display_info(message, context)` - Info messages with info icon
|
|
|
- - `display_skipped(message, reason)` - Skipped/disabled messages
|
|
|
+### Linting and Formatting
|
|
|
|
|
|
-2. **Tables:**
|
|
|
- - `display_templates_table(templates, module, title)` - Template listings
|
|
|
- - `display_status_table(title, rows, columns)` - Status tables with success/error indicators
|
|
|
- - `display_summary_table(title, items)` - Simple key-value summary tables
|
|
|
- - `display_file_operation_table(files)` - File operations with sizes and statuses
|
|
|
+Should **always** happen before pushing anything to the repository.
|
|
|
|
|
|
-3. **Structured Display:**
|
|
|
- - `display_template_details(template, id)` - Detailed template view with file tree and variables
|
|
|
- - `display_config_tree(spec, module_name, show_all)` - Configuration as tree view
|
|
|
- - `display_file_generation_confirmation(output_dir, files, existing)` - File generation preview
|
|
|
+- Use `yamllint` for YAML files and `pylint` for Python code.
|
|
|
+- Use `2` spaces for YAML and Python indentation.
|
|
|
|
|
|
-4. **Interactive:**
|
|
|
- - `display_warning_with_confirmation(message, details, default)` - Warning with user confirmation
|
|
|
- - `display_section_header(title, description)` - Section headers for prompts
|
|
|
+### Project Management and Git
|
|
|
|
|
|
-5. **Utility:**
|
|
|
- - `display_heading(text, icon_type, style)` - Headings with optional icons
|
|
|
- - `display_next_steps(next_steps, variable_values)` - Post-generation instructions
|
|
|
- - `get_lock_icon()` - Get lock icon for sensitive variables (for prompts)
|
|
|
+The project is stored in a public GitHub Repository, use issues, and branches for features/bugfixes and open PRs for merging.
|
|
|
|
|
|
-**Usage:**
|
|
|
-```python
|
|
|
-from cli.core.display import DisplayManager
|
|
|
+**Naming Conventions and Best-Practices:**
|
|
|
+- Branches, PRs: `feature/2314-add-feature`, `problem/1249-fix-bug`
|
|
|
+- Issues should have clear titles and descriptions, link related issues/PRs, and have appropriate labels like (problem, feature, discussion, question).
|
|
|
+- Commit messages should be clear and concise, following the format: `type(scope): subject` (e.g., `fix(compose): correct variable parsing`).
|
|
|
|
|
|
-display = DisplayManager()
|
|
|
+## Architecture
|
|
|
|
|
|
-# Status messages
|
|
|
-display.display_success("Operation completed")
|
|
|
-display.display_error("Failed to process", context="module_name")
|
|
|
+### File Structure
|
|
|
|
|
|
-# Tables
|
|
|
-status_rows = [("lib1", "Updated", True), ("lib2", "Failed", False)]
|
|
|
-display.display_status_table("Update Summary", status_rows)
|
|
|
+- `cli/` - Python CLI application source code
|
|
|
+ - `cli/core/` - Core Components of the CLI application
|
|
|
+ - `cli/modules/` - Modules implementing variable specs and technology-specific functions
|
|
|
+ - `cli/__main__.py` - CLI entry point, auto-discovers modules and registers commands
|
|
|
+- `library/` - Template collections organized by module
|
|
|
+ - `library/ansible/` - Ansible playbooks and configurations
|
|
|
+ - `library/compose/` - Docker Compose configurations
|
|
|
+ - `library/docker/` - Docker templates
|
|
|
+ - `library/kubernetes/` - Kubernetes deployments
|
|
|
+ - `library/packer/` - Packer templates
|
|
|
+ - `library/terraform/` - OpenTofu/Terraform templates and examples
|
|
|
|
|
|
-# Warnings with confirmation
|
|
|
-if display.display_warning_with_confirmation(
|
|
|
- "Directory is not empty",
|
|
|
- ["5 files will be overwritten"],
|
|
|
- default=False
|
|
|
-):
|
|
|
- # User confirmed
|
|
|
- pass
|
|
|
-```
|
|
|
+### Core Components
|
|
|
|
|
|
-### Icon Manager
|
|
|
+- `cli/core/collection.py` - Dataclass for VariableCollection (stores variable sections and variables)
|
|
|
+- `cli/core/config.py` - Configuration management (loading, saving, validation)
|
|
|
+- `cli/core/display.py` - Centralized CLI output rendering (**Always use this to display output - never print directly**)
|
|
|
+- `cli/core/exceptions.py` - Custom exceptions for error handling (**Always use this for raising errors**)
|
|
|
+- `cli/core/library.py` - LibraryManager for template discovery from git-synced libraries and static file paths
|
|
|
+- `cli/core/module.py` - Abstract base class for modules (defines standard commands)
|
|
|
+- `cli/core/prompt.py` - Interactive CLI prompts using rich library
|
|
|
+- `cli/core/registry.py` - Central registry for module classes (auto-discovers modules)
|
|
|
+- `cli/core/repo.py` - Repository management for syncing git-based template libraries
|
|
|
+- `cli/core/sections.py` - Dataclass for VariableSection (stores section metadata and variables)
|
|
|
+- `cli/core/template.py` - Template Class for parsing, managing and rendering templates
|
|
|
+- `cli/core/variables.py` - Dataclass for Variable (stores variable metadata and values)
|
|
|
|
|
|
-`IconManager` provides **Nerd Font icons** internally for DisplayManager.
|
|
|
+### Modules
|
|
|
|
|
|
-**IMPORTANT:**
|
|
|
-- ❌ **DO NOT import or use IconManager directly in your code**
|
|
|
-- ✅ **All icon display should go through DisplayManager methods**
|
|
|
-- The only exception is DisplayManager itself, which uses IconManager internally
|
|
|
+- `cli/modules/compose.py` - Docker Compose-specific functionality
|
|
|
+**(Work in Progress)**
|
|
|
+- `cli/modules/terraform.py` - Terraform-specific functionality
|
|
|
+- `cli/modules/docker.py` - Docker-specific functionality
|
|
|
+- `cli/modules/ansible.py` - Ansible-specific functionality
|
|
|
+- `cli/modules/kubernetes.py` - Kubernetes-specific functionality
|
|
|
+- `cli/modules/packer.py` - Packer-specific functionality
|
|
|
|
|
|
-**Icon Categories (Internal):**
|
|
|
-- **File Types**: `FILE_YAML`, `FILE_JSON`, `FILE_MARKDOWN`, `FILE_JINJA2`, `FILE_DOCKER`, etc.
|
|
|
-- **Status**: `STATUS_SUCCESS`, `STATUS_ERROR`, `STATUS_WARNING`, `STATUS_INFO`, `STATUS_SKIPPED`
|
|
|
-- **UI Elements**: `UI_CONFIG`, `UI_LOCK`, `UI_SETTINGS`, `UI_ARROW_RIGHT`, `FILE_FOLDER`
|
|
|
+### LibraryManager
|
|
|
|
|
|
-**Architecture:**
|
|
|
-```
|
|
|
-┌─────────────────┐
|
|
|
-│ Module Code │
|
|
|
-│ (module.py, │
|
|
|
-│ repo.py, etc) │
|
|
|
-└────────┬────────┘
|
|
|
- │
|
|
|
- ▼
|
|
|
-┌─────────────────┐
|
|
|
-│ DisplayManager │ ◄── Use this for ALL output
|
|
|
-└────────┬────────┘
|
|
|
- │
|
|
|
- ▼
|
|
|
-┌─────────────────┐
|
|
|
-│ IconManager │ ◄── Internal use only
|
|
|
-└─────────────────┘
|
|
|
-```
|
|
|
+- Loads libraries from config file
|
|
|
+- Stores Git Libraries under: `~/.config/boilerplates/libraries/{name}/`
|
|
|
+- Uses sparse-checkout to clone only template directories for git-based libraries (avoiding unnecessary files)
|
|
|
|
|
|
-**Best Practices:**
|
|
|
-- ❌ `from cli.core.display import IconManager` - NEVER do this
|
|
|
-- ❌ `console.print(f"✓ {message}")` - Don't use emojis or direct console access
|
|
|
-- ❌ `IconManager.get_status_icon("success")` - Don't call IconManager directly
|
|
|
-- ✅ `display.display_success(message)` - Always use DisplayManager methods
|
|
|
-- ✅ `display.get_lock_icon()` - Exception: prompts can get lock icon for text formatting
|
|
|
+### ConfigManager
|
|
|
|
|
|
-## Architecture Notes
|
|
|
+- User Config stored in `~/.config/boilerplates/config.yaml`
|
|
|
|
|
|
-### Key Components
|
|
|
+### DisplayManager and IconManager
|
|
|
|
|
|
-Modular architecture with dynamic module discovery:
|
|
|
+External code should NEVER directly call `IconManager` or `console.print`, instead always use `DisplayManager` methods.
|
|
|
|
|
|
-- **`cli/__main__.py`**: Entry point. Auto-discovers modules and registers commands.
|
|
|
-- **`cli/core/registry.py`**: Central module class store.
|
|
|
-- **`cli/core/module.py`**: Abstract `Module` base class for standardized commands (list, search, show, generate).
|
|
|
-- **`cli/core/library.py`**: `LibraryManager` finds templates from git-synced libraries with priority system.
|
|
|
-- **`cli/core/repo.py`**: Repository management for syncing git-based template libraries.
|
|
|
-- **`cli/core/config.py`**: `ConfigManager` handles configuration, defaults, and library definitions.
|
|
|
-- **`cli/core/template.py`**: Parses templates, merges YAML frontmatter with Jinja2 content.
|
|
|
-- **`cli/core/variables.py`**: Variable data structures (`Variable`, `VariableSection`, `VariableCollection`).
|
|
|
-- **`cli/core/prompt.py`**: Interactive CLI prompts via `rich` library.
|
|
|
-- **`cli/core/display.py`**: Consistent output rendering with `DisplayManager` and `IconManager`.
|
|
|
+- `DisplayManager` provides a **centralized interface** for ALL CLI output rendering (Use `display_***` methods from `DisplayManager` for ALL output)
|
|
|
+- `IconManager` provides **Nerd Font icons** internally for DisplayManager, don't use Emojis or direct console access
|
|
|
|
|
|
-### Template Format
|
|
|
+## Templates
|
|
|
|
|
|
Templates are directory-based. Each template is a directory containing all the necessary files and subdirectories for the boilerplate.
|
|
|
|
|
|
-#### Main Template File
|
|
|
-
|
|
|
-Requires `template.yaml` or `template.yml` with metadata and variables in YAML frontmatter:
|
|
|
+Requires `template.yaml` or `template.yml` with metadata and variables:
|
|
|
|
|
|
```yaml
|
|
|
---
|
|
|
@@ -309,30 +123,19 @@ spec:
|
|
|
default: latest
|
|
|
```
|
|
|
|
|
|
-#### Template Files
|
|
|
+### Template Files
|
|
|
|
|
|
- **Jinja2 Templates (`.j2`)**: Rendered by Jinja2, `.j2` extension removed in output. Support `{% include %}` and `{% import %}`.
|
|
|
- **Static Files**: Non-`.j2` files copied as-is.
|
|
|
- **Sanitization**: Auto-sanitized (single blank lines, no leading blanks, trimmed whitespace, single trailing newline).
|
|
|
|
|
|
-#### Example Directory Structure
|
|
|
-
|
|
|
-```
|
|
|
-library/compose/my-nginx-template/
|
|
|
-├── template.yaml
|
|
|
-├── compose.yaml.j2
|
|
|
-├── config/
|
|
|
-│ └── nginx.conf.j2
|
|
|
-└── static/
|
|
|
- └── README.md
|
|
|
-```
|
|
|
-
|
|
|
-#### Variables
|
|
|
+### Variables
|
|
|
|
|
|
**Precedence** (lowest to highest):
|
|
|
1. Module `spec` (defaults for all templates of that kind)
|
|
|
2. Template `spec` (overrides module defaults)
|
|
|
-3. CLI `--var` (highest priority)
|
|
|
+3. User `config.yaml` (overrides template and module defaults)
|
|
|
+4. CLI `--var` (highest priority)
|
|
|
|
|
|
**Key Features:**
|
|
|
- **Required Sections**: Mark with `required: true` (general is implicit). Users must provide all values.
|
|
|
@@ -344,56 +147,37 @@ library/compose/my-nginx-template/
|
|
|
```yaml
|
|
|
spec:
|
|
|
traefik:
|
|
|
- title: "Traefik"
|
|
|
- toggle: "traefik_enabled"
|
|
|
+ title: Traefik
|
|
|
+ required: false
|
|
|
+ toggle: traefik_enabled
|
|
|
vars:
|
|
|
traefik_enabled:
|
|
|
- type: "bool"
|
|
|
+ type: bool
|
|
|
default: false
|
|
|
traefik_host:
|
|
|
- type: "hostname"
|
|
|
+ type: hostname
|
|
|
|
|
|
traefik_tls:
|
|
|
- title: "Traefik TLS/SSL"
|
|
|
- needs: "traefik" # Only shown if traefik is enabled
|
|
|
- toggle: "traefik_tls_enabled"
|
|
|
+ title: Traefik TLS/SSL
|
|
|
+ needs: traefik
|
|
|
+ toggle: traefik_tls_enabled
|
|
|
vars:
|
|
|
traefik_tls_enabled:
|
|
|
- type: "bool"
|
|
|
+ type: bool
|
|
|
default: true
|
|
|
traefik_tls_certresolver:
|
|
|
- type: "str"
|
|
|
+ type: str
|
|
|
+ sensitive: false
|
|
|
+ default: myresolver
|
|
|
```
|
|
|
|
|
|
-## Best Practices
|
|
|
+## Prompt
|
|
|
|
|
|
-### Template Structure
|
|
|
-- Include `template.yaml`/`template.yml` with descriptive IDs (lowercase-with-hyphens)
|
|
|
-- Use subdirectories for Jinja2 templates (e.g., `config/`)
|
|
|
-- Prefer `config` module for app-specific configs vs complex directories
|
|
|
+Uses `rich` library for interactive prompts. Supports:
|
|
|
+- Text input
|
|
|
+- Password input (masked)
|
|
|
+- Selection from list (single/multiple)
|
|
|
+- Confirmation (yes/no)
|
|
|
+- Default values
|
|
|
|
|
|
-### Variables
|
|
|
-- **Priority**: Prefer module spec → override when needed → add new only if unique
|
|
|
-- Use descriptive underscore names, always specify `type`
|
|
|
-- **Defaults**: Define sensible `default` values in `template.yaml` for all non-required variables (improves non-interactive generation)
|
|
|
-- **Credentials**: Mark with `sensitive: true` (hides input), `autogenerated: true` (auto-generates secure values when empty)
|
|
|
-
|
|
|
-### Jinja2
|
|
|
-- Keep logic simple, add descriptive comments
|
|
|
-
|
|
|
-### Docker Compose
|
|
|
-
|
|
|
-**Naming Conventions:**
|
|
|
-- Service: `service_name`, `container_name`, `container_timezone`, `restart_policy`
|
|
|
-- App: Prefix with app name (e.g., `authentik_secret_key`)
|
|
|
-- Database: `database_*` (type, enabled, external, host, port, name, user, password)
|
|
|
-- Network: `network_*` (enabled, name, external)
|
|
|
-- Traefik: `traefik_*` (enabled, host, tls_enabled, tls_entrypoint, tls_certresolver)
|
|
|
-- Ports: `ports_*` (enabled, http, https, ssh)
|
|
|
-- Email: `email_*` (enabled, host, port, username, password, from)
|
|
|
-
|
|
|
-**Patterns:**
|
|
|
-- Use scoped `.env.{service}.j2` files for better security/organization
|
|
|
-- Always: `depends_on`, named volumes, health checks (DB), `restart: {{ restart_policy | default('unless-stopped') }}`
|
|
|
-- Conditionals: `{% if not database_external %}` for service creation
|
|
|
-- Common toggles: `database_enabled`, `email_enabled`, `traefik_enabled`, `ports_enabled`, `network_enabled`
|
|
|
+To skip the prompt use the `--no-interactive` flag, which will use defaults or empty values.
|