use std::{path::PathBuf, process::ExitCode};
use clap::Parser;
mod bump;
mod changelog;
mod changeset;
mod commands;
mod config;
mod jsonc;
mod output;
mod package_json;
mod plan;
mod pre;
mod release_plan;
mod skip;
mod snapshot;
mod workspace;
#[derive(Parser)]
#[command(version, args_conflicts_with_subcommands = true)]
struct Cli {
#[command(subcommand)]
command: Option<Command>,
#[command(flatten)]
add: AddArgs,
#[arg(long, value_name = "LEVEL", global = true, default_value = "info")]
log_level: LogLevel,
}
#[derive(Clone, Copy, clap::ValueEnum)]
enum LogLevel {
Error,
Warn,
Info,
Debug,
}
impl LogLevel {
fn filter(self) -> tracing::level_filters::LevelFilter {
use tracing::level_filters::LevelFilter;
match self {
LogLevel::Error => LevelFilter::ERROR,
LogLevel::Warn => LevelFilter::WARN,
LogLevel::Info => LevelFilter::INFO,
LogLevel::Debug => LevelFilter::DEBUG,
}
}
}
#[derive(clap::Args)]
struct AddArgs {
#[arg(long, conflicts_with_all = ["major", "minor", "patch"])]
empty: bool,
#[arg(long)]
open: bool,
#[arg(short, long)]
message: Option<String>,
#[arg(long, value_name = "PACKAGES", value_delimiter = ',')]
major: Vec<String>,
#[arg(long, value_name = "PACKAGES", value_delimiter = ',')]
minor: Vec<String>,
#[arg(long, value_name = "PACKAGES", value_delimiter = ',')]
patch: Vec<String>,
}
#[derive(clap::Subcommand)]
enum Command {
Init,
Add(AddArgs),
Version {
#[arg(long, value_name = "PACKAGES", value_delimiter = ',')]
ignore: Vec<String>,
#[arg(
long,
value_name = "TAG",
num_args = 0..=1,
value_parser = clap::builder::NonEmptyStringValueParser::new()
)]
snapshot: Option<Option<String>>,
#[arg(
long,
value_name = "TEMPLATE",
requires = "snapshot",
value_parser = clap::builder::NonEmptyStringValueParser::new()
)]
snapshot_prerelease_template: Option<String>,
#[arg(short, long)]
allow_no_changesets: bool,
#[arg(short, long, value_name = "FILE")]
output: Option<PathBuf>,
},
Pre {
#[command(subcommand)]
command: PreCommand,
},
Status {
#[arg(short, long)]
verbose: bool,
#[arg(short, long, value_name = "FILE")]
output: Option<PathBuf>,
},
GetPackages {
#[arg(long)]
all: bool,
},
GetChangelogEntry {
package: String,
version: semver::Version,
},
}
#[derive(clap::Subcommand)]
enum PreCommand {
Enter {
tag: String,
},
Exit,
}
fn main() -> ExitCode {
let cli = Cli::parse();
output::init_subscriber(cli.log_level.filter());
match run(cli) {
Ok(()) => ExitCode::SUCCESS,
Err(err) => {
tracing::error!("{err:#}");
ExitCode::FAILURE
}
}
}
fn run(cli: Cli) -> anyhow::Result<()> {
match cli.command.unwrap_or(Command::Add(cli.add)) {
Command::Init => commands::init::run(),
Command::Add(AddArgs {
major,
minor,
patch,
message,
empty,
open,
}) => commands::add::run(major, minor, patch, message, empty, open),
Command::Version {
ignore,
snapshot,
snapshot_prerelease_template,
allow_no_changesets,
output,
} => {
let snapshot = snapshot.map(|tag| snapshot::Snapshot {
tag,
template: snapshot_prerelease_template,
});
commands::version::run(
&ignore,
allow_no_changesets,
output.as_deref(),
snapshot.as_ref(),
)
}
Command::Pre { command } => match command {
PreCommand::Enter { tag } => commands::pre::enter(&tag),
PreCommand::Exit => commands::pre::exit(),
},
Command::Status { verbose, output } => commands::status::run(verbose, output.as_deref()),
Command::GetPackages { all } => commands::get_packages::run(all),
Command::GetChangelogEntry { package, version } => {
commands::get_changelog_entry::run(&package, &version)
}
}
}