upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2024-03-08 16:49:03 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2024-03-08 17:27:13 +0000
commit098b0258fdd581c750099cb463adbddb57843388 (patch)
tree000b80fd630083aefef314ec999060c65fb57573 /src
parent6b3aecbcbde669859533716225e9c3bbfd2023b2 (diff)
feat(send): compare against origin/main vs main
catch more errors when proposed commits are not connected to origin/main branch improve default selected commits when on main branch
Diffstat (limited to 'src')
-rw-r--r--src/git.rs92
-rw-r--r--src/sub_commands/list.rs2
-rw-r--r--src/sub_commands/pull.rs2
-rw-r--r--src/sub_commands/push.rs2
-rw-r--r--src/sub_commands/send.rs29
5 files changed, 97 insertions, 30 deletions
diff --git a/src/git.rs b/src/git.rs
index 42297be..bb2b8e7 100644
--- a/src/git.rs
+++ b/src/git.rs
@@ -32,10 +32,13 @@ impl Repo {
32pub trait RepoActions { 32pub trait RepoActions {
33 fn get_path(&self) -> Result<&Path>; 33 fn get_path(&self) -> Result<&Path>;
34 fn get_origin_url(&self) -> Result<String>; 34 fn get_origin_url(&self) -> Result<String>;
35 fn get_remote_branch_names(&self) -> Result<Vec<String>>;
35 fn get_local_branch_names(&self) -> Result<Vec<String>>; 36 fn get_local_branch_names(&self) -> Result<Vec<String>>;
37 fn get_origin_main_or_master_branch(&self) -> Result<(&str, Sha1Hash)>;
38 fn get_local_main_or_master_branch(&self) -> Result<(&str, Sha1Hash)>;
36 fn get_main_or_master_branch(&self) -> Result<(&str, Sha1Hash)>; 39 fn get_main_or_master_branch(&self) -> Result<(&str, Sha1Hash)>;
37 fn get_checked_out_branch_name(&self) -> Result<String>; 40 fn get_checked_out_branch_name(&self) -> Result<String>;
38 fn get_tip_of_local_branch(&self, branch_name: &str) -> Result<Sha1Hash>; 41 fn get_tip_of_branch(&self, branch_name: &str) -> Result<Sha1Hash>;
39 fn get_root_commit(&self) -> Result<Sha1Hash>; 42 fn get_root_commit(&self) -> Result<Sha1Hash>;
40 fn does_commit_exist(&self, commit: &str) -> Result<bool>; 43 fn does_commit_exist(&self, commit: &str) -> Result<bool>;
41 fn get_head_commit(&self) -> Result<Sha1Hash>; 44 fn get_head_commit(&self) -> Result<Sha1Hash>;
@@ -91,7 +94,30 @@ impl RepoActions for Repo {
91 .to_string()) 94 .to_string())
92 } 95 }
93 96
94 fn get_main_or_master_branch(&self) -> Result<(&str, Sha1Hash)> { 97 fn get_origin_main_or_master_branch(&self) -> Result<(&str, Sha1Hash)> {
98 let main_branch_name = {
99 let remote_branches = self
100 .get_remote_branch_names()
101 .context("cannot find any local branches")?;
102 if remote_branches.contains(&"origin/main".to_string()) {
103 "origin/main"
104 } else if remote_branches.contains(&"origin/master".to_string()) {
105 "origin/master"
106 } else {
107 bail!("no main or master branch locally in this git repository to initiate from",)
108 }
109 };
110
111 let tip = self
112 .get_tip_of_branch(main_branch_name)
113 .context(format!(
114 "branch {main_branch_name} was listed as a remote branch but cannot get its tip commit id",
115 ))?;
116
117 Ok((main_branch_name, tip))
118 }
119
120 fn get_local_main_or_master_branch(&self) -> Result<(&str, Sha1Hash)> {
95 let main_branch_name = { 121 let main_branch_name = {
96 let local_branches = self 122 let local_branches = self
97 .get_local_branch_names() 123 .get_local_branch_names()
@@ -106,7 +132,7 @@ impl RepoActions for Repo {
106 }; 132 };
107 133
108 let tip = self 134 let tip = self
109 .get_tip_of_local_branch(main_branch_name) 135 .get_tip_of_branch(main_branch_name)
110 .context(format!( 136 .context(format!(
111 "branch {main_branch_name} was listed as a local branch but cannot get its tip commit id", 137 "branch {main_branch_name} was listed as a local branch but cannot get its tip commit id",
112 ))?; 138 ))?;
@@ -114,6 +140,18 @@ impl RepoActions for Repo {
114 Ok((main_branch_name, tip)) 140 Ok((main_branch_name, tip))
115 } 141 }
116 142
143 fn get_main_or_master_branch(&self) -> Result<(&str, Sha1Hash)> {
144 if let Ok(main_tuple) = self
145 .get_origin_main_or_master_branch()
146 .context("the default branches (main or master) do not exist")
147 {
148 Ok(main_tuple)
149 } else {
150 self.get_main_or_master_branch()
151 .context("the default branches (main or master) do not exist")
152 }
153 }
154
117 fn get_local_branch_names(&self) -> Result<Vec<String>> { 155 fn get_local_branch_names(&self) -> Result<Vec<String>> {
118 let local_branches = self 156 let local_branches = self
119 .git_repo 157 .git_repo
@@ -131,6 +169,23 @@ impl RepoActions for Repo {
131 Ok(branch_names) 169 Ok(branch_names)
132 } 170 }
133 171
172 fn get_remote_branch_names(&self) -> Result<Vec<String>> {
173 let remote_branches = self
174 .git_repo
175 .branches(Some(git2::BranchType::Remote))
176 .context("getting GitRepo branches should not error even for a blank repository")?;
177
178 let mut branch_names = vec![];
179
180 for iter in remote_branches {
181 let branch = iter?.0;
182 if let Some(name) = branch.name()? {
183 branch_names.push(name.to_string());
184 }
185 }
186 Ok(branch_names)
187 }
188
134 fn get_checked_out_branch_name(&self) -> Result<String> { 189 fn get_checked_out_branch_name(&self) -> Result<String> {
135 Ok(self 190 Ok(self
136 .git_repo 191 .git_repo
@@ -140,11 +195,18 @@ impl RepoActions for Repo {
140 .to_string()) 195 .to_string())
141 } 196 }
142 197
143 fn get_tip_of_local_branch(&self, branch_name: &str) -> Result<Sha1Hash> { 198 fn get_tip_of_branch(&self, branch_name: &str) -> Result<Sha1Hash> {
144 let branch = self 199 let branch = if let Ok(branch) = self
145 .git_repo 200 .git_repo
146 .find_branch(branch_name, git2::BranchType::Local) 201 .find_branch(branch_name, git2::BranchType::Local)
147 .context(format!("cannot find branch {branch_name}"))?; 202 .context(format!("cannot find local branch {branch_name}"))
203 {
204 branch
205 } else {
206 self.git_repo
207 .find_branch(branch_name, git2::BranchType::Remote)
208 .context(format!("cannot find local or remote branch {branch_name}"))?
209 };
148 Ok(oid_to_sha1(&branch.into_reference().peel_to_commit()?.id())) 210 Ok(oid_to_sha1(&branch.into_reference().peel_to_commit()?.id()))
149 } 211 }
150 212
@@ -407,7 +469,7 @@ impl RepoActions for Repo {
407 branch_name: &str, 469 branch_name: &str,
408 patch_and_ancestors: Vec<nostr::Event>, 470 patch_and_ancestors: Vec<nostr::Event>,
409 ) -> Result<Vec<nostr::Event>> { 471 ) -> Result<Vec<nostr::Event>> {
410 let branch_tip_result = self.get_tip_of_local_branch(branch_name); 472 let branch_tip_result = self.get_tip_of_branch(branch_name);
411 473
412 // filter out existing ancestors in branch 474 // filter out existing ancestors in branch
413 let mut patches_to_apply: Vec<nostr::Event> = patch_and_ancestors 475 let mut patches_to_apply: Vec<nostr::Event> = patch_and_ancestors
@@ -1663,7 +1725,7 @@ mod tests {
1663 let git_repo = Repo::from_path(&test_repo.dir)?; 1725 let git_repo = Repo::from_path(&test_repo.dir)?;
1664 git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?; 1726 git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?;
1665 assert_eq!( 1727 assert_eq!(
1666 git_repo.get_tip_of_local_branch(BRANCH_NAME)?, 1728 git_repo.get_tip_of_branch(BRANCH_NAME)?,
1667 oid_to_sha1(&original_repo.git_repo.head()?.peel_to_commit()?.id(),), 1729 oid_to_sha1(&original_repo.git_repo.head()?.peel_to_commit()?.id(),),
1668 ); 1730 );
1669 Ok(()) 1731 Ok(())
@@ -1677,11 +1739,11 @@ mod tests {
1677 let existing_branch = test_repo.get_checked_out_branch_name()?; 1739 let existing_branch = test_repo.get_checked_out_branch_name()?;
1678 let git_repo = Repo::from_path(&test_repo.dir)?; 1740 let git_repo = Repo::from_path(&test_repo.dir)?;
1679 let previous_tip_of_existing_branch = 1741 let previous_tip_of_existing_branch =
1680 git_repo.get_tip_of_local_branch(existing_branch.as_str())?; 1742 git_repo.get_tip_of_branch(existing_branch.as_str())?;
1681 git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?; 1743 git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?;
1682 assert_eq!( 1744 assert_eq!(
1683 previous_tip_of_existing_branch, 1745 previous_tip_of_existing_branch,
1684 git_repo.get_tip_of_local_branch(existing_branch.as_str())?, 1746 git_repo.get_tip_of_branch(existing_branch.as_str())?,
1685 ); 1747 );
1686 Ok(()) 1748 Ok(())
1687 } 1749 }
@@ -1744,7 +1806,7 @@ mod tests {
1744 let git_repo = Repo::from_path(&test_repo.dir)?; 1806 let git_repo = Repo::from_path(&test_repo.dir)?;
1745 git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?; 1807 git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?;
1746 assert_eq!( 1808 assert_eq!(
1747 git_repo.get_tip_of_local_branch(BRANCH_NAME)?, 1809 git_repo.get_tip_of_branch(BRANCH_NAME)?,
1748 oid_to_sha1(&original_repo.git_repo.head()?.peel_to_commit()?.id(),), 1810 oid_to_sha1(&original_repo.git_repo.head()?.peel_to_commit()?.id(),),
1749 ); 1811 );
1750 Ok(()) 1812 Ok(())
@@ -1760,11 +1822,11 @@ mod tests {
1760 let existing_branch = test_repo.get_checked_out_branch_name()?; 1822 let existing_branch = test_repo.get_checked_out_branch_name()?;
1761 let git_repo = Repo::from_path(&test_repo.dir)?; 1823 let git_repo = Repo::from_path(&test_repo.dir)?;
1762 let previous_tip_of_existing_branch = 1824 let previous_tip_of_existing_branch =
1763 git_repo.get_tip_of_local_branch(existing_branch.as_str())?; 1825 git_repo.get_tip_of_branch(existing_branch.as_str())?;
1764 git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?; 1826 git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?;
1765 assert_eq!( 1827 assert_eq!(
1766 previous_tip_of_existing_branch, 1828 previous_tip_of_existing_branch,
1767 git_repo.get_tip_of_local_branch(existing_branch.as_str())?, 1829 git_repo.get_tip_of_branch(existing_branch.as_str())?,
1768 ); 1830 );
1769 Ok(()) 1831 Ok(())
1770 } 1832 }
@@ -1800,7 +1862,7 @@ mod tests {
1800 git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?; 1862 git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?;
1801 1863
1802 assert_eq!( 1864 assert_eq!(
1803 git_repo.get_tip_of_local_branch(BRANCH_NAME)?, 1865 git_repo.get_tip_of_branch(BRANCH_NAME)?,
1804 oid_to_sha1(&original_repo.git_repo.head()?.peel_to_commit()?.id(),), 1866 oid_to_sha1(&original_repo.git_repo.head()?.peel_to_commit()?.id(),),
1805 ); 1867 );
1806 Ok(()) 1868 Ok(())
@@ -1832,7 +1894,7 @@ mod tests {
1832 git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?; 1894 git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?;
1833 1895
1834 assert_eq!( 1896 assert_eq!(
1835 git_repo.get_tip_of_local_branch(BRANCH_NAME)?, 1897 git_repo.get_tip_of_branch(BRANCH_NAME)?,
1836 oid_to_sha1(&original_repo.git_repo.head()?.peel_to_commit()?.id(),), 1898 oid_to_sha1(&original_repo.git_repo.head()?.peel_to_commit()?.id(),),
1837 ); 1899 );
1838 Ok(()) 1900 Ok(())
diff --git a/src/sub_commands/list.rs b/src/sub_commands/list.rs
index ad5a28d..102c3bd 100644
--- a/src/sub_commands/list.rs
+++ b/src/sub_commands/list.rs
@@ -274,7 +274,7 @@ pub async fn launch(_cli_args: &Cli, _args: &SubCommandArgs) -> Result<()> {
274 }; 274 };
275 } 275 }
276 276
277 let local_branch_tip = git_repo.get_tip_of_local_branch(&cover_letter.branch_name)?; 277 let local_branch_tip = git_repo.get_tip_of_branch(&cover_letter.branch_name)?;
278 278
279 // up-to-date 279 // up-to-date
280 if proposal_tip.eq(&local_branch_tip) { 280 if proposal_tip.eq(&local_branch_tip) {
diff --git a/src/sub_commands/pull.rs b/src/sub_commands/pull.rs
index daae37f..716e6c5 100644
--- a/src/sub_commands/pull.rs
+++ b/src/sub_commands/pull.rs
@@ -60,7 +60,7 @@ pub async fn launch() -> Result<()> {
60 get_most_recent_patch_with_ancestors(commit_events.clone()) 60 get_most_recent_patch_with_ancestors(commit_events.clone())
61 .context("cannot get most recent patch for proposal")?; 61 .context("cannot get most recent patch for proposal")?;
62 62
63 let local_branch_tip = git_repo.get_tip_of_local_branch(&branch_name)?; 63 let local_branch_tip = git_repo.get_tip_of_branch(&branch_name)?;
64 64
65 let (main_branch_name, master_tip) = git_repo.get_main_or_master_branch()?; 65 let (main_branch_name, master_tip) = git_repo.get_main_or_master_branch()?;
66 66
diff --git a/src/sub_commands/push.rs b/src/sub_commands/push.rs
index fdaab8e..651b250 100644
--- a/src/sub_commands/push.rs
+++ b/src/sub_commands/push.rs
@@ -75,7 +75,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
75 let most_recent_proposal_patch_chain = get_most_recent_patch_with_ancestors(commit_events) 75 let most_recent_proposal_patch_chain = get_most_recent_patch_with_ancestors(commit_events)
76 .context("cannot get most recent patch for proposal")?; 76 .context("cannot get most recent patch for proposal")?;
77 77
78 let branch_tip = git_repo.get_tip_of_local_branch(&branch_name)?; 78 let branch_tip = git_repo.get_tip_of_branch(&branch_name)?;
79 79
80 let most_recent_patch_commit_id = str_to_sha1( 80 let most_recent_patch_commit_id = str_to_sha1(
81 &get_commit_id_from_patch( 81 &get_commit_id_from_patch(
diff --git a/src/sub_commands/send.rs b/src/sub_commands/send.rs
index 9b44cc3..81cecd8 100644
--- a/src/sub_commands/send.rs
+++ b/src/sub_commands/send.rs
@@ -53,13 +53,13 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
53 println!("creating proposal revision for: {id}"); 53 println!("creating proposal revision for: {id}");
54 } 54 }
55 55
56 let (main_branch_name, main_tip) = git_repo
57 .get_main_or_master_branch()
58 .context("the default branches (main or master) do not exist")?;
59
56 let mut commits: Vec<Sha1Hash> = { 60 let mut commits: Vec<Sha1Hash> = {
57 if args.since_or_range.is_empty() { 61 if args.since_or_range.is_empty() {
58 let branch_name = git_repo.get_checked_out_branch_name()?; 62 let branch_name = git_repo.get_checked_out_branch_name()?;
59 let (main_branch_name, main_tip) = git_repo
60 .get_main_or_master_branch()
61 .context("the default branches (main or master) do not exist")?;
62
63 let proposed_commits = if branch_name.eq(main_branch_name) { 63 let proposed_commits = if branch_name.eq(main_branch_name) {
64 vec![main_tip] 64 vec![main_tip]
65 } else { 65 } else {
@@ -88,9 +88,6 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
88 ); 88 );
89 } 89 }
90 90
91 let (main_branch_name, main_tip) = git_repo
92 .get_main_or_master_branch()
93 .context("the default branches (main or master) do not exist")?;
94 let (first_commit_ahead, behind) = 91 let (first_commit_ahead, behind) =
95 git_repo.get_commits_ahead_behind(&main_tip, commits.last().context("no commits")?)?; 92 git_repo.get_commits_ahead_behind(&main_tip, commits.last().context("no commits")?)?;
96 93
@@ -385,7 +382,7 @@ fn choose_commits(git_repo: &Repo, proposed_commits: Vec<Sha1Hash>) -> Result<Ve
385 proposed_commits 382 proposed_commits
386 }; 383 };
387 384
388 let tip_of_head = git_repo.get_tip_of_local_branch(&git_repo.get_checked_out_branch_name()?)?; 385 let tip_of_head = git_repo.get_tip_of_branch(&git_repo.get_checked_out_branch_name()?)?;
389 let most_recent_commit = proposed_commits.first().unwrap_or(&tip_of_head); 386 let most_recent_commit = proposed_commits.first().unwrap_or(&tip_of_head);
390 387
391 let mut last_15_commits = vec![*most_recent_commit]; 388 let mut last_15_commits = vec![*most_recent_commit];
@@ -571,7 +568,11 @@ pub fn generate_cover_letter_and_patch_events(
571 // a change like this, or the removal of this tag will require the actual branch name to be tracked 568 // a change like this, or the removal of this tag will require the actual branch name to be tracked
572 // so pulling and pushing still work 569 // so pulling and pushing still work
573 if let Ok(branch_name) = git_repo.get_checked_out_branch_name() { 570 if let Ok(branch_name) = git_repo.get_checked_out_branch_name() {
574 if !branch_name.eq("main") && !branch_name.eq("master") { 571 if !branch_name.eq("main")
572 && !branch_name.eq("master")
573 && !branch_name.eq("origin/main")
574 && !branch_name.eq("origin/master")
575 {
575 vec![Tag::Generic( 576 vec![Tag::Generic(
576 TagKind::Custom("branch-name".to_string()), 577 TagKind::Custom("branch-name".to_string()),
577 vec![branch_name], 578 vec![branch_name],
@@ -608,7 +609,11 @@ pub fn generate_cover_letter_and_patch_events(
608 }, 609 },
609 if events.is_empty() { 610 if events.is_empty() {
610 if let Ok(branch_name) = git_repo.get_checked_out_branch_name() { 611 if let Ok(branch_name) = git_repo.get_checked_out_branch_name() {
611 if !branch_name.eq("main") && !branch_name.eq("master") { 612 if !branch_name.eq("main")
613 && !branch_name.eq("master")
614 && !branch_name.eq("origin/main")
615 && !branch_name.eq("origin/master")
616 {
612 Some(branch_name) 617 Some(branch_name)
613 } else { 618 } else {
614 None 619 None
@@ -915,7 +920,7 @@ fn identify_ahead_behind(
915 Some(name) => ( 920 Some(name) => (
916 name.to_string(), 921 name.to_string(),
917 git_repo 922 git_repo
918 .get_tip_of_local_branch(name) 923 .get_tip_of_branch(name)
919 .context(format!("cannot find from_branch '{name}'"))?, 924 .context(format!("cannot find from_branch '{name}'"))?,
920 ), 925 ),
921 None => ( 926 None => (
@@ -937,7 +942,7 @@ fn identify_ahead_behind(
937 Some(name) => ( 942 Some(name) => (
938 name.to_string(), 943 name.to_string(),
939 git_repo 944 git_repo
940 .get_tip_of_local_branch(name) 945 .get_tip_of_branch(name)
941 .context(format!("cannot find to_branch '{name}'"))?, 946 .context(format!("cannot find to_branch '{name}'"))?,
942 ), 947 ),
943 None => { 948 None => {