diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2023-12-07 09:57:43 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2023-12-07 09:57:43 +0000 |
| commit | 82bf53ac3c18e15b75852a48b2e5b432c75a5c7f (patch) | |
| tree | 8f7ffb8d3ad11462fe87196ae61ad32446becedc /src/sub_commands/pull.rs | |
| parent | f811835ca768d6cbcef24f2873c43b51e63578ce (diff) | |
feat(pull) pull commits for checked out pr branch
- find pr event which matches branch name
- fetch and apply latest commits
Diffstat (limited to 'src/sub_commands/pull.rs')
| -rw-r--r-- | src/sub_commands/pull.rs | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/src/sub_commands/pull.rs b/src/sub_commands/pull.rs new file mode 100644 index 0000000..a6513e8 --- /dev/null +++ b/src/sub_commands/pull.rs | |||
| @@ -0,0 +1,114 @@ | |||
| 1 | use anyhow::{bail, Context, Result}; | ||
| 2 | |||
| 3 | #[cfg(not(test))] | ||
| 4 | use crate::client::Client; | ||
| 5 | #[cfg(test)] | ||
| 6 | use crate::client::MockConnect; | ||
| 7 | use crate::{ | ||
| 8 | client::Connect, | ||
| 9 | git::{Repo, RepoActions}, | ||
| 10 | repo_ref, | ||
| 11 | sub_commands::prs::{ | ||
| 12 | create::{PATCH_KIND, PR_KIND}, | ||
| 13 | list::{get_most_recent_patch_with_ancestors, tag_value}, | ||
| 14 | }, | ||
| 15 | }; | ||
| 16 | |||
| 17 | pub async fn launch() -> Result<()> { | ||
| 18 | let git_repo = Repo::discover().context("cannot find a git repository")?; | ||
| 19 | |||
| 20 | let (main_or_master_branch_name, _) = git_repo | ||
| 21 | .get_main_or_master_branch() | ||
| 22 | .context("no main or master branch")?; | ||
| 23 | |||
| 24 | let root_commit = git_repo | ||
| 25 | .get_root_commit(main_or_master_branch_name) | ||
| 26 | .context("failed to get root commit of the repository")?; | ||
| 27 | |||
| 28 | let branch_name = git_repo | ||
| 29 | .get_checked_out_branch_name() | ||
| 30 | .context("cannot get checked out branch name")?; | ||
| 31 | |||
| 32 | if branch_name == main_or_master_branch_name { | ||
| 33 | bail!("checkout a branch associated with a PR first") | ||
| 34 | } | ||
| 35 | #[cfg(not(test))] | ||
| 36 | let client = Client::default(); | ||
| 37 | #[cfg(test)] | ||
| 38 | let client = <MockConnect as std::default::Default>::default(); | ||
| 39 | |||
| 40 | let repo_ref = repo_ref::fetch( | ||
| 41 | root_commit.to_string(), | ||
| 42 | &client, | ||
| 43 | client.get_more_fallback_relays().clone(), | ||
| 44 | ) | ||
| 45 | .await?; | ||
| 46 | |||
| 47 | println!("finding PR event..."); | ||
| 48 | |||
| 49 | let pr_event: nostr::Event = client | ||
| 50 | .get_events( | ||
| 51 | repo_ref.relays.clone(), | ||
| 52 | vec![ | ||
| 53 | nostr::Filter::default() | ||
| 54 | .kind(nostr::Kind::Custom(PR_KIND)) | ||
| 55 | .reference(format!("r-{root_commit}")), | ||
| 56 | ], | ||
| 57 | ) | ||
| 58 | .await? | ||
| 59 | .iter() | ||
| 60 | .find(|e| { | ||
| 61 | e.kind.as_u64() == PR_KIND | ||
| 62 | && e.tags | ||
| 63 | .iter() | ||
| 64 | .any(|t| t.as_vec().len() > 1 && t.as_vec()[1].eq(&format!("r-{root_commit}"))) | ||
| 65 | && tag_value(e, "branch-name") | ||
| 66 | .unwrap_or_default() | ||
| 67 | .eq(&branch_name) | ||
| 68 | }) | ||
| 69 | .context("cannot find a PR event associated with the checked out branch name")? | ||
| 70 | .to_owned(); | ||
| 71 | |||
| 72 | println!("found PR event. finding commits..."); | ||
| 73 | |||
| 74 | let commits_events: Vec<nostr::Event> = client | ||
| 75 | .get_events( | ||
| 76 | repo_ref.relays.clone(), | ||
| 77 | vec![ | ||
| 78 | nostr::Filter::default() | ||
| 79 | .kind(nostr::Kind::Custom(PATCH_KIND)) | ||
| 80 | .event(pr_event.id) | ||
| 81 | .reference(format!("r-{root_commit}")), | ||
| 82 | ], | ||
| 83 | ) | ||
| 84 | .await? | ||
| 85 | .iter() | ||
| 86 | .filter(|e| { | ||
| 87 | e.kind.as_u64() == PATCH_KIND | ||
| 88 | && e.tags | ||
| 89 | .iter() | ||
| 90 | .any(|t| t.as_vec().len() > 2 && t.as_vec()[1].eq(&pr_event.id.to_string())) | ||
| 91 | && e.tags | ||
| 92 | .iter() | ||
| 93 | .any(|t| t.as_vec().len() > 1 && t.as_vec()[1].eq(&format!("r-{root_commit}"))) | ||
| 94 | }) | ||
| 95 | .map(std::borrow::ToOwned::to_owned) | ||
| 96 | .collect(); | ||
| 97 | |||
| 98 | // TODO: are there outstanding changes to prevent checking out a new branch? | ||
| 99 | |||
| 100 | let most_recent_pr_patch_chain = get_most_recent_patch_with_ancestors(commits_events) | ||
| 101 | .context("cannot get most recent patch for PR")?; | ||
| 102 | |||
| 103 | let applied = git_repo | ||
| 104 | .apply_patch_chain(&branch_name, most_recent_pr_patch_chain) | ||
| 105 | .context("cannot apply patch chain")?; | ||
| 106 | |||
| 107 | if applied.is_empty() { | ||
| 108 | println!("branch already up-to-date"); | ||
| 109 | } else { | ||
| 110 | println!("applied {} new commits", applied.len(),); | ||
| 111 | } | ||
| 112 | |||
| 113 | Ok(()) | ||
| 114 | } | ||