Release v0.1.0 (#1562)

* updated version number

* chore(config): apply ruff formatting to release/v0.1.0

- Run ruff check --fix to remove unused imports and fix code issues
- Run ruff format to apply PEP 8 formatting (4 spaces for Python)
- Fix TemplateRenderError import and remove unused defaults variable

* fix(core): required sections ignore toggle and always enabled

- Modified VariableSection.is_enabled() to return True for required sections
- Hide toggle variables from display in required sections
- Add warnings when attempting to disable required section toggles via config or CLI
- Updated pihole template with better defaults and required network section

Fixes #1411

* feat(core): comprehensive improvements to variable dependencies and prompts

Major enhancements:
- Sort variables by dependencies within sections for logical display/prompt order
- Skip prompting for variables with unsatisfied needs
- Hide toggle variables in required sections from display
- Use standard prompt logic for toggle variables (supports extra text)
- Add warnings when setting values for variables with unsatisfied needs via config/CLI
- Fix section merge to preserve needs from module spec when template doesn't override
- Support semicolon-separated multiple AND conditions in needs syntax
  Example: needs: 'traefik_enabled=true;network_mode=bridge,macvlan'

Fixes and improvements for issues with:
- Required sections incorrectly showing as disabled
- Variables displayed/prompted in illogical order
- Macvlan variables prompted when network_mode=bridge
- Toggle descriptions not showing extra text
- Section needs being cleared during template merge

Related to #1411

* fix(pihole): handle host network mode correctly

Remove dependency on network_enabled toggle since Network section is now required.
Template now directly checks network_mode value for host/bridge/macvlan logic.

* feat(core): remove Jinja2 default() filter extraction (#1410) (#1416)

- Removed _extract_jinja_default_values() method from Template class
- Removed merge logic for Jinja2 defaults in variables property
- Fixed validate command to handle 3-tuple from LibraryManager.find()
- All defaults must now be explicitly defined in template/module specs
- Updated CHANGELOG.md with removal notice

* feat(core): add --var-file support for loading variables from YAML (#1331)

- Added _load_var_file() method to parse YAML variable files
- Added _apply_var_file() method to apply var file variables with proper precedence
- Added --var-file/-f parameter to generate command
- Supports both flat (var: value) and nested (section: {var: value}) YAML structures
- Proper precedence chain: module < template < config < var-file < CLI --var
- Comprehensive error handling for file not found, invalid YAML, and type errors
- Updated documentation and examples
- All existing templates validate successfully

* update changelog

* docs(quality): add comprehensive code quality analysis

* refactor(collection): add iter_active_sections() helper method

- Adds centralized iterator for sections with proper filtering
- Eliminates duplicate iteration logic in prompt.py
- Supports include_disabled and include_unsatisfied flags
- Reduces code duplication by ~30 lines

Related to #1364 (High Priority #1)

* refactor(module): deduplicate template loading logic

- Adds _load_all_templates() helper method with optional filtering
- Updates list(), search(), and validate() to use centralized helper
- Eliminates ~90 lines of duplicate code
- Improves maintainability with single source of truth for template loading

Related to #1364 (High Priority #3)

* docs: add comprehensive naming and API improvement analysis

- Identifies 6 major improvement opportunities
- Prioritizes by impact (High/Medium/Low)
- Proposes CRUD standardization across ConfigManager
- Recommends consolidating duplicate methods
- Includes breaking change mitigation strategies
- Estimates +1.0 code quality score improvement

Related to #1364

* docs: remove analysis documents (not needed for PR)

* refactor(display): split DisplayManager into specialized managers

- Refactored monolithic DisplayManager (971 lines) into 4 specialized managers:
  * VariableDisplayManager - variable and section rendering
  * TemplateDisplayManager - template display and file trees
  * StatusDisplayManager - status messages and errors
  * TableDisplayManager - all table types

- Maintained 100% backward compatibility via delegation methods
- All existing code works without modifications
- Follows Single Responsibility Principle
- Updated AGENTS.md with new architecture documentation

Previous improvements included in this commit:
- Renamed display methods for consistency (display_template, display_section)
- Reduced variable map lookups in reset_disabled_bool_variables()
- Improved exception hierarchy (VariableValidationError, VariableError)
- Extracted error context building to TemplateErrorHandler class
- Fixed VariableSection forward reference in variable.py

All ruff checks pass. Tested with compose list and compose show commands.

Relates to #1364

* refactor(display): complete optimization with settings, helpers, and method splitting

Major improvements to display.py architecture:

1. DisplaySettings Class (65 lines):
   - Centralized all hardcoded values (colors, styles, layouts, text labels)
   - Easy customization via single class
   - Constants: colors, styles, padding, sizes, labels, etc.

2. Helper Methods in DisplayManager:
   - _format_library_display() - eliminates duplicate library formatting
   - _truncate_value() - centralized value truncation logic
   - _format_file_size() - human-readable size formatting (B, KB, MB)

3. Split render_variables_table() (91 → 56 lines):
   - Extracted _render_section_header() (20 lines)
   - Extracted _render_variable_row() (35 lines)
   - Main method now cleaner coordinator logic

4. Updated All Managers to Use Settings:
   - VariableDisplayManager: uses all style/color/text constants
   - TemplateDisplayManager: uses settings and _format_library_display()
   - StatusDisplayManager: uses color scheme constants
   - TableDisplayManager: uses helpers and settings throughout

5. Removed Code Duplication:
   - Library display logic (was in 2 places)
   - File size formatting (was in 1 place)
   - Value truncation (was in 2 places with different logic)
   - Sensitive masking (consolidated)

Benefits:
- Single source of truth for all display configuration
- Easy to theme/customize CLI appearance
- Better testability (helpers can be unit tested)
- Reduced duplication
- More maintainable (change color scheme in one place)

File stats: 1343 → 1337 lines (-6 lines despite adding 65-line settings class)
All tests pass: compose list, compose show traefik
Linting: ruff checks passed

Relates to #1364

* refactor(display): split display.py into separate manager modules

- Created cli/core/display/ package structure
- Split DisplayManager into specialized managers:
  - VariableDisplayManager: variable rendering
  - TemplateDisplayManager: template display
  - StatusDisplayManager: status messages and errors
  - TableDisplayManager: table rendering
- Moved DisplaySettings and IconManager to __init__.py
- Maintained backward compatibility through delegation methods
- All imports remain unchanged (from cli.core.display import DisplayManager)
- Follows Single Responsibility Principle for better maintainability

* docs(changelog): add display module refactoring entry

* refactor(display): separate DisplaySettings, IconManager, and DisplayManager into individual files

- Moved DisplaySettings to display_settings.py
- Moved IconManager to icon_manager.py
- Moved DisplayManager to display_manager.py
- Updated __init__.py to only handle imports/exports (27 lines vs 526)
- Each file now has single, clear responsibility
- Better adherence to Single Responsibility Principle
- Updated AGENTS.md with new structure and ruff formatting instructions

* style: apply ruff formatting to entire codebase

* fix(display): simplify section disabled label logic and fix table row styling

- Fixed table row styling being added as 5th column instead of style parameter
- Simplified disabled label logic: show (disabled) if section has toggle and is not enabled
- Removed redundant has_dependencies parameter from _render_section_header
- Now all disabled toggle sections consistently show (disabled) label

* refactor(display): standardize table header styling across CLI

- Enforce consistent STYLE_TABLE_HEADER ('bold blue') for all tables via _print_table()
- Remove optional style parameter logic from table header styling
- Remove separate heading() calls before tables for cleaner output
- Ensure uniform table appearance throughout compose, repo, and config commands

* updated changelog

* updated changelog and description for code quality

* feature(ci): Add Ruff linting configuration and GitHub Actions workflow

- Add Ruff configuration to pyproject.toml with PEP 8 compliance
  - Line length: 88 characters
  - Indentation: 4 spaces (PEP 8 standard)
  - Enable comprehensive rule sets (pycodestyle, pyflakes, isort, pylint, etc.)
- Create .github/workflows/codequality-ruff.yaml
  - Runs on PRs to main and pushes to main/release/* branches
  - Checks both linting and formatting (blocking)
- Fix yamllint errors in config.yaml and release workflow
- Remove whitespace from table_display.py

Related to #1318

* fixed some ruff errors

* feat(compose): add --var and --var-file support to show command (#1421)

- Add --var and --var-file options to show command
- Apply same variable precedence as generate command
- Update CHANGELOG.md with feature description
- Users can now preview variable overrides before generating files

* started developing new functions

* critical updates to templates

* updates to the template tags

* n8n template preparation

* traefik security headers

* version pinning for twingate-connector

* template fix

* recent template updates

* traefik template publish

* n8n tags

* prometheus update

* fix(compose): use CF_API_TOKEN_FILE for Cloudflare API token in Traefik

* fix bug in schema 1.1

* renovate draft template

* make updates to renovate

* code quality updates

* feat: Add schema 1.2 with dedicated volume and resources sections

- Add spec_v1_2.py with new volume and resources sections
- Volume section: Replaces swarm_volume_* vars, works universally
- Resources section: CPU/memory limits for production deployments
- Ports section: Add ports_http and ports_https variables
- Update compose module to support schema 1.2
- Create new v2 archetypes:
  - service-volumes-v2.j2: Uses volume_mode
  - volumes-v2.j2: Top-level volumes with new section
  - service-resources-v1.j2: Resource limits

Related: #1519

* fixed #1522 and archetype improvements

* fixed issues in archetypes

* prepare other templates

* prepare other templates

* fix(variable): correct email validation regex

Fixed malformed email validation regex that was matching literal
backslash-s characters instead of whitespace. Changed from
r"^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$" to
r"^[^@\s]+@[^@\s]+\.[^@\s]+$"

Fixes #1481

* fix(variable): replace regex with RFC-compliant email validation

Replaced regex-based email validation with email-validator library.
Regex cannot properly validate emails per RFC 5322/5321 - it fails
on valid addresses like "John Doe"@example.com, user+tag@example.com.

Changes:
- Added email-validator>=2.0.0 dependency to pyproject.toml
- Removed EMAIL_REGEX constant
- Updated _convert_email() to use validate_email() function
- Returns normalized email addresses
- Provides better error messages for invalid emails

Fixes #1481

* prepare migration for other modules

* ruff fixes

* fix(template): gracefully handle missing 'needs' dependencies

When a section's 'needs' dependency references a non-existent section,
the CLI now logs a warning instead of raising an error. This allows
templates to be modified without breaking when dependencies are removed.

Closes #1428

* fix(template): skip empty files during generation (#1518) (#1530)

* big update

* docs: add markdown support to changelog (#1471)

* feature(install): add auto-install for dependencies on Linux and macOS

- Auto-detects OS and Linux distribution
- Installs python3, pip, git, and pipx if missing
- Supports Ubuntu, Debian, Fedora, RHEL, CentOS, Rocky, AlmaLinux, openSUSE, Arch, Manjaro, Alpine, and macOS
- Adds --no-auto-install flag to skip automatic installation
- Improves error messages with clear installation instructions

Closes #1517

* fix(install): handle PEP 668 externally-managed environments

- Try installing pipx from system packages first
- Fall back to pip with --break-system-packages flag for PEP 668
- Add pipx package names for each distro
- Improve pipx ensurepath handling

* fix(install): improve pipx installation error handling

- Properly suppress stderr when trying system package installation
- Better conditional logic for pip installation with --break-system-packages
- Add success logging for each installation method

* fix(install): suppress pip error output by checking success

- Use grep to check for 'Successfully installed' instead of exit codes
- This suppresses PEP 668 error output when trying pip methods
- Provides helpful error message suggesting manual apt install

* fix(install): handle distros without VERSION_ID in os-release

- Arch Linux and some other rolling distros don't have VERSION_ID
- Use parameter expansion to set empty default

* fix(install): add support for archarm distribution

- OrbStack Arch Linux uses 'archarm' as distribution ID
- Add it to the Arch Linux case pattern

* chore: add build/ and dist/ to .gitignore

- Ignore Python build artifacts
- Ignore distribution packages

* fix: add 'boilerplates' prefix to command suggestions in help text

- Update help messages to show 'boilerplates repo update' instead of 'repo update'
- Makes it clearer that commands should be run with the boilerplates CLI prefix
- Addresses user feedback from issue #1517

* feat(gitlab): integrate improvements from template/1372 with schema 1.2

- Add .env.j2 for environment variables (root password)
- Add container_hostname, root_email, root_password variables
- Add initial root user configuration to gitlab.rb
- Add default_theme, default_color_mode, disable_usage_data settings
- Improve template description and next_steps documentation
- Add env_file and swarm configs/secrets support
- Update to use schema 1.2 volume section (volume_mode instead of swarm_volume_*)
- Fix registry port from 5678 to standard 5000
- Add swarm placement constraints support
- Update ports section to include ports_https

* archetype validation testing

* schema1.2-traefik_domain

* feat(traefik): add multiple DNS challenge providers

- Add support for Porkbun, GoDaddy, DigitalOcean, Route53 (AWS), Azure, GCP, and Namecheap
- Add provider-specific credential variables with conditional visibility
- Support both standard and Docker Swarm modes for all providers
- Update environment variable handling for each provider

Closes #1478

* fix repo and changelog

* feature(docs): add GitHub Action to auto-generate wiki variable documentation

- Created .github/scripts/generate_wiki_docs.py script

- Generates markdown documentation for all module variables

- Uses latest schema version for each module

- Created workflow to auto-update wiki on schema changes

- Workflow triggers on changes to module specs and script

- Runs on release/v0.1.0 branch (will switch to main later)

Relates to #1316

* docs(wiki): add prominent Contributing section with CONTRIBUTING.md link

- Added Contributing section in Developer Documentation area

- Links directly to CONTRIBUTING.md in repository

- Highlights key points: CLI requires Discord, templates welcome PRs

Relates to #1316

* Documentation

* template updates

* template updates

* fix(compose): add Loki batching configuration to Alloy template

- Add batch_wait (5s) and batch_size (1MB) to reduce request volume
- Add max_backoff (5m) and min_backoff (500ms) for retry reliability
- Prevents ingestion rate limit errors with multiple Alloy instances
- Reduces HTTP overhead and improves compression efficiency

Fixes #1556

* updates

* update schema

* update

* fix ruff

* update wiki

* fix wiki

* fix wiki

* refactor(workflows): rename and extend wiki sync workflow

- Rename docs-update-wiki-variables.yaml to docs-update-wiki.yaml
- Add syncing of static wiki pages from .wiki/ directory
- Add .wiki/** to workflow triggers
- Improve commit message and workflow description

* fix(workflows): improve wiki branch detection for new wikis

- Add fallback to current branch if symbolic ref doesn't exist
- Prevents 'invalid refspec' error on newly created wikis

* fix(workflows): simplify wiki workflow by assuming master branch

- Remove complex branch detection that was causing empty variable issues
- Hardcode master branch (GitHub wikis default)
- Remove unnecessary initialization check (wiki must exist for checkout to succeed)
- Simplify commit message

* update email settings

* fix wiki

* big template updates 1

* big template updates 1

* template refactoring 2

* working on templates 2

* working on templates 3

* refactoring updates

* release-test-1

* release-test-2

* fix(templates): resolve yamllint errors - add missing newlines and remove duplicate key

* fix(templates): resolve yamllint line-length warnings in descriptions
This commit is contained in:
Christian Lempa
2025-12-10 16:02:30 +01:00
committed by GitHub
parent c77186a385
commit f856aef030
301 changed files with 19766 additions and 9945 deletions
+200 -9
View File
@@ -4,6 +4,7 @@ set -euo pipefail
REPO_OWNER="christianlempa"
REPO_NAME="boilerplates"
VERSION="${VERSION:-latest}"
AUTO_INSTALL="${AUTO_INSTALL:-true}"
usage() {
cat <<USAGE
@@ -12,12 +13,13 @@ Usage: install.sh [OPTIONS]
Install the boilerplates CLI from GitHub releases via pipx.
Options:
--version VER Version to install (default: "latest")
-h, --help Show this message
--version VER Version to install (default: "latest")
--no-auto-install Skip automatic dependency installation
-h, --help Show this message
Examples:
curl -qfsSL https://raw.githubusercontent.com/$REPO_OWNER/$REPO_NAME/main/scripts/install.sh | bash
curl -qfsSL https://raw.githubusercontent.com/$REPO_OWNER/$REPO_NAME/main/scripts/install.sh | bash -s -- --version v1.0.0
curl -fsSL https://raw.githubusercontent.com/$REPO_OWNER/$REPO_NAME/main/scripts/install.sh | bash
curl -fsSL https://raw.githubusercontent.com/$REPO_OWNER/$REPO_NAME/main/scripts/install.sh | bash -s -- --version v1.0.0
Uninstall:
pipx uninstall boilerplates
@@ -27,18 +29,203 @@ USAGE
log() { printf '[boilerplates] %s\n' "$*" >&2; }
error() { printf '[boilerplates][error] %s\n' "$*" >&2; exit 1; }
detect_os() {
if [[ "$OSTYPE" == "darwin"* ]]; then
OS_TYPE="macos"
elif [[ -f /etc/os-release ]]; then
OS_TYPE="linux"
. /etc/os-release
DISTRO_ID="$ID"
DISTRO_VERSION="${VERSION_ID:-}"
else
OS_TYPE="unknown"
fi
}
install_dependencies_macos() {
log "Detected macOS"
if ! command -v brew >/dev/null 2>&1; then
log "Homebrew not found. Installing Homebrew..."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || error "Failed to install Homebrew"
fi
if ! command -v python3 >/dev/null 2>&1; then
log "Installing Python3..."
brew install python3 || error "Failed to install Python3"
fi
if ! command -v git >/dev/null 2>&1; then
log "Installing git..."
brew install git || error "Failed to install git"
fi
if ! command -v pipx >/dev/null 2>&1; then
log "Installing pipx..."
brew install pipx || error "Failed to install pipx"
pipx ensurepath
fi
}
install_dependencies_linux() {
log "Detected Linux ($DISTRO_ID)"
case "$DISTRO_ID" in
ubuntu|debian|pop|linuxmint|elementary)
PKG_MANAGER="apt"
PYTHON_PKG="python3 python3-pip python3-venv"
PIPX_PKG="pipx"
GIT_PKG="git"
UPDATE_CMD="sudo apt update"
INSTALL_CMD="sudo apt install -y"
;;
fedora|rhel|centos|rocky|almalinux)
PKG_MANAGER="dnf"
PYTHON_PKG="python3 python3-pip"
PIPX_PKG="pipx"
GIT_PKG="git"
UPDATE_CMD="sudo dnf check-update || true"
INSTALL_CMD="sudo dnf install -y"
;;
opensuse*|sles)
PKG_MANAGER="zypper"
PYTHON_PKG="python3 python3-pip"
PIPX_PKG="python3-pipx"
GIT_PKG="git"
UPDATE_CMD="sudo zypper refresh"
INSTALL_CMD="sudo zypper install -y"
;;
arch|archarm|manjaro|endeavouros)
PKG_MANAGER="pacman"
PYTHON_PKG="python python-pip"
PIPX_PKG="python-pipx"
GIT_PKG="git"
UPDATE_CMD="sudo pacman -Sy"
INSTALL_CMD="sudo pacman -S --noconfirm"
;;
alpine)
PKG_MANAGER="apk"
PYTHON_PKG="python3 py3-pip"
PIPX_PKG="pipx"
GIT_PKG="git"
UPDATE_CMD="sudo apk update"
INSTALL_CMD="sudo apk add"
;;
*)
log "Unsupported Linux distribution: $DISTRO_ID"
log "Please install manually: python3, pip, git, and pipx"
return 1
;;
esac
if ! command -v python3 >/dev/null 2>&1; then
log "Installing Python3..."
$UPDATE_CMD
$INSTALL_CMD $PYTHON_PKG || error "Failed to install Python3"
fi
if ! command -v git >/dev/null 2>&1; then
log "Installing git..."
$INSTALL_CMD $GIT_PKG || error "Failed to install git"
fi
if ! python3 -m pip --version >/dev/null 2>&1; then
log "pip not available, installing..."
$INSTALL_CMD $PYTHON_PKG || error "Failed to install pip"
fi
if ! command -v pipx >/dev/null 2>&1 && [[ ! -x "$(python3 -m site --user-base 2>/dev/null)/bin/pipx" ]]; then
log "Installing pipx..."
# Try system package first if available
if [[ -n "${PIPX_PKG:-}" ]]; then
if $INSTALL_CMD $PIPX_PKG >/dev/null 2>&1; then
log "pipx installed from system package"
else
# System package failed, try pip with --break-system-packages
if python3 -m pip install --user --break-system-packages pipx 2>&1 | grep -q "Successfully installed"; then
log "pipx installed via pip"
elif python3 -m pip install --user pipx 2>&1 | grep -q "Successfully installed"; then
log "pipx installed via pip"
else
error "Failed to install pipx. Try installing manually: sudo apt install pipx"
fi
fi
else
# No system package, use pip
if python3 -m pip install --user --break-system-packages pipx 2>&1 | grep -q "Successfully installed"; then
log "pipx installed via pip"
elif python3 -m pip install --user pipx 2>&1 | grep -q "Successfully installed"; then
log "pipx installed via pip"
else
error "Failed to install pipx"
fi
fi
# Ensure pipx is in PATH
if command -v pipx >/dev/null 2>&1; then
pipx ensurepath >/dev/null 2>&1
elif [[ -x "$(python3 -m site --user-base 2>/dev/null)/bin/pipx" ]]; then
"$(python3 -m site --user-base)/bin/pipx" ensurepath >/dev/null 2>&1
fi
fi
}
check_dependencies() {
command -v tar >/dev/null 2>&1 || error "tar is required but not found"
command -v mktemp >/dev/null 2>&1 || error "mktemp is required but not found"
command -v python3 >/dev/null 2>&1 || error "Python 3 is required. Install: sudo apt install python3 python3-pip"
python3 -m pip --version >/dev/null 2>&1 || error "pip is required. Install: sudo apt install python3-pip"
local missing_deps=()
command -v tar >/dev/null 2>&1 || missing_deps+=("tar")
command -v mktemp >/dev/null 2>&1 || missing_deps+=("mktemp")
if [[ ${#missing_deps[@]} -gt 0 ]]; then
error "Required system tools missing: ${missing_deps[*]}"
fi
local needs_install=false
if ! command -v python3 >/dev/null 2>&1; then
log "Python3 not found"
needs_install=true
fi
if ! command -v git >/dev/null 2>&1; then
log "git not found"
needs_install=true
fi
if ! python3 -m pip --version >/dev/null 2>&1; then
log "pip not found"
needs_install=true
fi
if ! command -v pipx >/dev/null 2>&1 && [[ ! -x "$(python3 -m site --user-base 2>/dev/null)/bin/pipx" ]]; then
log "pipx not found"
needs_install=true
fi
if [[ "$needs_install" == "true" ]]; then
if [[ "$AUTO_INSTALL" == "true" ]]; then
log "Installing missing dependencies..."
detect_os
if [[ "$OS_TYPE" == "macos" ]]; then
install_dependencies_macos
elif [[ "$OS_TYPE" == "linux" ]]; then
install_dependencies_linux
else
error "Unsupported OS. Please install manually: python3, pip, git, and pipx"
fi
else
error "Missing dependencies. Install: python3, pip, git, and pipx (or run without --no-auto-install)"
fi
fi
if command -v pipx >/dev/null 2>&1; then
PIPX_CMD="pipx"
elif [[ -x "$(python3 -m site --user-base 2>/dev/null)/bin/pipx" ]]; then
PIPX_CMD="$(python3 -m site --user-base)/bin/pipx"
else
error "pipx is required. Install: pip install --user pipx"
error "pipx installation failed or not found in PATH. Try: python3 -m pip install --user pipx && python3 -m pipx ensurepath"
fi
log "All dependencies available"
@@ -53,6 +240,10 @@ parse_args() {
VERSION="$2"
shift 2
;;
--no-auto-install)
AUTO_INSTALL="false"
shift
;;
-h|--help) usage; exit 0 ;;
*) error "Unknown option: $1" ;;
esac