runique 3.0.2

A Django-inspired web framework for Rust with ORM, templates, and comprehensive security middleware
Documentation
//! CLI binary `runique` — `new`, `start`, `makemigration`, `migrate` commands via clap.
use anyhow::Result;
use clap::{Parser, Subcommand};
use runique::{
    cli::{create_new_project, create_superuser, makemigration, migrate, run_tests, runique_start},
    utils::{
        init_logging,
        trad::{Lang, set_lang},
    },
};

#[derive(Parser)]
#[command(name = "runique")]
#[command(about = "Runique framework CLI", long_about = None)]
struct Cli {
    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    /// Create a new Runique project
    ///
    /// Generates the complete structure with routes, views, models and templates.
    New { name: String },

    /// Start Runique services (from the project root)
    ///
    /// Automatically detects the project configuration:
    ///   - If `.with_admin(...)` is present in src/main.rs → starts the `AdminPanel` daemon
    ///   - Otherwise → nothing to do
    Start {
        /// Path to src/main.rs (default: ./src/main.rs)
        #[arg(long, default_value = "src/main.rs")]
        main: String,

        /// Path to src/admin.rs (default: ./src/admin.rs)
        #[arg(long, default_value = "src/admin.rs")]
        admin: String,
    },
    /// Create an admin superuser
    CreateSuperuser,

    /// Run the project's runique tests (src/runique_test/)
    ///
    /// Each test runs against your database inside a transaction that always
    /// gets rolled back. `runique test` runs them all, `runique test user` only
    /// src/runique_test/user.rs, `runique test user add_email` a single test.
    Test {
        /// Test file in src/runique_test/, without the .rs
        file: Option<String>,
        /// Test function in that file
        test: Option<String>,
    },
    Migration {
        #[command(subcommand)]
        action: MigrateAction,
    },
    Makemigrations {
        #[arg(long, default_value = "src/entities")]
        entities: String,
        #[arg(long, default_value = "migration/src")]
        migrations: String,
        #[arg(long, default_value = "false")]
        force: bool,
    },
}

#[derive(Subcommand)]
enum MigrateAction {
    Up {
        #[arg(long, default_value = "migration/src")]
        migrations: String,
    },
}

#[tokio::main]
async fn main() -> Result<()> {
    let _log_guards = init_logging();
    dotenvy::dotenv_override().ok();

    if let Some(lang) = Lang::from_env() {
        set_lang(lang);
    }

    let cli = Cli::parse();

    match cli.command {
        Commands::New { name } => create_new_project(&name)?,
        Commands::Start { main, admin } => runique_start(&main, &admin)?,
        Commands::CreateSuperuser => create_superuser().await?,
        Commands::Test { file, test } => run_tests(file.as_deref(), test.as_deref())?,
        Commands::Migration { action } => match action {
            MigrateAction::Up { migrations } => {
                migrate::up(&migrations).await?;
            }
        },
        Commands::Makemigrations {
            entities,
            migrations,
            force,
        } => {
            makemigration::run(&entities, &migrations, force)?;
        }
    }

    Ok(())
}