Skip to main content

dotenv_space/
cli.rs

1use clap::{Parser, Subcommand};
2
3#[derive(Parser)]
4#[command(
5    name = "evnx",
6    about = "Manage .env files — validation, secret scanning, and format conversion",
7    version,
8    author
9)]
10pub struct Cli {
11    #[command(subcommand)]
12    pub command: Commands,
13
14    #[arg(short, long, global = true)]
15    pub verbose: bool,
16
17    #[arg(short, long, global = true)]
18    pub quiet: bool,
19
20    #[arg(long, global = true)]
21    pub no_color: bool,
22}
23
24#[derive(Subcommand)]
25pub enum Commands {
26    /// Interactive project setup — generates .env.example
27    Init {
28        /// Project stack (python, nodejs, rust, go, php)
29        #[arg(long)]
30        stack: Option<String>,
31
32        /// Services to include (comma-separated)
33        #[arg(long)]
34        services: Option<String>,
35
36        /// Output path for .env.example
37        #[arg(long, default_value = ".")]
38        path: String,
39
40        /// Skip all prompts and use defaults
41        #[arg(short, long)]
42        yes: bool,
43    },
44
45    /// Check .env against .env.example, find issues
46    Validate {
47        /// Path to .env file
48        #[arg(long, default_value = ".env")]
49        env: String,
50
51        /// Path to .env.example file
52        #[arg(long, default_value = ".env.example")]
53        example: String,
54
55        /// Fail on warnings, not just errors
56        #[arg(long)]
57        strict: bool,
58
59        /// Auto-fix safe issues
60        #[arg(long)]
61        fix: bool,
62
63        /// Output format (pretty, json, github-actions)
64        #[arg(long, default_value = "pretty")]
65        format: String,
66
67        /// Always exit with 0 (useful in CI)
68        #[arg(long)]
69        exit_zero: bool,
70    },
71
72    /// Detect secrets that look real (AWS keys, tokens, etc.)
73    Scan {
74        /// Files/directories to scan
75        #[arg(default_value = ".")]
76        path: Vec<String>,
77
78        /// Exclude files matching pattern
79        #[arg(long, default_value = ".env.example")]
80        exclude: Vec<String>,
81
82        /// Only scan for specific patterns (aws, stripe, github, all)
83        #[arg(long)]
84        pattern: Vec<String>,
85
86        /// Skip obvious placeholders
87        #[arg(long)]
88        ignore_placeholders: bool,
89
90        /// Output format (pretty, json, sarif)
91        #[arg(long, default_value = "pretty")]
92        format: String,
93
94        /// Don't fail CI even if secrets found
95        #[arg(long)]
96        exit_zero: bool,
97    },
98
99    /// Compare .env vs .env.example — show missing/extra vars
100    Diff {
101        /// Path to .env file
102        #[arg(long, default_value = ".env")]
103        env: String,
104
105        /// Path to .env.example file
106        #[arg(long, default_value = ".env.example")]
107        example: String,
108
109        /// Show actual values (default: hide for security)
110        #[arg(long)]
111        show_values: bool,
112
113        /// Output format (pretty, json, patch)
114        #[arg(long, default_value = "pretty")]
115        format: String,
116
117        /// Reverse comparison (.env.example vs .env)
118        #[arg(long)]
119        reverse: bool,
120    },
121
122    /// Transform to different formats (JSON, YAML, shell, etc.)
123    Convert {
124        /// Input .env file
125        #[arg(long, default_value = ".env")]
126        env: String,
127
128        /// Target format (required in non-interactive mode)
129        #[arg(long)]
130        to: Option<String>,
131
132        /// Output file (default: stdout)
133        #[arg(long)]
134        output: Option<String>,
135
136        /// Include only matching vars (glob pattern)
137        #[arg(long)]
138        include: Option<String>,
139
140        /// Exclude matching vars
141        #[arg(long)]
142        exclude: Option<String>,
143
144        /// Base64-encode all values
145        #[arg(long)]
146        base64: bool,
147
148        /// Add prefix to all keys
149        #[arg(long)]
150        prefix: Option<String>,
151
152        /// Key transform (uppercase, lowercase, camelCase, snake_case)
153        #[arg(long)]
154        transform: Option<String>,
155    },
156
157    /// Full migration workflow to secret managers
158    #[cfg(feature = "migrate")]
159    Migrate {
160        /// Source type (env-file, aws, gcp, github, doppler)
161        #[arg(long)]
162        from: Option<String>,
163
164        /// Destination type
165        #[arg(long)]
166        to: Option<String>,
167
168        /// Source .env file
169        #[arg(long, default_value = ".env")]
170        source_file: String,
171
172        /// GitHub repository (OWNER/REPO)
173        #[arg(long)]
174        repo: Option<String>,
175
176        /// Secret name for AWS/GCP single-secret storage
177        #[arg(long)]
178        secret_name: Option<String>,
179
180        /// Show what would happen without making changes
181        #[arg(long)]
182        dry_run: bool,
183
184        /// Skip variables that already exist
185        #[arg(long)]
186        skip_existing: bool,
187
188        /// Overwrite existing secrets
189        #[arg(long)]
190        overwrite: bool,
191
192        /// GitHub Personal Access Token
193        #[arg(long, env = "GITHUB_TOKEN")]
194        github_token: Option<String>,
195
196        /// AWS profile to use
197        #[arg(long)]
198        aws_profile: Option<String>,
199    },
200
201    /// Keep .env and .env.example in sync
202    Sync {
203        /// Direction (forward: .env → .env.example, reverse: .env.example → .env)
204        #[arg(long, default_value = "forward")]
205        direction: String,
206
207        /// Add with placeholder values
208        #[arg(long)]
209        placeholder: bool,
210    },
211
212    /// Generate config files from templates   
213    Template {
214        /// Input template file
215        #[arg(long)]
216        input: String,
217
218        /// Output file
219        #[arg(long)]
220        output: String,
221
222        /// .env file to use for values
223        #[arg(long, default_value = ".env")]
224        env: String,
225    },
226
227    /// Create encrypted backup of .env
228    #[cfg(feature = "backup")]
229    Backup {
230        /// .env file to backup
231        #[arg(default_value = ".env")]
232        env: String,
233
234        /// Output file
235        #[arg(long)]
236        output: Option<String>,
237    },
238
239    /// Restore from encrypted backup
240    #[cfg(feature = "backup")]
241    Restore {
242        /// Backup file
243        backup: String,
244
245        /// Output file
246        #[arg(long, default_value = ".env")]
247        output: String,
248    },
249
250    /// Diagnose common setup issues   
251    Doctor {
252        /// Project directory to diagnose
253        #[arg(default_value = ".")]
254        path: String,
255    },
256
257    /// Generate shell completions
258    Completions {
259        /// Shell type (bash, zsh, fish, powershell)
260        shell: String,
261    },
262}