diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2024-09-04 11:32:05 +0100 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2024-09-04 14:23:54 +0100 |
| commit | 771f944af447c202eba045936a36dee71ab797ac (patch) | |
| tree | e691de4ebc8dde7ac4855e139881ff923bc254ce /src/lib/git/identify_ahead_behind.rs | |
| parent | 949c6459aa7683453a7160423b689ceadb08954b (diff) | |
refactor: fix imports, etc based on restructure
move some functions out of ngit and into lib/mod
and lib/git_events
remove MockConnect from binaries so it is only used in the library.
this was done:
* mainly because automocks were not being imported from
lib into each binary
* but also because the these functions were being
tested with MockConnect
Diffstat (limited to 'src/lib/git/identify_ahead_behind.rs')
| -rw-r--r-- | src/lib/git/identify_ahead_behind.rs | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/src/lib/git/identify_ahead_behind.rs b/src/lib/git/identify_ahead_behind.rs new file mode 100644 index 0000000..c98c994 --- /dev/null +++ b/src/lib/git/identify_ahead_behind.rs | |||
| @@ -0,0 +1,196 @@ | |||
| 1 | use anyhow::{Context, Result}; | ||
| 2 | use nostr_sdk::hashes::sha1::Hash as Sha1Hash; | ||
| 3 | |||
| 4 | use super::{Repo, RepoActions}; | ||
| 5 | |||
| 6 | /** | ||
| 7 | * returns `(from_branch,to_branch,ahead,behind)` | ||
| 8 | */ | ||
| 9 | pub fn identify_ahead_behind( | ||
| 10 | git_repo: &Repo, | ||
| 11 | from_branch: &Option<String>, | ||
| 12 | to_branch: &Option<String>, | ||
| 13 | ) -> Result<(String, String, Vec<Sha1Hash>, Vec<Sha1Hash>)> { | ||
| 14 | let (from_branch, from_tip) = match from_branch { | ||
| 15 | Some(name) => ( | ||
| 16 | name.to_string(), | ||
| 17 | git_repo | ||
| 18 | .get_tip_of_branch(name) | ||
| 19 | .context(format!("cannot find from_branch '{name}'"))?, | ||
| 20 | ), | ||
| 21 | None => ( | ||
| 22 | if let Ok(name) = git_repo.get_checked_out_branch_name() { | ||
| 23 | name | ||
| 24 | } else { | ||
| 25 | "head".to_string() | ||
| 26 | }, | ||
| 27 | git_repo | ||
| 28 | .get_head_commit() | ||
| 29 | .context("failed to get head commit") | ||
| 30 | .context( | ||
| 31 | "checkout a commit or specify a from_branch. head does not reveal a commit", | ||
| 32 | )?, | ||
| 33 | ), | ||
| 34 | }; | ||
| 35 | |||
| 36 | let (to_branch, to_tip) = match to_branch { | ||
| 37 | Some(name) => ( | ||
| 38 | name.to_string(), | ||
| 39 | git_repo | ||
| 40 | .get_tip_of_branch(name) | ||
| 41 | .context(format!("cannot find to_branch '{name}'"))?, | ||
| 42 | ), | ||
| 43 | None => { | ||
| 44 | let (name, commit) = git_repo | ||
| 45 | .get_main_or_master_branch() | ||
| 46 | .context("the default branches (main or master) do not exist")?; | ||
| 47 | (name.to_string(), commit) | ||
| 48 | } | ||
| 49 | }; | ||
| 50 | |||
| 51 | match git_repo.get_commits_ahead_behind(&to_tip, &from_tip) { | ||
| 52 | Err(e) => { | ||
| 53 | if e.to_string().contains("is not an ancestor of") { | ||
| 54 | return Err(e).context(format!( | ||
| 55 | "'{from_branch}' is not branched from '{to_branch}'" | ||
| 56 | )); | ||
| 57 | } | ||
| 58 | Err(e).context(format!( | ||
| 59 | "failed to get commits ahead and behind from '{from_branch}' to '{to_branch}'" | ||
| 60 | )) | ||
| 61 | } | ||
| 62 | Ok((ahead, behind)) => Ok((from_branch, to_branch, ahead, behind)), | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | #[cfg(test)] | ||
| 67 | mod tests { | ||
| 68 | |||
| 69 | use test_utils::git::GitTestRepo; | ||
| 70 | |||
| 71 | use super::*; | ||
| 72 | use crate::git::oid_to_sha1; | ||
| 73 | |||
| 74 | #[test] | ||
| 75 | fn when_from_branch_doesnt_exist_return_error() -> Result<()> { | ||
| 76 | let test_repo = GitTestRepo::default(); | ||
| 77 | let git_repo = Repo::from_path(&test_repo.dir)?; | ||
| 78 | |||
| 79 | test_repo.populate()?; | ||
| 80 | let branch_name = "doesnt_exist"; | ||
| 81 | assert_eq!( | ||
| 82 | identify_ahead_behind(&git_repo, &Some(branch_name.to_string()), &None) | ||
| 83 | .unwrap_err() | ||
| 84 | .to_string(), | ||
| 85 | format!("cannot find from_branch '{}'", &branch_name), | ||
| 86 | ); | ||
| 87 | Ok(()) | ||
| 88 | } | ||
| 89 | |||
| 90 | #[test] | ||
| 91 | fn when_to_branch_doesnt_exist_return_error() -> Result<()> { | ||
| 92 | let test_repo = GitTestRepo::default(); | ||
| 93 | let git_repo = Repo::from_path(&test_repo.dir)?; | ||
| 94 | |||
| 95 | test_repo.populate()?; | ||
| 96 | let branch_name = "doesnt_exist"; | ||
| 97 | assert_eq!( | ||
| 98 | identify_ahead_behind(&git_repo, &None, &Some(branch_name.to_string())) | ||
| 99 | .unwrap_err() | ||
| 100 | .to_string(), | ||
| 101 | format!("cannot find to_branch '{}'", &branch_name), | ||
| 102 | ); | ||
| 103 | Ok(()) | ||
| 104 | } | ||
| 105 | |||
| 106 | #[test] | ||
| 107 | fn when_to_branch_is_none_and_no_main_or_master_branch_return_error() -> Result<()> { | ||
| 108 | let test_repo = GitTestRepo::new("notmain")?; | ||
| 109 | let git_repo = Repo::from_path(&test_repo.dir)?; | ||
| 110 | |||
| 111 | test_repo.populate()?; | ||
| 112 | |||
| 113 | assert_eq!( | ||
| 114 | identify_ahead_behind(&git_repo, &None, &None) | ||
| 115 | .unwrap_err() | ||
| 116 | .to_string(), | ||
| 117 | "the default branches (main or master) do not exist", | ||
| 118 | ); | ||
| 119 | Ok(()) | ||
| 120 | } | ||
| 121 | |||
| 122 | #[test] | ||
| 123 | fn when_from_branch_is_not_head_return_as_from_branch() -> Result<()> { | ||
| 124 | let test_repo = GitTestRepo::default(); | ||
| 125 | let git_repo = Repo::from_path(&test_repo.dir)?; | ||
| 126 | |||
| 127 | test_repo.populate()?; | ||
| 128 | // create feature branch with 1 commit ahead | ||
| 129 | test_repo.create_branch("feature")?; | ||
| 130 | test_repo.checkout("feature")?; | ||
| 131 | std::fs::write(test_repo.dir.join("t3.md"), "some content")?; | ||
| 132 | let head_oid = test_repo.stage_and_commit("add t3.md")?; | ||
| 133 | |||
| 134 | // make feature branch 1 commit behind | ||
| 135 | test_repo.checkout("main")?; | ||
| 136 | std::fs::write(test_repo.dir.join("t4.md"), "some content")?; | ||
| 137 | let main_oid = test_repo.stage_and_commit("add t4.md")?; | ||
| 138 | |||
| 139 | let (from_branch, to_branch, ahead, behind) = | ||
| 140 | identify_ahead_behind(&git_repo, &Some("feature".to_string()), &None)?; | ||
| 141 | |||
| 142 | assert_eq!(from_branch, "feature"); | ||
| 143 | assert_eq!(ahead, vec![oid_to_sha1(&head_oid)]); | ||
| 144 | assert_eq!(to_branch, "main"); | ||
| 145 | assert_eq!(behind, vec![oid_to_sha1(&main_oid)]); | ||
| 146 | Ok(()) | ||
| 147 | } | ||
| 148 | |||
| 149 | #[test] | ||
| 150 | fn when_to_branch_is_not_main_return_as_to_branch() -> Result<()> { | ||
| 151 | let test_repo = GitTestRepo::default(); | ||
| 152 | let git_repo = Repo::from_path(&test_repo.dir)?; | ||
| 153 | |||
| 154 | test_repo.populate()?; | ||
| 155 | // create dev branch with 1 commit ahead | ||
| 156 | test_repo.create_branch("dev")?; | ||
| 157 | test_repo.checkout("dev")?; | ||
| 158 | std::fs::write(test_repo.dir.join("t3.md"), "some content")?; | ||
| 159 | let dev_oid_first = test_repo.stage_and_commit("add t3.md")?; | ||
| 160 | |||
| 161 | // create feature branch with 1 commit ahead of dev | ||
| 162 | test_repo.create_branch("feature")?; | ||
| 163 | test_repo.checkout("feature")?; | ||
| 164 | std::fs::write(test_repo.dir.join("t4.md"), "some content")?; | ||
| 165 | let feature_oid = test_repo.stage_and_commit("add t4.md")?; | ||
| 166 | |||
| 167 | // make feature branch 1 behind | ||
| 168 | test_repo.checkout("dev")?; | ||
| 169 | std::fs::write(test_repo.dir.join("t3.md"), "some content")?; | ||
| 170 | let dev_oid = test_repo.stage_and_commit("add t3.md")?; | ||
| 171 | |||
| 172 | let (from_branch, to_branch, ahead, behind) = identify_ahead_behind( | ||
| 173 | &git_repo, | ||
| 174 | &Some("feature".to_string()), | ||
| 175 | &Some("dev".to_string()), | ||
| 176 | )?; | ||
| 177 | |||
| 178 | assert_eq!(from_branch, "feature"); | ||
| 179 | assert_eq!(ahead, vec![oid_to_sha1(&feature_oid)]); | ||
| 180 | assert_eq!(to_branch, "dev"); | ||
| 181 | assert_eq!(behind, vec![oid_to_sha1(&dev_oid)]); | ||
| 182 | |||
| 183 | let (from_branch, to_branch, ahead, behind) = | ||
| 184 | identify_ahead_behind(&git_repo, &Some("feature".to_string()), &None)?; | ||
| 185 | |||
| 186 | assert_eq!(from_branch, "feature"); | ||
| 187 | assert_eq!( | ||
| 188 | ahead, | ||
| 189 | vec![oid_to_sha1(&feature_oid), oid_to_sha1(&dev_oid_first)] | ||
| 190 | ); | ||
| 191 | assert_eq!(to_branch, "main"); | ||
| 192 | assert_eq!(behind, vec![]); | ||
| 193 | |||
| 194 | Ok(()) | ||
| 195 | } | ||
| 196 | } | ||