diff options
| -rw-r--r-- | src/git.rs | 14 | ||||
| -rw-r--r-- | src/sub_commands/prs/list.rs | 23 | ||||
| -rw-r--r-- | tests/prs_list.rs | 23 |
3 files changed, 53 insertions, 7 deletions
| @@ -3,7 +3,7 @@ use std::path::PathBuf; | |||
| 3 | use std::{env::current_dir, path::Path}; | 3 | use std::{env::current_dir, path::Path}; |
| 4 | 4 | ||
| 5 | use anyhow::{bail, Context, Result}; | 5 | use anyhow::{bail, Context, Result}; |
| 6 | use git2::{Oid, Revwalk}; | 6 | use git2::{DiffOptions, Oid, Revwalk}; |
| 7 | use nostr::prelude::{sha1::Hash as Sha1Hash, Hash}; | 7 | use nostr::prelude::{sha1::Hash as Sha1Hash, Hash}; |
| 8 | 8 | ||
| 9 | use crate::sub_commands::prs::list::tag_value; | 9 | use crate::sub_commands::prs::list::tag_value; |
| @@ -52,6 +52,8 @@ pub trait RepoActions { | |||
| 52 | base_commit: &Sha1Hash, | 52 | base_commit: &Sha1Hash, |
| 53 | latest_commit: &Sha1Hash, | 53 | latest_commit: &Sha1Hash, |
| 54 | ) -> Result<(Vec<Sha1Hash>, Vec<Sha1Hash>)>; | 54 | ) -> Result<(Vec<Sha1Hash>, Vec<Sha1Hash>)>; |
| 55 | // including (un)staged changes and (un)tracked files | ||
| 56 | fn has_outstanding_changes(&self) -> Result<bool>; | ||
| 55 | fn make_patch_from_commit(&self, commit: &Sha1Hash) -> Result<String>; | 57 | fn make_patch_from_commit(&self, commit: &Sha1Hash) -> Result<String>; |
| 56 | fn extract_commit_pgp_signature(&self, commit: &Sha1Hash) -> Result<String>; | 58 | fn extract_commit_pgp_signature(&self, commit: &Sha1Hash) -> Result<String>; |
| 57 | fn checkout(&self, ref_name: &str) -> Result<Sha1Hash>; | 59 | fn checkout(&self, ref_name: &str) -> Result<Sha1Hash>; |
| @@ -242,6 +244,16 @@ impl RepoActions for Repo { | |||
| 242 | .to_owned()) | 244 | .to_owned()) |
| 243 | } | 245 | } |
| 244 | 246 | ||
| 247 | // including (un)staged changes and (un)tracked files | ||
| 248 | fn has_outstanding_changes(&self) -> Result<bool> { | ||
| 249 | let diff = self.git_repo.diff_tree_to_workdir_with_index( | ||
| 250 | Some(&self.git_repo.head()?.peel_to_tree()?), | ||
| 251 | Some(DiffOptions::new().include_untracked(true)), | ||
| 252 | )?; | ||
| 253 | |||
| 254 | Ok(diff.deltas().len().gt(&0)) | ||
| 255 | } | ||
| 256 | |||
| 245 | fn get_commits_ahead_behind( | 257 | fn get_commits_ahead_behind( |
| 246 | &self, | 258 | &self, |
| 247 | base_commit: &Sha1Hash, | 259 | base_commit: &Sha1Hash, |
diff --git a/src/sub_commands/prs/list.rs b/src/sub_commands/prs/list.rs index a6aa8b7..f896f5a 100644 --- a/src/sub_commands/prs/list.rs +++ b/src/sub_commands/prs/list.rs | |||
| @@ -1,11 +1,11 @@ | |||
| 1 | use anyhow::{Context, Result}; | 1 | use anyhow::{bail, Context, Result}; |
| 2 | 2 | ||
| 3 | #[cfg(not(test))] | 3 | #[cfg(not(test))] |
| 4 | use crate::client::Client; | 4 | use crate::client::Client; |
| 5 | #[cfg(test)] | 5 | #[cfg(test)] |
| 6 | use crate::client::MockConnect; | 6 | use crate::client::MockConnect; |
| 7 | use crate::{ | 7 | use crate::{ |
| 8 | cli_interactor::{Interactor, InteractorPrompt, PromptChoiceParms}, | 8 | cli_interactor::{Interactor, InteractorPrompt, PromptChoiceParms, PromptConfirmParms}, |
| 9 | client::Connect, | 9 | client::Connect, |
| 10 | git::{Repo, RepoActions}, | 10 | git::{Repo, RepoActions}, |
| 11 | repo_ref, | 11 | repo_ref, |
| @@ -134,7 +134,7 @@ pub async fn launch( | |||
| 134 | .map(std::borrow::ToOwned::to_owned) | 134 | .map(std::borrow::ToOwned::to_owned) |
| 135 | .collect(); | 135 | .collect(); |
| 136 | 136 | ||
| 137 | // TODO: are there outstanding changes to prevent checking out a new branch? | 137 | confirm_checkout(&git_repo)?; |
| 138 | 138 | ||
| 139 | let most_recent_pr_patch_chain = get_most_recent_patch_with_ancestors(commits_events) | 139 | let most_recent_pr_patch_chain = get_most_recent_patch_with_ancestors(commits_events) |
| 140 | .context("cannot get most recent patch for PR")?; | 140 | .context("cannot get most recent patch for PR")?; |
| @@ -192,6 +192,23 @@ pub async fn launch( | |||
| 192 | Ok(()) | 192 | Ok(()) |
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | fn confirm_checkout(git_repo: &Repo) -> Result<()> { | ||
| 196 | if !Interactor::default().confirm( | ||
| 197 | PromptConfirmParms::default() | ||
| 198 | .with_prompt("check out branch?") | ||
| 199 | .with_default(true), | ||
| 200 | )? { | ||
| 201 | bail!("Exiting..."); | ||
| 202 | } | ||
| 203 | |||
| 204 | if git_repo.has_outstanding_changes()? { | ||
| 205 | bail!( | ||
| 206 | "cannot pull PR branch when repository is not clean. discard or stash (un)staged changes and try again." | ||
| 207 | ); | ||
| 208 | } | ||
| 209 | Ok(()) | ||
| 210 | } | ||
| 211 | |||
| 195 | pub fn tag_value(event: &nostr::Event, tag_name: &str) -> Result<String> { | 212 | pub fn tag_value(event: &nostr::Event, tag_name: &str) -> Result<String> { |
| 196 | Ok(event | 213 | Ok(event |
| 197 | .tags | 214 | .tags |
diff --git a/tests/prs_list.rs b/tests/prs_list.rs index 7bc3935..7f753c0 100644 --- a/tests/prs_list.rs +++ b/tests/prs_list.rs | |||
| @@ -141,7 +141,9 @@ mod when_main_branch_is_uptodate { | |||
| 141 | ], | 141 | ], |
| 142 | )?; | 142 | )?; |
| 143 | c.succeeds_with(0, true)?; | 143 | c.succeeds_with(0, true)?; |
| 144 | 144 | let mut confirm = | |
| 145 | p.expect_confirm_eventually("check out branch?", Some(true))?; | ||
| 146 | confirm.succeeds_with(None)?; | ||
| 145 | p.expect_end_eventually_and_print()?; | 147 | p.expect_end_eventually_and_print()?; |
| 146 | 148 | ||
| 147 | for p in [51, 52, 53, 55, 56] { | 149 | for p in [51, 52, 53, 55, 56] { |
| @@ -200,6 +202,8 @@ mod when_main_branch_is_uptodate { | |||
| 200 | )?; | 202 | )?; |
| 201 | c.succeeds_with(0, true)?; | 203 | c.succeeds_with(0, true)?; |
| 202 | p.expect("finding commits...\r\n")?; | 204 | p.expect("finding commits...\r\n")?; |
| 205 | let mut confirm = p.expect_confirm("check out branch?", Some(true))?; | ||
| 206 | confirm.succeeds_with(None)?; | ||
| 203 | p.expect("checked out PR branch. pulled 2 new commits\r\n")?; | 207 | p.expect("checked out PR branch. pulled 2 new commits\r\n")?; |
| 204 | p.expect_end()?; | 208 | p.expect_end()?; |
| 205 | 209 | ||
| @@ -302,7 +306,9 @@ mod when_main_branch_is_uptodate { | |||
| 302 | ], | 306 | ], |
| 303 | )?; | 307 | )?; |
| 304 | c.succeeds_with(2, true)?; | 308 | c.succeeds_with(2, true)?; |
| 305 | 309 | let mut confirm = | |
| 310 | p.expect_confirm_eventually("check out branch?", Some(true))?; | ||
| 311 | confirm.succeeds_with(None)?; | ||
| 306 | p.expect_end_eventually_and_print()?; | 312 | p.expect_end_eventually_and_print()?; |
| 307 | 313 | ||
| 308 | for p in [51, 52, 53, 55, 56] { | 314 | for p in [51, 52, 53, 55, 56] { |
| @@ -361,6 +367,8 @@ mod when_main_branch_is_uptodate { | |||
| 361 | )?; | 367 | )?; |
| 362 | c.succeeds_with(2, true)?; | 368 | c.succeeds_with(2, true)?; |
| 363 | p.expect("finding commits...\r\n")?; | 369 | p.expect("finding commits...\r\n")?; |
| 370 | let mut confirm = p.expect_confirm("check out branch?", Some(true))?; | ||
| 371 | confirm.succeeds_with(None)?; | ||
| 364 | p.expect("checked out PR branch. pulled 2 new commits\r\n")?; | 372 | p.expect("checked out PR branch. pulled 2 new commits\r\n")?; |
| 365 | p.expect_end()?; | 373 | p.expect_end()?; |
| 366 | 374 | ||
| @@ -478,6 +486,9 @@ mod when_main_branch_is_uptodate { | |||
| 478 | ], | 486 | ], |
| 479 | )?; | 487 | )?; |
| 480 | c.succeeds_with(0, true)?; | 488 | c.succeeds_with(0, true)?; |
| 489 | let mut confirm = | ||
| 490 | p.expect_confirm_eventually("check out branch?", Some(true))?; | ||
| 491 | confirm.succeeds_with(None)?; | ||
| 481 | p.expect_end_eventually_and_print()?; | 492 | p.expect_end_eventually_and_print()?; |
| 482 | 493 | ||
| 483 | for p in [51, 52, 53, 55, 56] { | 494 | for p in [51, 52, 53, 55, 56] { |
| @@ -544,6 +555,8 @@ mod when_main_branch_is_uptodate { | |||
| 544 | )?; | 555 | )?; |
| 545 | c.succeeds_with(0, true)?; | 556 | c.succeeds_with(0, true)?; |
| 546 | p.expect("finding commits...\r\n")?; | 557 | p.expect("finding commits...\r\n")?; |
| 558 | let mut confirm = p.expect_confirm("check out branch?", Some(true))?; | ||
| 559 | confirm.succeeds_with(None)?; | ||
| 547 | p.expect("checked out PR branch. no new commits to pull\r\n")?; | 560 | p.expect("checked out PR branch. no new commits to pull\r\n")?; |
| 548 | p.expect_end()?; | 561 | p.expect_end()?; |
| 549 | 562 | ||
| @@ -632,7 +645,9 @@ mod when_main_branch_is_uptodate { | |||
| 632 | ], | 645 | ], |
| 633 | )?; | 646 | )?; |
| 634 | c.succeeds_with(0, true)?; | 647 | c.succeeds_with(0, true)?; |
| 635 | 648 | let mut confirm = | |
| 649 | p.expect_confirm_eventually("check out branch?", Some(true))?; | ||
| 650 | confirm.succeeds_with(None)?; | ||
| 636 | p.expect_end_eventually_and_print()?; | 651 | p.expect_end_eventually_and_print()?; |
| 637 | 652 | ||
| 638 | for p in [51, 52, 53, 55, 56] { | 653 | for p in [51, 52, 53, 55, 56] { |
| @@ -699,6 +714,8 @@ mod when_main_branch_is_uptodate { | |||
| 699 | )?; | 714 | )?; |
| 700 | c.succeeds_with(0, true)?; | 715 | c.succeeds_with(0, true)?; |
| 701 | p.expect("finding commits...\r\n")?; | 716 | p.expect("finding commits...\r\n")?; |
| 717 | let mut confirm = p.expect_confirm("check out branch?", Some(true))?; | ||
| 718 | confirm.succeeds_with(None)?; | ||
| 702 | p.expect("checked out PR branch. pulled 1 new commits\r\n")?; | 719 | p.expect("checked out PR branch. pulled 1 new commits\r\n")?; |
| 703 | p.expect_end()?; | 720 | p.expect_end()?; |
| 704 | 721 | ||