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