ferrous_forge/commands/mod.rs
1//! Command implementations for Ferrous Forge
2
3use clap::Subcommand;
4
5/// Available commands for Ferrous Forge
6#[derive(Subcommand)]
7pub enum Commands {
8 /// Initialize Ferrous Forge system-wide, or set up a project with --project
9 Init {
10 /// Force initialization even if already configured
11 #[arg(short, long)]
12 force: bool,
13 /// Set up project-level tooling (rustfmt.toml, clippy.toml, Cargo.toml lints,
14 /// .vscode/settings.json, CI workflow, and git hooks) in the current directory.
15 /// Requires an existing Rust project with Cargo.toml.
16 #[arg(short, long)]
17 project: bool,
18 },
19 /// Show status of Ferrous Forge installation and configuration
20 Status,
21 /// Update Ferrous Forge to the latest version
22 Update {
23 /// Update channel to use (stable, beta, nightly)
24 #[arg(long, default_value = "stable")]
25 channel: String,
26 /// Only update rules, not the binary
27 #[arg(short, long)]
28 rules_only: bool,
29 /// Show what would be updated without actually updating
30 #[arg(short, long)]
31 dry_run: bool,
32 },
33 /// Manage configuration settings
34 Config {
35 /// Config subcommand
36 #[command(subcommand)]
37 command: Option<ConfigCommand>,
38 },
39 /// Validate a Rust project against standards
40 Validate {
41 /// Path to the project to validate (defaults to current directory)
42 path: Option<std::path::PathBuf>,
43 /// Generate AI-friendly compliance report
44 #[arg(long)]
45 ai_report: bool,
46 /// Compare with previous report
47 #[arg(long)]
48 compare_previous: bool,
49 /// Only check locked settings (edition, rust-version) — exits 1 if any locked violation
50 #[arg(long)]
51 locked_only: bool,
52 },
53 /// Rollback to a previous version
54 Rollback {
55 /// Version to rollback to
56 version: String,
57 },
58 /// Uninstall Ferrous Forge from the system
59 Uninstall {
60 /// Confirm uninstallation without prompting
61 #[arg(short, long)]
62 confirm: bool,
63 },
64 /// Rust version management
65 Rust {
66 /// Rust version management subcommand
67 #[command(subcommand)]
68 command: RustCommand,
69 },
70 /// Edition management
71 Edition {
72 /// Edition management subcommand
73 #[command(subcommand)]
74 command: EditionCommand,
75 },
76 /// Safety pipeline management
77 Safety {
78 /// Safety pipeline subcommand
79 #[command(subcommand)]
80 command: SafetyCommand,
81 },
82 /// Project template management
83 Template {
84 /// Template subcommand
85 #[command(subcommand)]
86 command: template::TemplateCommand,
87 },
88 /// Automatically fix code violations
89 Fix {
90 /// Path to the project to fix (defaults to current directory)
91 path: Option<std::path::PathBuf>,
92 /// Only fix specific violation types (comma-separated)
93 #[arg(long)]
94 only: Option<String>,
95 /// Skip specific violation types (comma-separated)
96 #[arg(long)]
97 skip: Option<String>,
98 /// Show what would be fixed without making changes
99 #[arg(long)]
100 dry_run: bool,
101 /// Fix at most this many violations (for testing)
102 #[arg(long)]
103 limit: Option<usize>,
104 /// Enable AI-powered analysis for complex violations
105 #[arg(long)]
106 ai_analysis: bool,
107 },
108}
109
110/// Rust version management subcommands
111#[derive(Subcommand)]
112pub enum RustCommand {
113 /// Check current Rust version and available updates
114 Check {
115 /// Show verbose output
116 #[arg(short, long)]
117 verbose: bool,
118 /// Exit with error if version doesn't meet locked requirements
119 #[arg(long)]
120 enforce: bool,
121 },
122 /// Get update recommendations
123 Recommend {
124 /// Only consider stable releases
125 #[arg(short, long)]
126 stable_only: bool,
127 },
128 /// List recent Rust releases or installed toolchains
129 List {
130 /// Number of releases to show
131 #[arg(short, long, default_value = "10")]
132 count: usize,
133 /// List installed toolchains instead of releases
134 #[arg(long)]
135 toolchains: bool,
136 },
137 /// List recent Rust releases (alias for 'list')
138 Releases {
139 /// Number of releases to show
140 #[arg(short, long, default_value = "10")]
141 count: usize,
142 },
143 /// Check if Rust updates are available
144 CheckUpdates {
145 /// Show detailed information about available updates
146 #[arg(short, long)]
147 verbose: bool,
148 },
149 /// Show release notes for a specific version
150 ReleaseNotes {
151 /// Version to show notes for (e.g., "1.70.0" or "v1.70.0")
152 version: String,
153 /// Show full parsed details including security/breaking changes
154 #[arg(short, long)]
155 detailed: bool,
156 },
157 /// Check for security advisories affecting current Rust version
158 Security {
159 /// Exit with error if security issues found
160 #[arg(long)]
161 fail_on_issues: bool,
162 },
163 /// Update Rust via rustup
164 Update {
165 /// Show what would be updated without making changes
166 #[arg(long)]
167 dry_run: bool,
168 /// Skip confirmation prompt
169 #[arg(short, long)]
170 yes: bool,
171 /// Also update rustup itself
172 #[arg(long)]
173 self_update: bool,
174 },
175 /// Install a specific toolchain
176 InstallToolchain {
177 /// Toolchain channel to install (stable, beta, nightly, or version like 1.70.0)
178 channel: String,
179 /// Set as default toolchain after installation
180 #[arg(short, long)]
181 default: bool,
182 },
183 /// Uninstall a toolchain
184 UninstallToolchain {
185 /// Toolchain channel to uninstall
186 channel: String,
187 },
188 /// Switch to a different toolchain
189 Switch {
190 /// Toolchain channel to switch to
191 channel: String,
192 },
193}
194
195/// Edition management subcommands
196#[derive(Subcommand)]
197pub enum EditionCommand {
198 /// Check edition compliance
199 Check {
200 /// Project path
201 #[arg(default_value = ".")]
202 path: std::path::PathBuf,
203 },
204 /// Migrate to a new edition
205 Migrate {
206 /// Target edition (2018, 2021, 2024)
207 #[arg(default_value = "2024")]
208 edition: String,
209 /// Skip backup creation
210 #[arg(long)]
211 no_backup: bool,
212 /// Run tests after migration
213 #[arg(long)]
214 test: bool,
215 /// Apply edition idioms
216 #[arg(long)]
217 idioms: bool,
218 },
219 /// Analyze edition compatibility
220 Analyze {
221 /// Project path
222 #[arg(default_value = ".")]
223 path: std::path::PathBuf,
224 /// Target edition
225 #[arg(default_value = "2024")]
226 edition: String,
227 },
228}
229
230/// Safety pipeline management subcommands
231#[derive(Subcommand)]
232pub enum SafetyCommand {
233 /// Check safety pipeline status
234 Status,
235 /// Install git hooks for safety pipeline
236 Install {
237 /// Force reinstall even if hooks already exist
238 #[arg(short, long)]
239 force: bool,
240 /// Project path
241 #[arg(default_value = ".")]
242 path: std::path::PathBuf,
243 /// Install cargo publish interception
244 #[arg(long)]
245 cargo: bool,
246 },
247 /// Run safety checks manually
248 Check {
249 /// Pipeline stage to check
250 #[arg(long, default_value = "pre-commit")]
251 stage: String,
252 /// Project path
253 #[arg(default_value = ".")]
254 path: std::path::PathBuf,
255 /// Show verbose output
256 #[arg(short, long)]
257 verbose: bool,
258 },
259 /// Test individual safety checks
260 Test {
261 /// Project path
262 #[arg(default_value = ".")]
263 path: std::path::PathBuf,
264 },
265 /// Create emergency bypass for safety checks
266 ///
267 /// Use this to temporarily skip safety checks with audit logging.
268 /// Requires explicit justification. Bypasses expire after 24 hours.
269 Bypass {
270 /// Pipeline stage to bypass (pre-commit, pre-push, publish)
271 #[arg(long, value_enum)]
272 stage: SafetyBypassStage,
273 /// Reason for bypass (required)
274 #[arg(long)]
275 reason: String,
276 /// Bypass duration in hours (default: 24)
277 #[arg(long, default_value = "24")]
278 duration: u64,
279 /// User creating the bypass (defaults to current user)
280 #[arg(long)]
281 user: Option<String>,
282 },
283 /// View bypass audit log
284 Audit {
285 /// Number of entries to show
286 #[arg(short, long, default_value = "20")]
287 limit: usize,
288 },
289 /// Check if a bypass is active (used by git hooks)
290 CheckBypass {
291 /// Pipeline stage to check
292 #[arg(long, value_enum)]
293 stage: SafetyBypassStage,
294 },
295 /// Uninstall git hooks
296 Uninstall {
297 /// Project path
298 #[arg(default_value = ".")]
299 path: std::path::PathBuf,
300 /// Confirm uninstall without prompting
301 #[arg(short, long)]
302 confirm: bool,
303 },
304 /// Manage safety configuration
305 Config {
306 /// Show current configuration
307 #[arg(long, group = "config_action")]
308 show: bool,
309 /// Set a configuration value (key=value)
310 #[arg(long, group = "config_action")]
311 set: Option<String>,
312 /// Get a specific configuration value
313 #[arg(long, group = "config_action")]
314 get: Option<String>,
315 },
316 /// View safety reports
317 Report {
318 /// Number of reports to show
319 #[arg(short, long, default_value = "10")]
320 last: usize,
321 /// Include bypass audit log
322 #[arg(long)]
323 audit: bool,
324 /// Filter by stage (pre-commit, pre-push, publish)
325 #[arg(long)]
326 stage: Option<String>,
327 },
328 /// Display safety statistics and metrics
329 Stats {
330 /// Number of days to include in statistics
331 #[arg(short, long, default_value = "30")]
332 days: u32,
333 },
334}
335
336/// Safety bypass stage options
337#[derive(clap::ValueEnum, Clone, Debug)]
338pub enum SafetyBypassStage {
339 /// Pre-commit checks
340 PreCommit,
341 /// Pre-push checks
342 PrePush,
343 /// Publish checks
344 Publish,
345}
346
347impl SafetyBypassStage {
348 /// Convert to `PipelineStage`
349 pub fn to_pipeline_stage(&self) -> crate::safety::PipelineStage {
350 match self {
351 Self::PreCommit => crate::safety::PipelineStage::PreCommit,
352 Self::PrePush => crate::safety::PipelineStage::PrePush,
353 Self::Publish => crate::safety::PipelineStage::Publish,
354 }
355 }
356}
357
358/// Configuration subcommands
359#[derive(Subcommand)]
360pub enum ConfigCommand {
361 /// Get a configuration value
362 Get {
363 /// The configuration key to retrieve
364 key: String,
365 },
366 /// Set a configuration value (key=value)
367 Set {
368 /// The key=value pair to set
369 value: String,
370 },
371 /// List all configuration values
372 List,
373 /// Reset configuration to defaults
374 Reset,
375 /// Show configuration sources from hierarchy
376 Sources,
377 /// Migrate old configuration to hierarchical system
378 Migrate,
379 /// Lock a configuration value to prevent changes
380 Lock {
381 /// The configuration key to lock
382 key: String,
383 /// The value to lock (defaults to current value)
384 #[arg(long)]
385 value: Option<String>,
386 /// Reason for locking (required)
387 #[arg(long)]
388 reason: String,
389 /// Configuration level to lock at (project, user, system)
390 #[arg(long, default_value = "project")]
391 level: ConfigLevelArg,
392 },
393 /// Unlock a configuration value to allow changes
394 Unlock {
395 /// The configuration key to unlock
396 key: String,
397 /// Reason for unlocking (required)
398 #[arg(long)]
399 reason: String,
400 /// Configuration level to unlock at
401 #[arg(long, default_value = "project")]
402 level: ConfigLevelArg,
403 },
404 /// Show lock status for all configuration values
405 LockStatus,
406 /// View lock audit log
407 LockAudit {
408 /// Number of entries to show
409 #[arg(short, long, default_value = "20")]
410 limit: usize,
411 },
412 /// Export configuration for sharing
413 Export {
414 /// Configuration level to export (project, user, system)
415 #[arg(long, default_value = "user")]
416 level: ConfigLevelArg,
417 /// Output file path (defaults to stdout)
418 #[arg(short, long)]
419 output: Option<std::path::PathBuf>,
420 /// Description of this shared config
421 #[arg(long)]
422 description: Option<String>,
423 },
424 /// Import configuration from shared file
425 Import {
426 /// Path to the shared config file
427 file: std::path::PathBuf,
428 /// Target level to import to (project, user, system)
429 #[arg(long, default_value = "project")]
430 level: ConfigLevelArg,
431 /// Skip importing locks
432 #[arg(long)]
433 no_locks: bool,
434 /// Force overwrite of existing values
435 #[arg(long)]
436 force: bool,
437 },
438}
439
440/// Configuration level argument for CLI
441#[derive(clap::ValueEnum, Clone, Debug)]
442pub enum ConfigLevelArg {
443 /// System-wide configuration
444 System,
445 /// User-specific configuration
446 User,
447 /// Project-specific configuration
448 Project,
449}
450
451impl ConfigLevelArg {
452 /// Convert to `ConfigLevel`
453 pub fn to_config_level(&self) -> crate::config::ConfigLevel {
454 match self {
455 Self::System => crate::config::ConfigLevel::System,
456 Self::User => crate::config::ConfigLevel::User,
457 Self::Project => crate::config::ConfigLevel::Project,
458 }
459 }
460}
461
462/// Configuration management command handlers.
463pub mod config;
464/// Edition management command handlers.
465pub mod edition;
466/// Automatic code violation fix command handlers.
467pub mod fix;
468/// Project and system initialization command handlers.
469pub mod init;
470/// Version rollback command handlers.
471pub mod rollback;
472/// Rust version management command handlers.
473pub mod rust;
474/// Safety pipeline command handlers.
475pub mod safety;
476/// Installation status display command handlers.
477pub mod status;
478/// Project template command handlers.
479pub mod template;
480/// Uninstall command handlers.
481pub mod uninstall;
482/// Self-update command handlers.
483pub mod update;
484/// Project validation command handlers.
485pub mod validate;