git-gamble 2.12.1

blend TDD + TCR to make sure to develop the right thing 😌, baby step by baby step πŸ‘ΆπŸ¦Ά
Documentation
use std::process::Command;

use crate::message::Message;

use super::cli::Cli;
use super::command_choice::tcr;
use super::command_choice::trc;
use super::gamble_result::GambleError;
use super::gamble_result::GambleResult;
use super::repository::Repository;

pub fn gamble(opt: Cli) -> GambleResult {
	let gamble_strategy = if opt.pass { tcr } else { trc };

	let maybe_test_command = reformat_command(opt.test_command.clone());

	maybe_test_command
		.ok_or_else(|| {
			let invalid_test_command = opt.test_command.join(" ");

			log::error!("Can't parse test command \"{invalid_test_command}\"");

			GambleError {
				messages: vec![Message::Error(format!(
					"Can't parse test command \"{invalid_test_command}\""
				))],
				code: 1,
			}
		})
		.and_then(|test_command| {
			let repository =
				Repository::new(opt.repository_path.as_path(), opt.dry_run, opt.no_verify);

			let hook_gambled = if opt.pass { "pass" } else { "fail" };
			repository
				.run_hook("pre-gamble", &[hook_gambled])
				.map_err(|error| {
					error.add_message(Message::Warn(
						"No tests have been run, and nothing has been committed or reverted"
							.to_string(),
					))
				})
				.and_then(|()| repository.command(&["add", "--all"]))
				.and_then(|()| {
					let status = Command::new(&test_command[0])
						.args(&test_command[1..])
						.status()
						.expect("failed to run tests"); // TODO: test this
					let command_choice = gamble_strategy(status);

					command_choice(&opt, &repository)
				})
		})
}

fn reformat_command(command: Vec<String>) -> Option<Vec<String>> {
	if command.len() == 1 {
		shlex::split(command[0].as_str())
	} else {
		Some(command)
	}
}