upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/sub_commands
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2023-12-07 09:57:43 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2023-12-07 09:57:43 +0000
commit82bf53ac3c18e15b75852a48b2e5b432c75a5c7f (patch)
tree8f7ffb8d3ad11462fe87196ae61ad32446becedc /src/sub_commands
parentf811835ca768d6cbcef24f2873c43b51e63578ce (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')
-rw-r--r--src/sub_commands/mod.rs1
-rw-r--r--src/sub_commands/pull.rs114
2 files changed, 115 insertions, 0 deletions
diff --git a/src/sub_commands/mod.rs b/src/sub_commands/mod.rs
index 6e99ca5..12a7f0f 100644
--- a/src/sub_commands/mod.rs
+++ b/src/sub_commands/mod.rs
@@ -1,3 +1,4 @@
1pub mod claim; 1pub mod claim;
2pub mod login; 2pub mod login;
3pub mod prs; 3pub mod prs;
4pub mod pull;
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 @@
1use anyhow::{bail, Context, Result};
2
3#[cfg(not(test))]
4use crate::client::Client;
5#[cfg(test)]
6use crate::client::MockConnect;
7use 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
17pub 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}