diff options
Diffstat (limited to 'mingling_ci/src/cmd/cmd_git_unlock.rs')
| -rw-r--r-- | mingling_ci/src/cmd/cmd_git_unlock.rs | 116 |
1 files changed, 0 insertions, 116 deletions
diff --git a/mingling_ci/src/cmd/cmd_git_unlock.rs b/mingling_ci/src/cmd/cmd_git_unlock.rs deleted file mode 100644 index 41efefc..0000000 --- a/mingling_ci/src/cmd/cmd_git_unlock.rs +++ /dev/null @@ -1,116 +0,0 @@ -use mingling::{ - Grouped, RenderResult, Routable, - macros::{arg, buffer, command, r_println, renderer}, - picker::{EntryPicker, value::Flag}, - res::ResExitCode, -}; - -use crate::git::{LOCK_FILE, TEMP_COMMIT_MARK, head_message, run_git, worktree_clean}; -use crate::res::{CargoError, MessagePrinter}; -use crate::{Entry, Next}; - -/// Undoes a CI temporary commit created by [`crate::cmd::cmd_git_lock`]. -/// -/// Only acts when the HEAD commit message contains `CI TEMP` (case-sensitive). -/// The restore path is picked by the marker file content: -/// -/// - `true`: a base `TEMP` commit with the dirty changes sits below; restore -/// by hard-resetting past the marker commit, then soft-resetting and -/// unstaging to put the user's changes back into the working tree. -/// - `false`: the tree was clean; a single hard reset back to the original -/// HEAD is enough. -/// -/// When the working tree is dirty (e.g. CI left tracked changes behind) the -/// restore still runs, but the command reports a non-zero exit code so the -/// caller knows the CI phase contaminated the repository. With `--show-diff` -/// the diff of those changes is printed before they are discarded. -#[command(node = "git-unlock")] -// `#[command]` rewrites an owned first param into the entry type, so the args -// must be passed by value even though the body only reads them. -#[allow(clippy::needless_pass_by_value)] -pub fn git_unlock(args: Entry) -> Next { - let head = head_message().unwrap_or_default(); - if !head.contains(TEMP_COMMIT_MARK) { - return ErrorGitUnlock(format!("HEAD is not a CI temporary commit: `{head}`")).to_chain(); - } - - // Record dirtiness before restoring: the restore discards those changes. - let dirty = !worktree_clean(); - - // The marker file lives in the HEAD (CI TEMP) commit, so it is readable - // from the working tree; a missing marker falls back to the clean path. - let based_on_dirty = - std::fs::read_to_string(LOCK_FILE).is_ok_and(|content| content.trim() == "true"); - - if dirty && *args.pick(&arg![show_diff: Flag]).unwrap() { - show_diff(); - } - - if let Err(e) = undo_ci_phase(based_on_dirty) { - return ErrorGitUnlock(e).to_chain(); - } - - ResultGitUnlock { dirty }.to_chain() -} - -/// Prints the tracked changes the CI run left behind, before the restore -/// discards them. Untracked files are not shown (they are removed by clean). -fn show_diff() { - let Ok(diff) = run_git(["diff", "HEAD"]) else { - return; - }; - if diff.is_empty() { - return; - } - println!("{diff}"); -} - -/// Restores the workspace, keeping the user's pre-lock changes. -/// -/// With a base `TEMP` commit (`true`) the marker commit is dropped by a hard -/// reset to `HEAD~1`, the `TEMP` commit is unwrapped into the staging area by -/// a soft reset, and a plain reset unstages it back into the working tree. -/// Without one (`false`) a single hard reset to `HEAD~1` removes the marker -/// commit and lands on the original HEAD. -fn undo_ci_phase(based_on_dirty: bool) -> Result<(), String> { - run_git(["reset", "--hard", "HEAD~1"])?; - if based_on_dirty { - // Unwrap the `TEMP` commit into the staging area, then unstage it - // back into the working tree. - run_git(["reset", "--soft", "HEAD~1"])?; - run_git(["reset"])?; - } - std::fs::remove_file(LOCK_FILE).ok(); - Ok(()) -} - -/// Whether the working tree was dirty when the unlock started. -#[derive(Grouped)] -pub struct ResultGitUnlock { - dirty: bool, -} - -#[derive(Grouped, Default)] -pub struct ErrorGitUnlock(pub String); - -#[renderer(buffer)] -pub fn render_git_unlock(r: ResultGitUnlock, exit_code: &mut ResExitCode) { - if r.dirty { - r_println!("Unlocked: workspace restored (working tree was dirty)"); - exit_code.exit_code = 1; - } else { - r_println!("Unlocked: workspace restored"); - } -} - -#[renderer] -pub fn render_error_git_unlock( - e: ErrorGitUnlock, - error: &CargoError, - exit_code: &mut ResExitCode, -) -> RenderResult { - let render_result = RenderResult::new(); - error.println(vec![format!("Git-Unlock: {}", e.0)]); - exit_code.exit_code = 1; - render_result -} |
