From 9853743eda935a25ddce18e32e97cca0192d9389 Mon Sep 17 00:00:00 2001 From: Neil Kistner Date: Tue, 27 Aug 2019 22:11:42 -0500 Subject: [PATCH] feat: Add commit count for ahead/behind symbols (#247) Add logic for the git status module to display the number of commits the index is ahead or behind next to the symbol. --- src/modules/git_status.rs | 13 +- tests/fixtures/rocket.bundle | Bin 0 -> 1870 bytes tests/testsuite/git_status.rs | 318 ++++++++++++++++++++++++++++++++++ tests/testsuite/main.rs | 1 + 4 files changed, 330 insertions(+), 2 deletions(-) create mode 100644 tests/fixtures/rocket.bundle create mode 100644 tests/testsuite/git_status.rs diff --git a/src/modules/git_status.rs b/src/modules/git_status.rs index 8c675c33..693b938a 100644 --- a/src/modules/git_status.rs +++ b/src/modules/git_status.rs @@ -66,12 +66,17 @@ pub fn module<'a>(context: &'a Context) -> Option> { // Add the ahead/behind segment if let Ok((ahead, behind)) = ahead_behind { + let ahead_segment = format!("{}{}", GIT_STATUS_AHEAD, ahead); + let behind_segment = format!("{}{}", GIT_STATUS_BEHIND, behind); + if ahead > 0 && behind > 0 { module.new_segment("diverged", GIT_STATUS_DIVERGED); + module.new_segment("ahead", ahead_segment.as_str()); + module.new_segment("behind", behind_segment.as_str()); } else if ahead > 0 { - module.new_segment("ahead", GIT_STATUS_AHEAD); + module.new_segment("ahead", ahead_segment.as_str()); } else if behind > 0 { - module.new_segment("behind", GIT_STATUS_BEHIND); + module.new_segment("behind", behind_segment.as_str()); } } @@ -113,7 +118,11 @@ pub fn module<'a>(context: &'a Context) -> Option> { /// Gets the bitflags associated with the repo's git status fn get_repo_status(repository: &Repository) -> Result { let mut status_options = git2::StatusOptions::new(); + status_options.include_untracked(true); + status_options.renames_from_rewrites(true); + status_options.renames_head_to_index(true); + status_options.renames_index_to_workdir(true); let repo_file_statuses = repository.statuses(Some(&mut status_options))?; diff --git a/tests/fixtures/rocket.bundle b/tests/fixtures/rocket.bundle new file mode 100644 index 0000000000000000000000000000000000000000..ca42dde93b920290e0edd84e7f7e76b8921f2863 GIT binary patch literal 1870 zcmV-U2eJ4gAa*h!XK8dGVs&n0Y-I{FHDqHmIA%FAGG#PkHe@z6IW}WsH)AznFk)gg zV_{}6FlI4iVm34&a%E<7FKA_9WOFZVVRLk4ataDiK|@Ob00062000J%M0lK?leZG9 zRun~hzT)H43BItrd_J!j7dLI4RqrO1>NSCA!1<`l)}0?Zkb zOc{!?~T~A0d+3;-F=cZRS;(Z_2 zs=jUay$*+6-&`~&%Hi>>QpLGsMElt=fIpi;MtGNr9E|ljPw93-YP_)mIRt!{9731t z$5V21GQ)C)U9%{I*WU^EaL2Eky<(FV8!;lB}!3dPPVC2dFu>n z8fA)MH)lut6Dh30V_+e?tfoF^TD@@wZ?!%fpR`kCl2jcLqg8drqI(r_r1p(nZqtP^ zx5rU9zt8tbanE&t0W;`I6jfsL(8vv^MsIv6r}Ci}JNqarNsI=+zEzgg&Uw*1;*RaZ zaMCE|si9j)-DM0+kF_(TB%;rs=78U=Z@;oFOiPdZOowwbPHJ(p7slF2`}M)MOYU>R zw^q+i;)vi345)K2EFoOq?f0Rrxf*6OKddvH=uV+<&A-yHfJJdyM`-l7rJ}^?CkB4b zrxT9-+Kgta|FsxQDhhyLT67Tm3l9fa?VUk*oSl=o5~EfSMRUI5<&Oqj@;R~K?mLEj(whkoK6oJlW}Ph(=1Crxg<+-nx)B{i{q5% zd72XhGJ9h2G?rZt?7V7#Q4Qle@4@fyFa7rVhyE25(6n2U1?KJYQK&ao@I>(+ih_ehVWkA>XN@r zgH2Rt+t=1oO&E&th~uWa)s^C3E>9X5KtwLnCl>AZQ!~0|h&U$H&V)0ncnrgjA$3ub z$LW5Pb>)5WdZ!3Y!m&3bI+ok|XAHa;1}fPSXRMt`k;pXFG@88mxwWjL&-EIfrHgVO za=d7f@pw7IDEBT^M<_7earAra`=~v^CsXDxyRnjl)pRwJEK75Zjjg9_+)c$x@hToC zSC6=RhXyY;4A(mt=j7dR&GfybPpO^BNcL2mZk{Xn*14Knxw_e8_0W`9r=D;1nYNmC zJx}5>xDR@O$N;g{8V0yWV_Kbf{o z_-!;ThNM2{y-+(!&8-Utc#jBgg0HqaGo!oG3GO{{J?~L3WIt`~l0`8gm8hjcDu#^} z!NKd}_WmK}&Ipzy#Q>Dx&J9|BW%q7`8jSNQm=B0>x@B`@{ahMnQgeI6nkk;)Vg#GB zuQtzRoe1e*$ub6rSVEsh}`Ik`&Ek#zCUsI+an=uniG_$&3ktDcv-_=;fO||FXIt?R0eOKq{i2Vi0CQzrV1bCb?G%zqTF;Q?%EK1MU zE6LBzVR$z8(dHO=kboDxdjm z`7)pUlA7e$8~};jASy6;oC5#=0003vc$`yK$Vkn}$>#z93Pl29rUH1JGc+(TGci$c zPAp2#*DJ}-&0%;p_tET47q2;ccWbUIkGgT_Nl)-Z02lHRE)x~*HzBCK8zE8y1nQu% IH+np?czyVfwg3PC literal 0 HcmV?d00001 diff --git a/tests/testsuite/git_status.rs b/tests/testsuite/git_status.rs new file mode 100644 index 00000000..4fd213b0 --- /dev/null +++ b/tests/testsuite/git_status.rs @@ -0,0 +1,318 @@ +use ansi_term::Color; +use git2::Repository; +use std::env; +use std::fs::{self, File}; +use std::io; +use std::process::Command; + +use crate::common; + +fn create_fixture_repo() -> io::Result { + let fixture_repo_dir = common::new_tempdir()?.path().join("fixture"); + let fixture = env::current_dir()?.join("tests/fixtures/rocket.bundle"); + + Command::new("git") + .args(&["config", "--global", "user.email", "starship@example.com"]) + .output()?; + + Command::new("git") + .args(&["config", "--global", "user.name", "starship"]) + .output()?; + + Command::new("git") + .args(&[ + "clone", + "-b", + "master", + &fixture.to_str().unwrap(), + fixture_repo_dir.to_str().unwrap(), + ]) + .output()?; + + Ok(fixture_repo_dir) +} + +#[test] +#[ignore] +fn shows_behind_count() -> io::Result<()> { + let fixture_repo_dir = create_fixture_repo()?; + let repo_dir = common::new_tempdir()?.path().join("rocket"); + + Repository::clone(fixture_repo_dir.to_str().unwrap(), &repo_dir.as_path()).unwrap(); + + Command::new("git") + .args(&["reset", "--hard", "HEAD^"]) + .current_dir(repo_dir.as_path()) + .output()?; + + let output = common::render_module("git_status") + .arg("--path") + .arg(repo_dir) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + let expected = Color::Red + .bold() + .paint(format!("[{}] ", "⇣1")) + .to_string(); + + assert_eq!(expected, actual); + + Ok(()) +} + +#[test] +#[ignore] +fn shows_ahead_count() -> io::Result<()> { + let fixture_repo_dir = create_fixture_repo()?; + let repo_dir = common::new_tempdir()?.path().join("rocket"); + + Repository::clone(fixture_repo_dir.to_str().unwrap(), &repo_dir.as_path()).unwrap(); + + File::create(repo_dir.join("readme.md"))?; + + Command::new("git") + .args(&["commit", "-am", "Update readme"]) + .current_dir(&repo_dir) + .output()?; + + let output = common::render_module("git_status") + .arg("--path") + .arg(repo_dir) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + let expected = Color::Red + .bold() + .paint(format!("[{}] ", "⇡1")) + .to_string(); + + assert_eq!(expected, actual); + + Ok(()) +} + +#[test] +#[ignore] +fn shows_diverged() -> io::Result<()> { + let fixture_repo_dir = create_fixture_repo()?; + let repo_dir = common::new_tempdir()?.path().join("rocket"); + + Repository::clone(fixture_repo_dir.to_str().unwrap(), &repo_dir.as_path()).unwrap(); + + Command::new("git") + .args(&["reset", "--hard", "HEAD^"]) + .current_dir(repo_dir.as_path()) + .output()?; + + fs::write(repo_dir.join("Cargo.toml"), " ")?; + + Command::new("git") + .args(&["commit", "-am", "Update readme"]) + .current_dir(repo_dir.as_path()) + .output()?; + + let output = common::render_module("git_status") + .arg("--path") + .arg(repo_dir) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + let expected = Color::Red + .bold() + .paint(format!("[{}] ", "⇕⇡1⇣1")) + .to_string(); + + assert_eq!(expected, actual); + + Ok(()) +} + +#[test] +#[ignore] +fn shows_conflicted() -> io::Result<()> { + let fixture_repo_dir = create_fixture_repo()?; + let repo_dir = common::new_tempdir()?.path().join("rocket"); + + Repository::clone(fixture_repo_dir.to_str().unwrap(), &repo_dir.as_path()).unwrap(); + + Command::new("git") + .args(&["reset", "--hard", "HEAD^"]) + .current_dir(repo_dir.as_path()) + .output()?; + + fs::write(repo_dir.join("readme.md"), "# goodbye")?; + + Command::new("git") + .args(&["add", "."]) + .current_dir(repo_dir.as_path()) + .output()?; + + Command::new("git") + .args(&["commit", "-m", "Change readme"]) + .current_dir(repo_dir.as_path()) + .output()?; + + Command::new("git") + .args(&["pull", "--rebase"]) + .current_dir(repo_dir.as_path()) + .output()?; + + let output = common::render_module("git_status") + .arg("--path") + .arg(repo_dir) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + let expected = Color::Red.bold().paint(format!("[{}] ", "=")).to_string(); + + assert_eq!(expected, actual); + + Ok(()) +} + +#[test] +#[ignore] +fn shows_untracked_file() -> io::Result<()> { + let fixture_repo_dir = create_fixture_repo()?; + let repo_dir = common::new_tempdir()?.path().join("rocket"); + + Repository::clone(fixture_repo_dir.to_str().unwrap(), &repo_dir.as_path()).unwrap(); + + File::create(repo_dir.join("license"))?; + + let output = common::render_module("git_status") + .arg("--path") + .arg(repo_dir) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + let expected = Color::Red.bold().paint(format!("[{}] ", "?")).to_string(); + + assert_eq!(expected, actual); + + Ok(()) +} + +#[test] +#[ignore] +fn shows_stashed() -> io::Result<()> { + let fixture_repo_dir = create_fixture_repo()?; + let repo_dir = common::new_tempdir()?.path().join("rocket"); + + Repository::clone(fixture_repo_dir.to_str().unwrap(), &repo_dir.as_path()).unwrap(); + + File::create(repo_dir.join("readme.md"))?; + + Command::new("git") + .arg("stash") + .current_dir(repo_dir.as_path()) + .output()?; + + let output = common::render_module("git_status") + .arg("--path") + .arg(repo_dir) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + let expected = Color::Red.bold().paint(format!("[{}] ", "$")).to_string(); + + assert_eq!(expected, actual); + + Ok(()) +} + +#[test] +#[ignore] +fn shows_modified() -> io::Result<()> { + let fixture_repo_dir = create_fixture_repo()?; + let repo_dir = common::new_tempdir()?.path().join("rocket"); + + Repository::clone(fixture_repo_dir.to_str().unwrap(), &repo_dir.as_path()).unwrap(); + + File::create(repo_dir.join("readme.md"))?; + + let output = common::render_module("git_status") + .arg("--path") + .arg(repo_dir) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + let expected = Color::Red.bold().paint(format!("[{}] ", "!")).to_string(); + + assert_eq!(expected, actual); + + Ok(()) +} + +#[test] +#[ignore] +fn shows_added_file() -> io::Result<()> { + let fixture_repo_dir = create_fixture_repo()?; + let repo_dir = common::new_tempdir()?.path().join("rocket"); + + Repository::clone(fixture_repo_dir.to_str().unwrap(), &repo_dir.as_path()).unwrap(); + + File::create(repo_dir.join("license"))?; + + Command::new("git") + .args(&["add", "."]) + .current_dir(repo_dir.as_path()) + .output()?; + + let output = common::render_module("git_status") + .arg("--path") + .arg(repo_dir) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + let expected = Color::Red.bold().paint(format!("[{}] ", "+")).to_string(); + + assert_eq!(expected, actual); + + Ok(()) +} + +#[test] +#[ignore] +fn shows_renamed_file() -> io::Result<()> { + let fixture_repo_dir = create_fixture_repo()?; + let repo_dir = common::new_tempdir()?.path().join("rocket"); + + Repository::clone(fixture_repo_dir.to_str().unwrap(), &repo_dir.as_path()).unwrap(); + + Command::new("git") + .args(&["mv", "readme.md", "readme.md.bak"]) + .current_dir(repo_dir.as_path()) + .output()?; + + Command::new("git") + .args(&["add", "-A"]) + .current_dir(repo_dir.as_path()) + .output()?; + + let output = common::render_module("git_status") + .arg("--path") + .arg(repo_dir) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + let expected = Color::Red.bold().paint(format!("[{}] ", "»")).to_string(); + + assert_eq!(expected, actual); + + Ok(()) +} + +#[test] +#[ignore] +fn shows_deleted_file() -> io::Result<()> { + let fixture_repo_dir = create_fixture_repo()?; + let repo_dir = common::new_tempdir()?.path().join("rocket"); + + Repository::clone(fixture_repo_dir.to_str().unwrap(), &repo_dir.as_path()).unwrap(); + + fs::remove_file(repo_dir.join("readme.md"))?; + + let output = common::render_module("git_status") + .arg("--path") + .arg(repo_dir) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + let expected = Color::Red.bold().paint(format!("[{}] ", "✘")).to_string(); + + assert_eq!(expected, actual); + + Ok(()) +} diff --git a/tests/testsuite/main.rs b/tests/testsuite/main.rs index 4ecde379..ed028983 100644 --- a/tests/testsuite/main.rs +++ b/tests/testsuite/main.rs @@ -3,6 +3,7 @@ mod cmd_duration; mod common; mod configuration; mod directory; +mod git_status; mod golang; mod jobs; mod line_break;