use clap::Parser;
use eyre::Result;
use inquire::Confirm;
use thiserror::Error;
use crate::{
config::{
VERSION,
updater::{AskForTicket, ConfigUpdater, Init},
},
error, hint, success,
tracing::LogResult as _,
};
use super::helpers::ensure_in_git_worktree;
#[derive(Debug, Parser)]
pub struct Update;
#[derive(Debug, Error)]
pub enum UpdateError {
#[error("Unsupported configuration version {version}")]
UnsupportedVersion {
version: String,
},
#[error("Unsupported development configuration version {version}")]
UnsupportedDevelopmentVersion {
version: String,
gitz_version: String,
},
}
impl super::Command for Update {
#[tracing::instrument(name = "update", level = "trace", skip_all)]
fn run(&self) -> Result<()> {
tracing::info!(params = ?self, "running update");
ensure_in_git_worktree()?;
let updater = ConfigUpdater::load()?;
match updater.config_version() {
VERSION => success!("The configuration is already up to date."),
"0.1" => update_from_v0_1(updater)?,
version @ ("0.2-dev.0" | "0.2-dev.1" | "0.2-dev.2"
| "0.2-dev.3") => Err(UpdateError::UnsupportedDevelopmentVersion {
version: version.to_owned(),
gitz_version: String::from("0.2.0"),
})
.log_err()?,
version => Err(UpdateError::UnsupportedVersion {
version: version.to_owned(),
})
.log_err()?,
}
Ok(())
}
}
#[tracing::instrument(level = "trace", skip_all)]
fn update_from_v0_1(updater: ConfigUpdater<Init>) -> Result<()> {
tracing::info!("updating from version 0.1");
let switch_scopes_to_any = ask_scopes_any(&updater)?;
let ask_for_ticket = ask_ticket_management()?;
let empty_prefix_to_hash = match ask_for_ticket {
AskForTicket::Ask { .. } => ask_empty_prefix_to_hash(&updater)?,
AskForTicket::DontAsk => false,
};
updater
.update_from_v0_1(
switch_scopes_to_any,
ask_for_ticket,
empty_prefix_to_hash,
)?
.save()?;
success!("The configuration has been updated.");
Ok(())
}
fn ask_scopes_any(updater: &ConfigUpdater<Init>) -> Result<bool> {
if updater.parsed_config().scopes.is_none() {
return Ok(false);
}
hint! {"
It is now possible to accept any arbitrary scope instead of a pre-defined list.
"};
let switch_scopes_to_any = Confirm::new(
"Do you want to accept any scope instead of a pre-defined list?",
)
.with_help_message("Answer no to keep the current behaviour (default)")
.with_default(false)
.prompt()
.log_err()?;
tracing::debug!(?switch_scopes_to_any);
Ok(switch_scopes_to_any)
}
fn ask_ticket_management() -> Result<AskForTicket> {
hint! {"
The ticket / issue number management has been updated. It is now possible to:
- ask for a required ticket number (as before),
- ask for an optional ticket number,
- do not ask for any ticket number.
"};
let ask_for_ticket = Confirm::new(
"Should the committer be proposed to enter a ticket number?",
)
.with_default(true)
.prompt()
.log_err()?;
let ask_for_ticket = if ask_for_ticket {
let require = Confirm::new("Should the ticket number be required?")
.with_default(true)
.prompt()
.log_err()?;
AskForTicket::Ask { require }
} else {
AskForTicket::DontAsk
};
tracing::debug!(?ask_for_ticket);
Ok(ask_for_ticket)
}
fn ask_empty_prefix_to_hash(updater: &ConfigUpdater<Init>) -> Result<bool> {
if updater.parsed_config().ticket.is_none() {
return Ok(false);
}
hint! {r##"
"#" is now properly handled as a ticket prefix. This means that if \"#\" is
part of your prefix list, a ticket number `#23` would be properly extracted
from a branch named `feature/23-name`.
"##};
let empty_prefix_to_hash = Confirm::new("Should any existing empty value in `ticket.prefixes` be replaced by \"#\"?")
.with_help_message("This will also remove any `#` prefix before `{{ ticket }}` in your commit template")
.with_default(true)
.prompt()
.log_err()?;
tracing::debug!(?empty_prefix_to_hash);
Ok(empty_prefix_to_hash)
}