lmrc-cli 0.3.16

CLI tool for scaffolding LMRC Stack infrastructure projects
Documentation
use crate::commands;
use crate::error::Result;
use clap::{Parser, Subcommand};

#[derive(Parser)]
#[command(name = "lmrc")]
#[command(version, about = "LMRC Stack - Infrastructure project scaffolding tool", long_about = None)]
pub struct Cli {
    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    /// Create a new LMRC Stack project (minimal workspace, add components with 'lmrc add')
    New {
        /// Project name
        name: String,

        /// Path where project will be created (defaults to current directory)
        #[arg(short, long)]
        path: Option<String>,
    },

    /// Add components to an existing project
    Add {
        #[command(subcommand)]
        component: AddCommands,
    },

    /// Generate a template configuration file
    Config {
        /// Output path for config file
        #[arg(short, long, default_value = "lmrc.toml")]
        output: String,
    },

    /// Validate an existing configuration file
    Validate {
        /// Path to configuration file
        #[arg(default_value = "lmrc.toml")]
        config: String,
    },

    /// Setup infrastructure and services
    Setup {
        #[command(subcommand)]
        target: SetupCommands,
    },

    /// Bootstrap a generated project (initialize Git, upload CI/CD variables, push to GitLab)
    #[deprecated(note = "Use 'lmrc setup' commands instead")]
    Bootstrap,

    /// Check development environment for required tools and dependencies
    Doctor {
        /// Attempt to auto-fix issues (experimental)
        #[arg(long)]
        fix: bool,
    },

    /// Local development commands
    Dev {
        #[command(subcommand)]
        action: DevCommands,
    },

    /// Destroy infrastructure and clean up all resources
    Destroy {
        /// Skip confirmation prompt
        #[arg(long)]
        confirm: bool,

        /// Project name or config file path
        #[arg(short, long)]
        project: Option<String>,
    },
}

#[derive(Subcommand)]
enum DevCommands {
    /// Start local development environment (docker-compose + build)
    Start,

    /// Stop local development environment
    Stop,

    /// Show development environment status
    Status,

    /// View logs from services
    Logs {
        /// Specific service name (optional)
        service: Option<String>,
    },
}

#[derive(Subcommand)]
enum AddCommands {
    /// Add an application to the project
    App {
        /// Application name
        name: String,

        /// Application type (api, basic, gateway, migrator)
        #[arg(short = 't', long)]
        app_type: Option<String>,
    },

    /// Add infrastructure pipeline
    Pipeline,

    /// Add GitLab CI/CD configuration
    Ci,

    /// Add documentation
    Docs,
}

#[derive(Subcommand)]
enum SetupCommands {
    /// Initialize git repository
    Git,

    /// Configure GitLab remote and push code
    Remote,

    /// Upload CI/CD secrets to GitLab
    Secrets,

    /// Provision servers on cloud provider
    Servers,

    /// Configure networking and firewall rules
    Network,

    /// Install and configure Kubernetes (K3s)
    Kubernetes,

    /// Setup PostgreSQL database
    Database,

    /// Setup RabbitMQ message queue
    Queue,

    /// Configure DNS records (Cloudflare)
    Dns,

    /// Setup ingress controller (Traefik)
    Ingress,

    /// Setup complete infrastructure (servers + network + kubernetes + database + queue + dns + ingress)
    Infra,

    /// Setup everything (git + remote + secrets + infra)
    All,
}

impl Cli {
    pub async fn execute(self) -> Result<()> {
        match self.command {
            Commands::New { name, path } => {
                commands::new::execute(name, path).await
            }
            Commands::Add { component } => {
                match component {
                    AddCommands::App { name, app_type } => {
                        commands::add::app(name, app_type).await
                    }
                    AddCommands::Pipeline => commands::add::pipeline().await,
                    AddCommands::Ci => commands::add::ci().await,
                    AddCommands::Docs => commands::add::docs().await,
                }
            }
            Commands::Config { output } => commands::config::execute(output).await,
            Commands::Validate { config } => commands::validate::execute(config).await,
            Commands::Setup { target } => {
                match target {
                    SetupCommands::Git => commands::setup::git().await,
                    SetupCommands::Remote => commands::setup::remote().await,
                    SetupCommands::Secrets => commands::setup::secrets().await,
                    SetupCommands::Servers => commands::setup::servers().await,
                    SetupCommands::Network => commands::setup::network().await,
                    SetupCommands::Kubernetes => commands::setup::kubernetes().await,
                    SetupCommands::Database => commands::setup::database().await,
                    SetupCommands::Queue => commands::setup::queue().await,
                    SetupCommands::Dns => commands::setup::dns().await,
                    SetupCommands::Ingress => commands::setup::ingress().await,
                    SetupCommands::Infra => commands::setup::infra().await,
                    SetupCommands::All => commands::setup::all().await,
                }
            }
            #[allow(deprecated)]
            Commands::Bootstrap => commands::bootstrap::execute().await,
            Commands::Doctor { fix } => commands::doctor::doctor(fix).await,
            Commands::Dev { action } => {
                match action {
                    DevCommands::Start => commands::dev::start().await,
                    DevCommands::Stop => commands::dev::stop().await,
                    DevCommands::Status => commands::dev::status().await,
                    DevCommands::Logs { service } => commands::dev::logs(service).await,
                }
            }
            Commands::Destroy { confirm, project } => {
                commands::destroy::execute(confirm, project).await
            }
        }
    }
}