Skip to main content

greentic_setup/
cli_args.rs

1//! CLI argument definitions for greentic-setup.
2
3use std::path::PathBuf;
4
5use clap::{Args, Parser, Subcommand};
6
7#[derive(Parser, Debug)]
8#[command(name = "greentic-setup")]
9#[command(version)]
10#[command(about = "Greentic bundle setup CLI")]
11#[command(after_help = r#"EXAMPLES:
12  Interactive wizard:
13    greentic-setup ./my-bundle
14
15  Preview without executing:
16    greentic-setup --dry-run ./my-bundle
17
18  Generate answers template:
19    greentic-setup --dry-run --emit-answers answers.json ./my-bundle
20
21  Apply answers file:
22    greentic-setup --answers answers.json ./my-bundle.gtbundle
23
24  Advanced (bundle subcommands):
25    greentic-setup bundle init ./my-bundle
26    greentic-setup bundle add pack.gtpack --bundle ./my-bundle
27    greentic-setup bundle status --bundle ./my-bundle
28"#)]
29pub struct Cli {
30    /// Bundle path (.gtbundle file or directory)
31    #[arg(value_name = "BUNDLE")]
32    pub bundle: Option<PathBuf>,
33
34    /// Dry run - show wizard but don't execute
35    #[arg(long = "dry-run", global = true)]
36    pub dry_run: bool,
37
38    /// Emit answers template to file (combine with --dry-run to only generate)
39    #[arg(long = "emit-answers", value_name = "FILE", global = true)]
40    pub emit_answers: Option<PathBuf>,
41
42    /// Apply answers from file
43    #[arg(long = "answers", short = 'a', value_name = "FILE", global = true)]
44    pub answers: Option<PathBuf>,
45
46    /// Encryption/decryption key for answer documents that include secrets
47    #[arg(long = "key", value_name = "KEY", global = true)]
48    pub key: Option<String>,
49
50    /// Tenant identifier
51    #[arg(long = "tenant", short = 't', default_value = "demo", global = true)]
52    pub tenant: String,
53
54    /// Team identifier
55    #[arg(long = "team", global = true)]
56    pub team: Option<String>,
57
58    /// Environment (dev/staging/prod)
59    #[arg(long = "env", short = 'e', default_value = "dev", global = true)]
60    pub env: String,
61
62    /// UI locale (BCP-47 tag, e.g., en, ja, id)
63    #[arg(long = "locale", global = true)]
64    pub locale: Option<String>,
65
66    /// Advanced mode — show all questions including optional ones
67    #[arg(long = "advanced", global = true)]
68    pub advanced: bool,
69
70    /// Launch web-based setup UI in browser (enabled by default).
71    /// Use --no-ui to disable the UI; stdin prompts may still be used.
72    #[arg(long = "ui", global = true, default_value_t = true)]
73    pub ui: bool,
74
75    /// Disable web UI; stdin prompts may still be used.
76    #[arg(long = "no-ui", global = true)]
77    pub no_ui: bool,
78
79    /// Strict non-interactive mode: no prompts, fail if answers incomplete
80    #[arg(long = "non-interactive", global = true)]
81    pub non_interactive: bool,
82
83    #[command(subcommand)]
84    pub command: Option<Command>,
85}
86
87#[derive(Subcommand, Debug)]
88pub enum Command {
89    /// Diagnose bundle setup inputs and generated setup outputs
90    Doctor(DoctorArgs),
91    /// Bundle lifecycle management (advanced)
92    #[command(subcommand)]
93    Bundle(Box<BundleCommand>),
94}
95
96#[derive(Args, Debug, Clone)]
97pub struct DoctorArgs {
98    /// Bundle path (.gtbundle file or directory)
99    #[arg(value_name = "BUNDLE")]
100    pub bundle: PathBuf,
101    /// Emit stable machine-readable JSON
102    #[arg(long = "json")]
103    pub json: bool,
104    /// Treat warnings as command failures
105    #[arg(long = "strict")]
106    pub strict: bool,
107    /// Include fix hints in human-readable output
108    #[arg(long = "fix-hints")]
109    pub fix_hints: bool,
110    /// Show informational diagnostics in human-readable output
111    #[arg(long = "show-info")]
112    pub show_info: bool,
113    /// Limit checks to one stage
114    #[arg(long = "stage", value_enum)]
115    pub stage: Option<DoctorStageArg>,
116}
117
118#[derive(clap::ValueEnum, Debug, Clone, Copy, PartialEq, Eq)]
119pub enum DoctorStageArg {
120    Setup,
121    Cache,
122    Locks,
123    Answers,
124    Runtime,
125    Routes,
126}
127
128#[derive(Subcommand, Debug, Clone)]
129pub enum BundleCommand {
130    /// Initialize a new bundle directory
131    Init(BundleInitArgs),
132    /// Add a pack to a bundle
133    Add(BundleAddArgs),
134    /// Run setup flow for provider(s) in a bundle
135    Setup(BundleSetupArgs),
136    /// Update a provider's configuration in a bundle
137    Update(BundleSetupArgs),
138    /// Remove a provider from a bundle
139    Remove(BundleRemoveArgs),
140    /// Build a portable bundle (copy + resolve)
141    Build(BundleBuildArgs),
142    /// List packs or flows in a bundle
143    List(BundleListArgs),
144    /// Show bundle status
145    Status(BundleStatusArgs),
146}
147
148#[derive(Args, Debug, Clone)]
149pub struct BundleInitArgs {
150    /// Bundle directory (default: current directory)
151    #[arg(value_name = "PATH")]
152    pub path: Option<PathBuf>,
153    /// Bundle name
154    #[arg(long = "name", short = 'n')]
155    pub name: Option<String>,
156}
157
158#[derive(Args, Debug, Clone)]
159pub struct BundleAddArgs {
160    /// Pack reference (local path or OCI reference)
161    #[arg(value_name = "PACK_REF")]
162    pub pack_ref: String,
163    /// Bundle directory (default: current directory)
164    #[arg(long = "bundle", short = 'b')]
165    pub bundle: Option<PathBuf>,
166    /// Tenant identifier
167    #[arg(long = "tenant", short = 't', default_value = "demo")]
168    pub tenant: String,
169    /// Team identifier
170    #[arg(long = "team")]
171    pub team: Option<String>,
172    /// Environment (dev/staging/prod)
173    #[arg(long = "env", short = 'e', default_value = "dev")]
174    pub env: String,
175    /// Dry run (don't actually add)
176    #[arg(long = "dry-run")]
177    pub dry_run: bool,
178}
179
180#[derive(Args, Debug, Clone)]
181pub struct BundleSetupArgs {
182    /// Provider ID to setup/update (optional, setup all if not specified)
183    #[arg(value_name = "PROVIDER_ID")]
184    pub provider_id: Option<String>,
185    /// Bundle directory (default: current directory)
186    #[arg(long = "bundle", short = 'b')]
187    pub bundle: Option<PathBuf>,
188    /// Answers file (JSON/YAML)
189    #[arg(long = "answers", short = 'a')]
190    pub answers: Option<PathBuf>,
191    /// Encryption/decryption key for answer documents that include secrets
192    #[arg(long = "key", value_name = "KEY")]
193    pub key: Option<String>,
194    /// Tenant identifier
195    #[arg(long = "tenant", short = 't', default_value = "demo")]
196    pub tenant: String,
197    /// Team identifier
198    #[arg(long = "team")]
199    pub team: Option<String>,
200    /// Environment (dev/staging/prod)
201    #[arg(long = "env", short = 'e', default_value = "dev")]
202    pub env: String,
203    /// Filter by domain (messaging/events/secrets/oauth/all)
204    #[arg(long = "domain", short = 'd', default_value = "all")]
205    pub domain: String,
206    /// Number of parallel setup operations
207    #[arg(long = "parallel", default_value = "1")]
208    pub parallel: usize,
209    /// Backup existing config before setup
210    #[arg(long = "backup")]
211    pub backup: bool,
212    /// Skip secrets initialization
213    #[arg(long = "skip-secrets-init")]
214    pub skip_secrets_init: bool,
215    /// Continue on error (best effort)
216    #[arg(long = "best-effort")]
217    pub best_effort: bool,
218    /// Populated from the global --non-interactive flag before dispatch.
219    #[arg(skip)]
220    pub non_interactive: bool,
221    /// Dry run (plan only, don't execute)
222    #[arg(long = "dry-run")]
223    pub dry_run: bool,
224    /// Emit answers template JSON (use with --dry-run)
225    #[arg(long = "emit-answers")]
226    pub emit_answers: Option<PathBuf>,
227    /// Advanced mode — show all questions including optional ones
228    #[arg(long = "advanced")]
229    pub advanced: bool,
230}
231
232#[derive(Args, Debug, Clone)]
233pub struct BundleRemoveArgs {
234    /// Provider ID to remove
235    #[arg(value_name = "PROVIDER_ID")]
236    pub provider_id: String,
237    /// Bundle directory (default: current directory)
238    #[arg(long = "bundle", short = 'b')]
239    pub bundle: Option<PathBuf>,
240    /// Tenant identifier
241    #[arg(long = "tenant", short = 't', default_value = "demo")]
242    pub tenant: String,
243    /// Team identifier
244    #[arg(long = "team")]
245    pub team: Option<String>,
246    /// Force removal without confirmation
247    #[arg(long = "force", short = 'f')]
248    pub force: bool,
249}
250
251#[derive(Args, Debug, Clone)]
252pub struct BundleBuildArgs {
253    /// Bundle directory (default: current directory)
254    #[arg(long = "bundle", short = 'b')]
255    pub bundle: Option<PathBuf>,
256    /// Output directory for portable bundle
257    #[arg(long = "out", short = 'o')]
258    pub out: PathBuf,
259    /// Tenant identifier
260    #[arg(long = "tenant", short = 't')]
261    pub tenant: Option<String>,
262    /// Team identifier
263    #[arg(long = "team")]
264    pub team: Option<String>,
265    /// Only include used providers
266    #[arg(long = "only-used-providers")]
267    pub only_used_providers: bool,
268    /// Run doctor validation after build
269    #[arg(long = "doctor")]
270    pub doctor: bool,
271    /// Skip doctor validation
272    #[arg(long = "skip-doctor")]
273    pub skip_doctor: bool,
274}
275
276#[derive(Args, Debug, Clone)]
277pub struct BundleListArgs {
278    /// Bundle directory (default: current directory)
279    #[arg(long = "bundle", short = 'b')]
280    pub bundle: Option<PathBuf>,
281    /// Filter by domain (messaging/events/secrets/oauth)
282    #[arg(long = "domain", short = 'd', default_value = "messaging")]
283    pub domain: String,
284    /// Show flows for a specific pack
285    #[arg(long = "pack", short = 'p')]
286    pub pack: Option<String>,
287    /// Output format (text/json)
288    #[arg(long = "format", default_value = "text")]
289    pub format: String,
290}
291
292#[derive(Args, Debug, Clone)]
293pub struct BundleStatusArgs {
294    /// Bundle directory (default: current directory)
295    #[arg(long = "bundle", short = 'b')]
296    pub bundle: Option<PathBuf>,
297    /// Output format (text/json)
298    #[arg(long = "format", default_value = "text")]
299    pub format: String,
300}