|
| 1 | +--- |
| 2 | +description: CLI implementation standards for zerv including core commands, pipeline architecture, argument structures, and format validation patterns |
| 3 | +globs: **/*.rs,**/src/cli/**/*.rs,**/tests/**/*.rs |
| 4 | +alwaysApply: true |
| 5 | +--- |
| 6 | + |
| 7 | +# CLI Implementation Standards |
| 8 | + |
| 9 | +## Core Commands |
| 10 | + |
| 11 | +### `zerv version [OPTIONS]` |
| 12 | + |
| 13 | +Main version processing pipeline with composable operations. |
| 14 | + |
| 15 | +### `zerv check <version> [OPTIONS]` |
| 16 | + |
| 17 | +Validation-only command for version strings. |
| 18 | + |
| 19 | +## Pipeline Architecture |
| 20 | + |
| 21 | +``` |
| 22 | +Input → Version Object → Zerv Object → Transform → Output Version Object → Display |
| 23 | +``` |
| 24 | + |
| 25 | +## Key Implementation Patterns |
| 26 | + |
| 27 | +### Version Command Args Structure |
| 28 | + |
| 29 | +```rust |
| 30 | +#[derive(Parser)] |
| 31 | +struct VersionArgs { |
| 32 | + version: Option<String>, |
| 33 | + #[arg(long, default_value = "git")] |
| 34 | + source: String, |
| 35 | + #[arg(long, default_value = "zerv-default")] |
| 36 | + schema: String, |
| 37 | + #[arg(long)] |
| 38 | + schema_ron: Option<String>, |
| 39 | + #[arg(long)] |
| 40 | + output_format: Option<String>, |
| 41 | +} |
| 42 | +``` |
| 43 | + |
| 44 | +### Check Command Args Structure |
| 45 | + |
| 46 | +```rust |
| 47 | +#[derive(Parser)] |
| 48 | +struct CheckArgs { |
| 49 | + version: String, |
| 50 | + #[arg(long)] |
| 51 | + format: Option<String>, // pep440, semver, auto-detect (default) |
| 52 | +} |
| 53 | +``` |
| 54 | + |
| 55 | +### Core Pipeline Function |
| 56 | + |
| 57 | +```rust |
| 58 | +pub fn run_version_pipeline(args: VersionArgs) -> Result<String> { |
| 59 | + // 1. Get VCS data |
| 60 | + let vcs_data = detect_vcs(current_dir())?.get_vcs_data()?; |
| 61 | + |
| 62 | + // 2. Convert to ZervVars |
| 63 | + let vars = vcs_data_to_zerv_vars(vcs_data)?; |
| 64 | + |
| 65 | + // 3. Apply schema and output format |
| 66 | + match args.output_format.as_deref() { |
| 67 | + Some("pep440") => Ok(PEP440::from_zerv(&vars)?.to_string()), |
| 68 | + Some("semver") => Ok(SemVer::from_zerv(&vars)?.to_string()), |
| 69 | + _ => Ok(vars.to_string()), |
| 70 | + } |
| 71 | +} |
| 72 | +``` |
| 73 | + |
| 74 | +## State-Based Versioning Tiers |
| 75 | + |
| 76 | +**Tier 1** (Tagged, clean): `major.minor.patch` |
| 77 | +**Tier 2** (Distance, clean): `major.minor.patch.post<distance>+branch.<commit>` |
| 78 | +**Tier 3** (Dirty): `major.minor.patch.dev<timestamp>+branch.<commit>` |
| 79 | + |
| 80 | +## Format Flag Validation Pattern |
| 81 | + |
| 82 | +```rust |
| 83 | +// Error if conflicting format flags used |
| 84 | +if args.format.is_some() && (args.input_format.is_some() || args.output_format.is_some()) { |
| 85 | + return Err(ZervError::ConflictingFlags( |
| 86 | + "Cannot use --format with --input-format or --output-format".to_string() |
| 87 | + )); |
| 88 | +} |
| 89 | +``` |
| 90 | + |
| 91 | +## Check Command Auto-Detection Pattern |
| 92 | + |
| 93 | +```rust |
| 94 | +fn run_check_command(args: CheckArgs) -> Result<()> { |
| 95 | + match args.format.as_deref() { |
| 96 | + Some("pep440") => { |
| 97 | + PEP440::parse(&args.version)?; |
| 98 | + println!("✓ Valid PEP440 version"); |
| 99 | + } |
| 100 | + Some("semver") => { |
| 101 | + SemVer::parse(&args.version)?; |
| 102 | + println!("✓ Valid SemVer version"); |
| 103 | + } |
| 104 | + None => { |
| 105 | + // Auto-detect format |
| 106 | + let pep440_valid = PEP440::parse(&args.version).is_ok(); |
| 107 | + let semver_valid = SemVer::parse(&args.version).is_ok(); |
| 108 | + |
| 109 | + match (pep440_valid, semver_valid) { |
| 110 | + (true, false) => println!("✓ Valid PEP440 version"), |
| 111 | + (false, true) => println!("✓ Valid SemVer version"), |
| 112 | + (true, true) => { |
| 113 | + println!("✓ Valid PEP440 version"); |
| 114 | + println!("✓ Valid SemVer version"); |
| 115 | + } |
| 116 | + (false, false) => return Err(ZervError::InvalidVersion(args.version)), |
| 117 | + } |
| 118 | + } |
| 119 | + Some(format) => return Err(ZervError::UnknownFormat(format.to_string())), |
| 120 | + } |
| 121 | + Ok(()) |
| 122 | +} |
| 123 | +``` |
| 124 | + |
| 125 | +## Essential CLI Options |
| 126 | + |
| 127 | +### Input Sources |
| 128 | + |
| 129 | +- `--source git` (default) - Auto-detect Git |
| 130 | +- `--source string <version>` - Parse version string |
| 131 | + |
| 132 | +### Schema Control |
| 133 | + |
| 134 | +- `--schema zerv-default` (default) - Tier-aware schema |
| 135 | +- `--schema-ron <ron>` - Custom RON schema |
| 136 | + |
| 137 | +### Output Control |
| 138 | + |
| 139 | +- `--output-format <format>` - Target format: pep440, semver |
| 140 | +- `--output-template <template>` - Custom template string |
| 141 | +- `--output-prefix [prefix]` - Add prefix (defaults to "v") |
0 commit comments