use clap::{Args, Parser, Subcommand, ValueEnum};
#[derive(Parser)]
#[command(name = "odometer")]
#[command(about = "A workspace version management tool")]
#[command(long_about = "Keeps package versions synchronized across projects")]
#[command(version)]
pub(crate) struct Cli {
#[command(subcommand)]
pub(crate) command: Commands,
}
#[derive(Args, Debug, Clone, Default)]
pub struct IgnoreOptions {
#[arg(long)]
pub no_ignore_git: bool,
#[arg(long)]
pub no_ignore: bool,
#[arg(long)]
pub no_ignore_global: bool,
#[arg(long)]
pub hidden: bool,
#[arg(long)]
pub no_ignore_all: bool,
}
#[derive(Clone, Debug, ValueEnum, Default)]
pub(crate) enum OutputFormat {
#[default]
Simple,
Json,
}
#[derive(Subcommand)]
pub(crate) enum Commands {
Roll {
#[command(subcommand)]
bump_type: BumpType,
},
Set {
version: String,
#[command(flatten)]
package_selection: PackageSelection,
#[arg(long, default_value = "simple")]
format: OutputFormat,
#[command(flatten)]
ignore_options: IgnoreOptions,
},
Sync {
version: String,
#[arg(long, default_value = "simple")]
format: OutputFormat,
#[command(flatten)]
ignore_options: IgnoreOptions,
},
Show {
#[command(flatten)]
package_selection: PackageSelection,
#[command(flatten)]
ignore_options: IgnoreOptions,
},
Lint {
#[command(flatten)]
package_selection: PackageSelection,
#[command(flatten)]
ignore_options: IgnoreOptions,
},
}
#[derive(Args, Debug)]
pub(crate) struct PackageSelection {
#[arg(short = 'p', long = "package")]
pub(crate) packages: Vec<String>,
#[arg(short = 'w', long = "workspace", conflicts_with = "packages")]
pub(crate) workspace: bool,
#[arg(long = "all", conflicts_with = "packages")]
pub(crate) all: bool,
}
#[derive(Subcommand, Debug)]
pub(crate) enum BumpType {
Major {
#[arg(default_value = "1", allow_negative_numbers = true)]
amount: i32,
#[command(flatten)]
package_selection: PackageSelection,
#[command(flatten)]
ignore_options: IgnoreOptions,
#[arg(long, default_value = "simple")]
format: OutputFormat,
},
Minor {
#[arg(default_value = "1", allow_negative_numbers = true)]
amount: i32,
#[command(flatten)]
package_selection: PackageSelection,
#[command(flatten)]
ignore_options: IgnoreOptions,
#[arg(long, default_value = "simple")]
format: OutputFormat,
},
Patch {
#[arg(default_value = "1", allow_negative_numbers = true)]
amount: i32,
#[command(flatten)]
package_selection: PackageSelection,
#[command(flatten)]
ignore_options: IgnoreOptions,
#[arg(long, default_value = "simple")]
format: OutputFormat,
},
}
impl From<BumpType>
for (
crate::domain::VersionBump,
crate::domain::PackageSelection,
IgnoreOptions,
OutputFormat,
)
{
fn from(bump_type: BumpType) -> Self {
match bump_type {
BumpType::Major {
amount,
package_selection,
ignore_options,
format,
} => (
crate::domain::VersionBump::Major(amount),
package_selection.into(),
ignore_options,
format,
),
BumpType::Minor {
amount,
package_selection,
ignore_options,
format,
} => (
crate::domain::VersionBump::Minor(amount),
package_selection.into(),
ignore_options,
format,
),
BumpType::Patch {
amount,
package_selection,
ignore_options,
format,
} => (
crate::domain::VersionBump::Patch(amount),
package_selection.into(),
ignore_options,
format,
),
}
}
}
impl From<PackageSelection> for crate::domain::PackageSelection {
fn from(selection: PackageSelection) -> Self {
if !selection.packages.is_empty() {
crate::domain::PackageSelection::Specific(selection.packages)
} else if selection.workspace || selection.all {
crate::domain::PackageSelection::Workspace
} else {
crate::domain::PackageSelection::Default
}
}
}