1use crate::config::{
6 DeploymentMode, GitVersionConfiguration, IncrementStrategy, SemanticVersionFormat,
7};
8use clap::{CommandFactory, Parser, ValueEnum};
9use rust_i18n::t;
10use std::path::PathBuf;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
14pub enum OutputFormat {
15 Json,
16 File,
18 DotEnv,
19 BuildServer,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
24pub enum Verbosity {
25 Quiet,
26 Minimal,
27 Normal,
28 Verbose,
29 Diagnostic,
30}
31
32impl Verbosity {
33 pub fn to_level(self) -> log::LevelFilter {
35 match self {
36 Verbosity::Quiet => log::LevelFilter::Error,
37 Verbosity::Minimal => log::LevelFilter::Warn,
38 Verbosity::Normal => log::LevelFilter::Info,
39 Verbosity::Verbose => log::LevelFilter::Debug,
40 Verbosity::Diagnostic => log::LevelFilter::Trace,
41 }
42 }
43}
44
45#[derive(Debug, Parser)]
49#[command(
50 name = "gitversion-rs",
51 version,
52 about = "Calculate a semantic version from Git history (GitVersion Rust port)"
53)]
54pub struct Cli {
55 #[arg(default_value = ".")]
57 pub path: PathBuf,
58
59 #[arg(long = "targetpath", value_name = "DIR")]
61 pub target_path: Option<PathBuf>,
62
63 #[arg(long)]
67 pub nofetch: bool,
68 #[arg(long)]
70 pub nonormalize: bool,
71 #[arg(long)]
73 pub nocache: bool,
74 #[arg(long)]
76 pub allowshallow: bool,
77
78 #[arg(long, value_enum, default_value = "json")]
80 pub output: Vec<OutputFormat>,
81
82 #[arg(long = "outputfile")]
84 pub output_file: Option<PathBuf>,
85
86 #[arg(long = "showvariable", short = 'v')]
88 pub show_variable: Option<String>,
89
90 #[arg(long)]
92 pub format: Option<String>,
93
94 #[arg(long)]
96 pub config: Option<PathBuf>,
97
98 #[arg(long = "showconfig")]
100 pub show_config: bool,
101
102 #[arg(long = "overrideconfig")]
104 pub override_config: Vec<String>,
105
106 #[arg(long, short = 'b')]
108 pub branch: Option<String>,
109
110 #[arg(long, value_name = "LANG")]
112 pub lang: Option<String>,
113
114 #[arg(long, value_enum, default_value = "normal")]
116 pub verbosity: Verbosity,
117
118 #[arg(long = "log", short = 'l', value_name = "FILE")]
121 pub log_file: Option<PathBuf>,
122
123 #[arg(long)]
125 pub diag: bool,
126
127 #[arg(long = "updateassemblyinfo", num_args = 0.., value_name = "FILE")]
129 pub update_assembly_info: Option<Vec<String>>,
130
131 #[arg(long = "ensureassemblyinfo")]
133 pub ensure_assembly_info: bool,
134
135 #[arg(long = "updateprojectfiles", num_args = 0.., value_name = "FILE")]
137 pub update_project_files: Option<Vec<String>>,
138
139 #[arg(long = "updatewixversionfile")]
141 pub update_wix_version_file: bool,
142
143 #[arg(long = "updatepackagefiles", num_args = 0.., value_name = "FILE")]
146 pub update_package_files: Option<Vec<String>>,
147
148 #[arg(long)]
150 pub url: Option<String>,
151
152 #[arg(long = "username", short = 'u')]
154 pub username: Option<String>,
155
156 #[arg(long = "password", short = 'p')]
158 pub password: Option<String>,
159
160 #[arg(long = "commit", short = 'c')]
162 pub commit: Option<String>,
163
164 #[arg(long = "dynamicRepoLocation")]
166 pub dynamic_repo_location: Option<PathBuf>,
167
168 #[arg(long)]
170 pub exec: Option<String>,
171
172 #[arg(long = "exec-version")]
174 pub exec_version: Option<String>,
175
176 #[arg(long = "dry-run")]
178 pub dry_run: bool,
179
180 #[arg(long)]
182 pub tui: bool,
183}
184
185pub fn localized_command() -> clap::Command {
190 Cli::command()
191 .about(t!("cli.about").to_string())
192 .mut_args(|arg| {
193 let key = format!("cli.help.{}", arg.get_id());
194 let val = t!(key.as_str()).to_string();
195 if val == key {
196 arg
197 } else {
198 arg.help(val)
199 }
200 })
201}
202
203pub fn apply_overrides(config: &mut GitVersionConfiguration, overrides: &[String]) {
205 for raw in overrides {
206 let Some((key, value)) = raw.split_once('=') else {
207 log::warn!("{}", t!("cli.override_invalid", entry = raw));
208 continue;
209 };
210 let key = key.trim();
211 let value = value.trim().to_string();
212 match key {
213 "tag-prefix" => config.tag_prefix = Some(value),
214 "next-version" => config.next_version = Some(value),
215 "label" => config.label = Some(value),
216 "commit-date-format" => config.commit_date_format = Some(value),
217 "major-version-bump-message" => config.major_version_bump_message = Some(value),
218 "minor-version-bump-message" => config.minor_version_bump_message = Some(value),
219 "patch-version-bump-message" => config.patch_version_bump_message = Some(value),
220 "no-bump-message" => config.no_bump_message = Some(value),
221 "tag-pre-release-weight" => {
222 if let Ok(n) = value.parse() {
223 config.tag_pre_release_weight = Some(n);
224 }
225 }
226 "update-build-number" => config.update_build_number = value.parse().ok(),
227 "increment" => config.increment = parse_increment(&value),
228 "mode" => config.mode = parse_mode(&value),
229 "semantic-version-format" => {
230 config.semantic_version_format = match value.to_lowercase().as_str() {
231 "loose" => Some(SemanticVersionFormat::Loose),
232 _ => Some(SemanticVersionFormat::Strict),
233 }
234 }
235 other => log::warn!("{}", t!("cli.override_unsupported", key = other)),
236 }
237 }
238}
239
240fn parse_increment(v: &str) -> Option<IncrementStrategy> {
241 Some(match v.to_lowercase().as_str() {
242 "major" => IncrementStrategy::Major,
243 "minor" => IncrementStrategy::Minor,
244 "patch" => IncrementStrategy::Patch,
245 "none" => IncrementStrategy::None,
246 "inherit" => IncrementStrategy::Inherit,
247 _ => return None,
248 })
249}
250
251fn parse_mode(v: &str) -> Option<DeploymentMode> {
252 Some(match v.to_lowercase().as_str() {
253 "continuousdelivery" => DeploymentMode::ContinuousDelivery,
254 "continuousdeployment" => DeploymentMode::ContinuousDeployment,
255 "manualdeployment" => DeploymentMode::ManualDeployment,
256 _ => return None,
257 })
258}