use clap::{Args, Parser, Subcommand};
#[derive(Parser)]
#[command(
name = "exe",
about = "ExecuteSoft repository tooling",
long_about = "ExecuteSoft repository tooling for service generation, compliance checks, gateway route generation, local development, database helpers, sync, release, and deployment workflows.",
after_long_help = "Examples:\n exe setup\n exe dev\n exe service check-all\n exe service create --name recommendation-engine --domain core --template rust\n exe gateway route entry --service auth --rpc Login\n exe gateway generate\n exe dev up\n exe release-sync\n exe deploy kubernetes tag=latest"
)]
pub(crate) struct Cli {
#[command(subcommand)]
pub(crate) command: Commands,
}
#[derive(Subcommand)]
pub(crate) enum Commands {
#[command(about = "Create, validate, build, test, and run services")]
Service {
#[command(subcommand)]
command: ServiceCommand,
},
#[command(about = "Generate and validate public gateway route artifacts")]
Gateway {
#[command(subcommand)]
command: GatewayCommand,
},
#[command(about = "Run service database migration helpers")]
Db {
#[command(subcommand)]
command: DbCommand,
},
#[command(
about = "Prepare a service-only checkout for development",
long_about = "Prepare the current service checkout: validate service.yaml, run local generators, download language dependencies, and start service-local Docker dependencies when development/compose.dev.yml exists."
)]
Setup(KeyValueArgs),
#[command(
about = "Run service-local dev mode or manage the platform development stack",
long_about = "Run plain `exe dev` inside a service checkout to start dependencies and hot-reload that service. Use subcommands such as `exe dev up` or `exe dev all` from the platform repository to manage shared local infrastructure."
)]
Dev {
#[command(subcommand)]
command: Option<DevCommand>,
},
#[command(about = "Sync service assets before release or deployment")]
Sync,
#[command(about = "Run the release workflow, for example: exe release tag=latest")]
Release(KeyValueArgs),
#[command(about = "Upload the local devops folder to the production server")]
ReleaseSync(KeyValueArgs),
#[command(about = "Run deployment workflows")]
Deploy {
#[command(subcommand)]
command: DeployCommand,
},
}
#[derive(Subcommand)]
pub(crate) enum ServiceCommand {
#[command(about = "Validate one service or template skeleton against the compliance contract")]
Check {
#[arg(help = "Service directory, for example services/core/auth")]
path: String,
},
#[command(about = "Validate all service roots and certified template skeletons")]
CheckAll,
#[command(about = "Create a service from a certified template")]
Create(CreateServiceArgs),
#[command(about = "Run the service test workflow")]
Test(ServiceTargetArgs),
#[command(about = "Run the service build workflow")]
Build(ServiceTargetArgs),
#[command(about = "Run the service generation workflow")]
Generate(ServiceTargetArgs),
#[command(about = "Run the service locally")]
Run(ServiceTargetArgs),
#[command(about = "Run the Rust clippy workflow for a service")]
Clippy(ServiceTargetArgs),
#[command(about = "Run service compliance checks")]
Compliance(ServiceTargetArgs),
#[command(about = "Validate a service gateway route source file")]
GatewayRoutesCheck(ServiceTargetArgs),
}
#[derive(Args)]
pub(crate) struct CreateServiceArgs {
#[arg(help = "Service key, for example recommendation-engine")]
#[arg(long, alias = "service")]
pub(crate) name: String,
#[arg(
help = "Service domain folder under services/",
long,
default_value = "core"
)]
pub(crate) domain: String,
#[arg(
help = "Template language: go, rust, python, or typescript",
long = "template",
alias = "tpl",
default_value = "go"
)]
pub(crate) template_lang: String,
#[arg(help = "Template service type", long = "type", default_value = "grpc")]
pub(crate) service_type: String,
#[arg(help = "Template framework variant", long, default_value = "native")]
pub(crate) framework: String,
#[arg(help = "Owning team metadata")]
#[arg(long)]
pub(crate) owner_team: Option<String>,
#[arg(help = "Output directory; defaults to services/<domain>/<name>")]
#[arg(long)]
pub(crate) output: Option<String>,
#[arg(help = "Override template metadata name")]
#[arg(long)]
pub(crate) template_name: Option<String>,
#[arg(help = "Override generated protobuf package")]
#[arg(long)]
pub(crate) proto_package: Option<String>,
#[arg(help = "Override generated protobuf service class prefix")]
#[arg(long)]
pub(crate) service_class: Option<String>,
}
#[derive(Args)]
pub(crate) struct ServiceTargetArgs {
#[arg(help = "Service name or service path, for example auth or services/core/auth")]
pub(crate) target: String,
#[arg(
help = "Extra Make variables, for example TAG=latest or --image-tag=v1",
trailing_var_arg = true,
allow_hyphen_values = true
)]
pub(crate) vars: Vec<String>,
}
#[derive(Subcommand)]
pub(crate) enum GatewayCommand {
#[command(about = "Regenerate gateway routes, permissions, mappers, and OpenAPI")]
Generate,
#[command(about = "Create gateway route source files")]
Route {
#[command(subcommand)]
command: GatewayRouteCommand,
},
#[command(about = "Validate gateway route source JSON files")]
ValidateRoutes {
#[arg(help = "Route JSON files to validate")]
files: Vec<String>,
},
}
#[derive(Subcommand)]
pub(crate) enum GatewayRouteCommand {
#[command(about = "Create a route source file for a service")]
Create(GatewayRouteArgs),
#[command(about = "Create or update route source from protobuf RPCs")]
FromProto(GatewayRouteArgs),
#[command(about = "Add one RPC route entry to a service route source")]
Entry(GatewayRouteEntryArgs),
}
#[derive(Args)]
pub(crate) struct GatewayRouteArgs {
#[arg(help = "Service key, for example auth", long, alias = "name")]
pub(crate) service: String,
#[arg(help = "Overwrite an existing route source when supported", long)]
pub(crate) force: bool,
#[arg(
help = "Append generated routes instead of replacing when supported",
long
)]
pub(crate) append: bool,
}
#[derive(Args)]
pub(crate) struct GatewayRouteEntryArgs {
#[arg(help = "Service key, for example auth", long, alias = "name")]
pub(crate) service: String,
#[arg(help = "RPC method name to add", long)]
pub(crate) rpc: String,
#[arg(help = "Overwrite an existing route source when supported", long)]
pub(crate) force: bool,
#[arg(
help = "Append generated routes instead of replacing when supported",
long
)]
pub(crate) append: bool,
}
#[derive(Subcommand)]
pub(crate) enum DbCommand {
#[command(about = "Run pending database migrations")]
Migrate(KeyValueArgs),
#[command(about = "Apply database migrations")]
Up(KeyValueArgs),
#[command(about = "Show database migration status")]
Status(KeyValueArgs),
#[command(about = "Revert the last database migration")]
Revert(KeyValueArgs),
#[command(about = "Rollback database migrations")]
Down(KeyValueArgs),
#[command(about = "Reset database state for local development")]
Reset(KeyValueArgs),
#[command(about = "Create a new migration file; pass NAME=create_table")]
New(KeyValueArgs),
}
#[derive(Subcommand)]
pub(crate) enum DevCommand {
#[command(about = "Start local dependencies")]
Up(KeyValueArgs),
#[command(about = "Start the full local development stack")]
All(KeyValueArgs),
#[command(about = "Build the local development stack")]
Build(KeyValueArgs),
#[command(about = "Stop the local development stack")]
Down(KeyValueArgs),
#[command(about = "Tail local dependency logs")]
Logs(KeyValueArgs),
#[command(about = "Stop and remove local development volumes")]
Reset(KeyValueArgs),
#[command(about = "Run a command with simple polling hot reload")]
Watch(WatchArgs),
}
#[derive(Args)]
pub(crate) struct WatchArgs {
#[arg(
help = "Environment file to load",
long,
default_value = "configs/app.env.example"
)]
pub(crate) env_file: String,
#[arg(help = "Directory to watch", long = "watch", default_value = ".")]
pub(crate) watch_root: String,
#[arg(help = "File basename to ignore; can be repeated", long)]
pub(crate) ignore: Vec<String>,
#[arg(help = "Polling interval in seconds", long, default_value_t = 1.0)]
pub(crate) poll: f64,
#[arg(help = "Command to run after --", last = true, required = true)]
pub(crate) command: Vec<String>,
}
#[derive(Subcommand)]
pub(crate) enum DeployCommand {
#[command(about = "Sync assets and deploy Kubernetes manifests")]
Kubernetes(KeyValueArgs),
#[command(about = "Build or deploy Docker artifacts")]
Docker(KeyValueArgs),
#[command(about = "Apply production service database migrations")]
Migrations(KeyValueArgs),
#[command(about = "Temporarily enable full observability stack")]
ObservabilityUp(KeyValueArgs),
#[command(about = "Return observability stack to balanced mode")]
ObservabilityDown(KeyValueArgs),
#[command(about = "Run the Postgres backup job once")]
BackupNow(KeyValueArgs),
#[command(about = "Install the daily host cron backup")]
InstallBackupCron(KeyValueArgs),
#[command(about = "Upload the local devops folder to the production server")]
ReleaseSync(KeyValueArgs),
#[command(about = "Reload Caddy on the production Docker host")]
ReloadCaddy(KeyValueArgs),
#[command(about = "Restart the CDN container")]
RestartCdn(KeyValueArgs),
#[command(about = "Force-recreate a Docker Compose service; pass CONTAINER=cdn")]
Recreate(KeyValueArgs),
}
#[derive(Args, Clone)]
pub(crate) struct KeyValueArgs {
#[arg(
help = "Workflow variables as key=value pairs, for example tag=latest",
trailing_var_arg = true,
allow_hyphen_values = true
)]
pub(crate) vars: Vec<String>,
}