Skip to content

Implement artifact generation command #326

@josecelano

Description

@josecelano

Overview

Add a command that generates all deployment artifacts (docker-compose files, tracker configuration, Ansible playbooks, Caddy configuration, etc.) to a user-specified output directory without executing any deployment operations. This enables users who want the generated configuration files but prefer to handle deployment manually.

This complements the validate command (which validates input without generating artifacts) and forms part of the "lightweight adoption" trilogy for flexible tool usage.

Specification

See detailed specification: docs/issues/artifact-generation-command.md

(Link will be updated after file rename with issue number)

🏗️ Architecture Requirements

DDD Layers: Application + Infrastructure (template rendering)

Module Paths:

  • src/application/command_handlers/render/ (or generate) - Command handler (new)
  • src/presentation/controllers/render/ - CLI controller (new)
  • src/infrastructure/external_tools/ansible/template/renderer/ - Reuse existing
  • src/infrastructure/external_tools/docker/template/renderer/ - Reuse existing

Pattern: Command Handler + Template Renderers (reuse from Release/Configure)

Module Structure Requirements

  • Follow DDD layer separation (see docs/codebase-architecture.md)
  • Application layer orchestrates template generation (no business logic in CLI)
  • Infrastructure layer handles actual template rendering (Tera, file I/O)
  • No remote operations (pure local artifact generation)
  • Use appropriate module organization (see docs/contributing/module-organization.md)

Architectural Constraints

  • Must reuse existing template renderers (no duplication)
  • No state transitions - operates on any environment state
  • No remote operations - purely local file generation
  • --output-dir is REQUIRED (avoid conflicts with internal build/ directory)
  • Instance IP is REQUIRED (from environment data OR --ip flag)
  • Error handling follows project conventions
  • User output through UserOutput abstraction

Anti-Patterns to Avoid

  • ❌ Duplicating template rendering logic
  • ❌ Executing remote operations (Ansible, SSH, etc.)
  • ❌ Modifying environment state
  • ❌ Using internal build/ directory for user-facing output
  • ❌ Hardcoding output paths

Implementation Plan

Phase 1: Application Layer - Command Handler (2-3 hours)

  • Create src/application/command_handlers/render/mod.rs
  • Create RenderCommandHandler struct
  • Define RenderInput (environment name OR config file path + IP, plus output directory)
  • Define RenderOutput (output directory path + target IP)
  • Define RenderCommandHandlerError enum
  • Implement dual input modes (from environment data OR config file + explicit IP)
  • Add IP address validation
  • Add comprehensive error messages with actionable instructions
  • Add unit tests for command handler logic

Phase 2: Template Orchestration (3-4 hours)

  • Identify all existing template renderers
  • Create orchestration logic to invoke ALL renderers (no conditional logic)
  • Ensure all artifacts write to user-specified output directory subdirectories
  • Pass IP address to Ansible inventory template renderer
  • Add progress indicators using UserOutput
  • Add integration tests verifying all templates rendered with correct IP

Phase 3: Presentation Layer - CLI Command (2 hours)

  • Create src/presentation/controllers/render/mod.rs
  • Create RenderCommandController
  • Add CLI argument parsing (--env-name, --env-file, --ip, --output-dir, --force)
  • Implement input validation (mutually exclusive flags, required parameters)
  • Connect to RenderCommandHandler
  • Format output using UserOutput (progress, success, output directory path, target IP)
  • Handle errors with clear messages
  • Add help text and examples
  • Add unit tests for controller logic

Phase 4: Documentation and Testing (2-3 hours)

  • Create user guide: docs/user-guide/commands/render.md
  • Update docs/console-commands.md with render command
  • Update roadmap (docs/roadmap.md) - mark task 9.2 complete
  • Add E2E tests (both input modes, IP validation, error conditions, --force flag)
  • Run pre-commit checks: ./scripts/pre-commit.sh

Phase 5: Polish and Review (1-2 hours)

  • Review generated artifact quality
  • Verify no external operations triggered
  • Test with various configuration combinations
  • Verify output messages are clear and actionable
  • Ensure consistent with project conventions
  • Final documentation review

Total Estimated Time: 10-14 hours

Acceptance Criteria

Note for Contributors: These criteria define what the PR reviewer will check. Use this as your pre-review checklist before submitting the PR to minimize back-and-forth iterations.

Quality Checks:

  • Pre-commit checks pass: ./scripts/pre-commit.sh

Functional Requirements:

  • Command generates all artifacts for given environment (from --env-name + --output-dir)
  • Command generates all artifacts from config file (from --env-file + --ip + --output-dir)
  • Both input modes produce identical output for same configuration and IP
  • --output-dir is REQUIRED (command fails without it)
  • --ip is REQUIRED when using --env-file (command fails without it)
  • --ip is FORBIDDEN when using --env-name (command fails if provided)
  • IP address is validated for correct format
  • IP address is correctly written to Ansible inventory template
  • ALL templates are ALWAYS generated (no conditional rendering)
  • All artifact types present: infrastructure, Ansible, docker-compose, tracker, monitoring, Caddy, backup
  • Artifacts written to user-specified output directory (NOT internal build/ directory)
  • Output directory path and target IP shown in success message (no file list)
  • No remote operations executed (no SSH, no Ansible playbook runs)
  • No environment state modifications
  • Command works from existing environment OR just config file + IP
  • Clear success message with output path and target IP (simplified, no file list)
  • Clear error messages for all failure scenarios
  • --force flag overwrites existing output directory
  • Without --force, fails if output directory exists

Code Quality:

  • Follows DDD layer placement rules
  • Reuses existing template renderers (no duplication)
  • Error handling follows project conventions
  • User output through UserOutput abstraction
  • Proper module organization
  • Comprehensive unit tests (handler and controller)
  • Integration tests for template rendering
  • E2E tests for complete workflow

Documentation:

  • User guide created: docs/user-guide/commands/render.md
  • Console commands reference updated: docs/console-commands.md
  • Roadmap updated (task 9.2 marked complete)
  • Help text includes examples
  • Generated artifacts explained in documentation

Testing:

  • Unit tests pass
  • Integration tests pass
  • E2E tests pass
  • Tested with all provider types
  • Tested with all service configurations
  • Tested error scenarios

Related

  • Parent: Roadmap #1 (Roadmap)
  • Roadmap task: 9.2 - Implement artifact generation command
  • Specification: docs/issues/artifact-generation-command.md (will be renamed after issue creation)

Command Name Decision

Recommendation: render

  • Aligns with internal architecture (Tera template renderer)
  • Technical accuracy
  • Already used in codebase (ProjectGenerator, TemplateRenderer)

Alternative: generate (more user-friendly if render is too technical)

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions