git-gamble 2.13.1

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

use super::cli::Cli;
use super::gamble_result::GambleError;
use super::gamble_result::GambleResult;
use super::repository::Repository;

pub(crate) fn commit(opt: &Cli, repository: &Repository) -> GambleResult<()> {
	log::info!("commit");

	let post_hook_gambled = if opt.pass { "pass" } else { "fail" };
	let post_hook_actual = post_hook_gambled;

	repository.is_clean().and_then(|is_clean| {
		if is_clean {
			log::warn!("There is nothing to commit");
			Message::Warn("There is nothing to commit".to_string()).display();

			repository
				.run_hook("post-gamble", &[post_hook_gambled, post_hook_actual])
				.map_err(|error| {
					error.add_message(Message::Warn(
						"The post-gamble hook failed to execute".to_string(),
					))
				})
				.and_then(|()| {
					Err(GambleError {
						messages: vec![],
						code: 1, // post-gamble hook may succeed but this not the happy path
					})
				})
		} else {
			let base_options = vec!["commit", "--allow-empty-message"];

			let head_is_failing_ref = repository.head_is_failing_ref();

			let mut message_options = if let Some(commit) = &opt.fixup {
				vec!["--fixup", commit]
			} else if opt.message.is_empty() && head_is_failing_ref {
				vec!["--reuse-message", "HEAD"]
			} else {
				vec![]
			};

			if !opt.message.is_empty() {
				message_options.extend_from_slice(&["--message", &opt.message]);
			}

			let edit_options = if opt.edit {
				vec!["--edit"]
			} else {
				vec!["--no-edit"]
			};

			let squash_options = if let Some(commit) = &opt.squash {
				vec!["--squash", commit]
			} else {
				vec![]
			};

			let amend_options = if head_is_failing_ref {
				vec!["--amend"]
			} else {
				vec![]
			};

			let no_verify_options = if opt.no_verify {
				vec!["--no-verify"]
			} else {
				vec![]
			};

			repository
				.command(
					&[
						base_options,
						message_options,
						edit_options,
						squash_options,
						amend_options,
						no_verify_options,
					]
					.concat(),
				)
				.and_then(|()| {
					if opt.fail {
						repository.command(&["update-ref", "refs/gamble-is-failing", "HEAD"])
					} else {
						Ok(())
					}
				})
				.and_then(|()| {
					log::info!("committed");
					Message::Info("Committed!".to_string()).display();

					repository
						.run_hook("post-gamble", &[post_hook_gambled, post_hook_actual])
						.map_err(|error| -> GambleError {
							error.add_message(Message::Warn(
								"It has been committed but the post-gamble hook failed to execute"
									.to_string(),
							))
						})
				})
		}
	})
}