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>2024-02-16 22:31:29 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2024-02-16 22:31:29 +0000
commit701668b02d999af42f51d8bd25fffb2a8692c3c8 (patch)
tree7defd0e7e711d743c8464994c2223a7a332ccf2a /src/sub_commands
parent61ffbf2008c0aaaee3d19ac027d63bca823dc8c9 (diff)
refactor: rename PR to proposal
PR is a problematic term when it ambiguous whether the set of patches are PR-like or email-patch like.
Diffstat (limited to 'src/sub_commands')
-rw-r--r--src/sub_commands/list.rs54
-rw-r--r--src/sub_commands/pull.rs21
-rw-r--r--src/sub_commands/push.rs59
-rw-r--r--src/sub_commands/send.rs4
4 files changed, 75 insertions, 63 deletions
diff --git a/src/sub_commands/list.rs b/src/sub_commands/list.rs
index 4764adc..b8c2919 100644
--- a/src/sub_commands/list.rs
+++ b/src/sub_commands/list.rs
@@ -46,21 +46,21 @@ pub async fn launch(_cli_args: &Cli, _args: &SubCommandArgs) -> Result<()> {
46 ) 46 )
47 .await?; 47 .await?;
48 48
49 println!("finding PRs..."); 49 println!("finding proposals...");
50 50
51 let pr_events: Vec<nostr::Event> = 51 let proposal_events: Vec<nostr::Event> =
52 find_pr_events(&client, &repo_ref, &root_commit.to_string()).await?; 52 find_proposal_events(&client, &repo_ref, &root_commit.to_string()).await?;
53 53
54 if pr_events.is_empty() { 54 if proposal_events.is_empty() {
55 println!("no PRs found... create one? try `ngit send`"); 55 println!("no proposals found... create one? try `ngit send`");
56 return Ok(()); 56 return Ok(());
57 } 57 }
58 58
59 let selected_index = Interactor::default().choice( 59 let selected_index = Interactor::default().choice(
60 PromptChoiceParms::default() 60 PromptChoiceParms::default()
61 .with_prompt("All PRs") 61 .with_prompt("all proposals")
62 .with_choices( 62 .with_choices(
63 pr_events 63 proposal_events
64 .iter() 64 .iter()
65 .map(|e| { 65 .map(|e| {
66 if let Ok(cl) = event_to_cover_letter(e) { 66 if let Ok(cl) = event_to_cover_letter(e) {
@@ -78,26 +78,27 @@ pub async fn launch(_cli_args: &Cli, _args: &SubCommandArgs) -> Result<()> {
78 println!("finding commits..."); 78 println!("finding commits...");
79 79
80 let commits_events: Vec<nostr::Event> = 80 let commits_events: Vec<nostr::Event> =
81 find_commits_for_pr_event(&client, &pr_events[selected_index], &repo_ref).await?; 81 find_commits_for_proposal_root_event(&client, &proposal_events[selected_index], &repo_ref)
82 .await?;
82 83
83 confirm_checkout(&git_repo)?; 84 confirm_checkout(&git_repo)?;
84 85
85 let most_recent_pr_patch_chain = get_most_recent_patch_with_ancestors(commits_events) 86 let most_recent_proposal_patch_chain = get_most_recent_patch_with_ancestors(commits_events)
86 .context("cannot get most recent patch for PR")?; 87 .context("cannot get most recent patch for proposal")?;
87 88
88 let branch_name: String = event_to_cover_letter(&pr_events[selected_index]) 89 let branch_name: String = event_to_cover_letter(&proposal_events[selected_index])
89 .context("cannot assign a branch name as event is not a patch set root")? 90 .context("cannot assign a branch name as event is not a patch set root")?
90 .branch_name; 91 .branch_name;
91 92
92 let applied = git_repo 93 let applied = git_repo
93 .apply_patch_chain(&branch_name, most_recent_pr_patch_chain) 94 .apply_patch_chain(&branch_name, most_recent_proposal_patch_chain)
94 .context("cannot apply patch chain")?; 95 .context("cannot apply patch chain")?;
95 96
96 if applied.is_empty() { 97 if applied.is_empty() {
97 println!("checked out PR branch. no new commits to pull"); 98 println!("checked out proposal branch. no new commits to pull");
98 } else { 99 } else {
99 println!( 100 println!(
100 "checked out PR branch. pulled {} new commits", 101 "checked out proposal branch. pulled {} new commits",
101 applied.len(), 102 applied.len(),
102 ); 103 );
103 } 104 }
@@ -115,7 +116,7 @@ fn confirm_checkout(git_repo: &Repo) -> Result<()> {
115 116
116 if git_repo.has_outstanding_changes()? { 117 if git_repo.has_outstanding_changes()? {
117 bail!( 118 bail!(
118 "cannot pull PR branch when repository is not clean. discard or stash (un)staged changes and try again." 119 "cannot pull proposal branch when repository is not clean. discard or stash (un)staged changes and try again."
119 ); 120 );
120 } 121 }
121 Ok(()) 122 Ok(())
@@ -201,7 +202,7 @@ pub fn get_most_recent_patch_with_ancestors(
201 Ok(res) 202 Ok(res)
202} 203}
203 204
204pub async fn find_pr_events( 205pub async fn find_proposal_events(
205 #[cfg(test)] client: &crate::client::MockConnect, 206 #[cfg(test)] client: &crate::client::MockConnect,
206 #[cfg(not(test))] client: &Client, 207 #[cfg(not(test))] client: &Client,
207 repo_ref: &RepoRef, 208 repo_ref: &RepoRef,
@@ -221,7 +222,8 @@ pub async fn find_pr_events(
221 .iter() 222 .iter()
222 .map(|m| format!("{REPO_REF_KIND}:{m}:{}", repo_ref.identifier)), 223 .map(|m| format!("{REPO_REF_KIND}:{m}:{}", repo_ref.identifier)),
223 ), 224 ),
224 // also pick up prs from the same repo but no target at our maintainers repo events 225 // also pick up proposals from the same repo but no target at our maintainers repo
226 // events
225 nostr::Filter::default() 227 nostr::Filter::default()
226 .kind(nostr::Kind::Custom(PATCH_KIND)) 228 .kind(nostr::Kind::Custom(PATCH_KIND))
227 .custom_tag(nostr::Alphabet::T, vec!["root"]) 229 .custom_tag(nostr::Alphabet::T, vec!["root"])
@@ -229,7 +231,7 @@ pub async fn find_pr_events(
229 ], 231 ],
230 ) 232 )
231 .await 233 .await
232 .context("cannot get pr events")? 234 .context("cannot get proposal events")?
233 .iter() 235 .iter()
234 .filter(|e| { 236 .filter(|e| {
235 event_is_patch_set_root(e) 237 event_is_patch_set_root(e)
@@ -250,10 +252,10 @@ pub async fn find_pr_events(
250 .collect::<Vec<nostr::Event>>()) 252 .collect::<Vec<nostr::Event>>())
251} 253}
252 254
253pub async fn find_commits_for_pr_event( 255pub async fn find_commits_for_proposal_root_event(
254 #[cfg(test)] client: &crate::client::MockConnect, 256 #[cfg(test)] client: &crate::client::MockConnect,
255 #[cfg(not(test))] client: &Client, 257 #[cfg(not(test))] client: &Client,
256 pr_event: &nostr::Event, 258 proposal_root_event: &nostr::Event,
257 repo_ref: &RepoRef, 259 repo_ref: &RepoRef,
258) -> Result<Vec<nostr::Event>> { 260) -> Result<Vec<nostr::Event>> {
259 let mut patch_events: Vec<nostr::Event> = client 261 let mut patch_events: Vec<nostr::Event> = client
@@ -265,7 +267,7 @@ pub async fn find_commits_for_pr_event(
265 // this requires every patch to reference the root event 267 // this requires every patch to reference the root event
266 // this will not pick up v2,v3 patch sets 268 // this will not pick up v2,v3 patch sets
267 // TODO: fetch commits for v2.. patch sets 269 // TODO: fetch commits for v2.. patch sets
268 .event(pr_event.id), 270 .event(proposal_root_event.id),
269 ], 271 ],
270 ) 272 )
271 .await 273 .await
@@ -273,15 +275,15 @@ pub async fn find_commits_for_pr_event(
273 .iter() 275 .iter()
274 .filter(|e| { 276 .filter(|e| {
275 e.kind.as_u64() == PATCH_KIND 277 e.kind.as_u64() == PATCH_KIND
276 && e.tags 278 && e.tags.iter().any(|t| {
277 .iter() 279 t.as_vec().len() > 2 && t.as_vec()[1].eq(&proposal_root_event.id.to_string())
278 .any(|t| t.as_vec().len() > 2 && t.as_vec()[1].eq(&pr_event.id.to_string())) 280 })
279 }) 281 })
280 .map(std::borrow::ToOwned::to_owned) 282 .map(std::borrow::ToOwned::to_owned)
281 .collect(); 283 .collect();
282 284
283 if !event_is_cover_letter(pr_event) { 285 if !event_is_cover_letter(proposal_root_event) {
284 patch_events.push(pr_event.clone()); 286 patch_events.push(proposal_root_event.clone());
285 } 287 }
286 Ok(patch_events) 288 Ok(patch_events)
287} 289}
diff --git a/src/sub_commands/pull.rs b/src/sub_commands/pull.rs
index fc6db37..de078e3 100644
--- a/src/sub_commands/pull.rs
+++ b/src/sub_commands/pull.rs
@@ -9,7 +9,8 @@ use crate::{
9 git::{Repo, RepoActions}, 9 git::{Repo, RepoActions},
10 repo_ref, 10 repo_ref,
11 sub_commands::{ 11 sub_commands::{
12 list::get_most_recent_patch_with_ancestors, push::fetch_pr_and_most_recent_patch_chain, 12 list::get_most_recent_patch_with_ancestors,
13 push::fetch_proposal_root_and_most_recent_patch_chain,
13 }, 14 },
14}; 15};
15 16
@@ -29,7 +30,7 @@ pub async fn launch() -> Result<()> {
29 .context("cannot get checked out branch name")?; 30 .context("cannot get checked out branch name")?;
30 31
31 if branch_name == main_or_master_branch_name { 32 if branch_name == main_or_master_branch_name {
32 bail!("checkout a branch associated with a PR first") 33 bail!("checkout a branch associated with a proposal first")
33 } 34 }
34 #[cfg(not(test))] 35 #[cfg(not(test))]
35 let client = Client::default(); 36 let client = Client::default();
@@ -44,19 +45,23 @@ pub async fn launch() -> Result<()> {
44 ) 45 )
45 .await?; 46 .await?;
46 47
47 let (_pr_event, commit_events) = 48 let (_proposal_root_event, commit_events) = fetch_proposal_root_and_most_recent_patch_chain(
48 fetch_pr_and_most_recent_patch_chain(&client, &repo_ref, &root_commit, &branch_name) 49 &client,
49 .await?; 50 &repo_ref,
51 &root_commit,
52 &branch_name,
53 )
54 .await?;
50 55
51 if git_repo.has_outstanding_changes()? { 56 if git_repo.has_outstanding_changes()? {
52 bail!("cannot pull changes when repository is not clean. discard changes and try again."); 57 bail!("cannot pull changes when repository is not clean. discard changes and try again.");
53 } 58 }
54 59
55 let most_recent_pr_patch_chain = get_most_recent_patch_with_ancestors(commit_events) 60 let most_recent_proposal_patch_chain = get_most_recent_patch_with_ancestors(commit_events)
56 .context("cannot get most recent patch for PR")?; 61 .context("cannot get most recent patch for proposal")?;
57 62
58 let applied = git_repo 63 let applied = git_repo
59 .apply_patch_chain(&branch_name, most_recent_pr_patch_chain) 64 .apply_patch_chain(&branch_name, most_recent_proposal_patch_chain)
60 .context("cannot apply patch chain")?; 65 .context("cannot apply patch chain")?;
61 66
62 if applied.is_empty() { 67 if applied.is_empty() {
diff --git a/src/sub_commands/push.rs b/src/sub_commands/push.rs
index 7c6b95b..0fdd56f 100644
--- a/src/sub_commands/push.rs
+++ b/src/sub_commands/push.rs
@@ -12,7 +12,7 @@ use crate::{
12 repo_ref::{self, RepoRef}, 12 repo_ref::{self, RepoRef},
13 sub_commands::{ 13 sub_commands::{
14 list::{ 14 list::{
15 find_commits_for_pr_event, find_pr_events, get_commit_id_from_patch, 15 find_commits_for_proposal_root_event, find_proposal_events, get_commit_id_from_patch,
16 get_most_recent_patch_with_ancestors, tag_value, 16 get_most_recent_patch_with_ancestors, tag_value,
17 }, 17 },
18 send::{event_to_cover_letter, generate_patch_event, send_events}, 18 send::{event_to_cover_letter, generate_patch_event, send_events},
@@ -36,7 +36,7 @@ pub async fn launch(cli_args: &Cli) -> Result<()> {
36 .context("cannot get checked out branch name")?; 36 .context("cannot get checked out branch name")?;
37 37
38 if branch_name == main_or_master_branch_name { 38 if branch_name == main_or_master_branch_name {
39 bail!("checkout a branch associated with a PR first") 39 bail!("checkout a branch associated with a proposal first")
40 } 40 }
41 #[cfg(not(test))] 41 #[cfg(not(test))]
42 let mut client = Client::default(); 42 let mut client = Client::default();
@@ -51,44 +51,48 @@ pub async fn launch(cli_args: &Cli) -> Result<()> {
51 ) 51 )
52 .await?; 52 .await?;
53 53
54 let (pr_event, commit_events) = 54 let (proposal_root_event, commit_events) = fetch_proposal_root_and_most_recent_patch_chain(
55 fetch_pr_and_most_recent_patch_chain(&client, &repo_ref, &root_commit, &branch_name) 55 &client,
56 .await?; 56 &repo_ref,
57 &root_commit,
58 &branch_name,
59 )
60 .await?;
57 61
58 // TODO: fix these scenarios: 62 // TODO: fix these scenarios:
59 // - local PR branch is 2 behind and 1 ahead. intructions: ... 63 // - local proposal branch is 2 behind and 1 ahead. intructions: ...
60 // - PR has been rebased. (against commit in main) instructions: ... 64 // - proposal has been rebased. (against commit in main) instructions: ...
61 // - PR has been rebased. (against commit not in repo) instructions: .. 65 // - proposal has been rebased. (against commit not in repo) instructions: ..
62 66
63 let most_recent_pr_patch_chain = get_most_recent_patch_with_ancestors(commit_events) 67 let most_recent_proposal_patch_chain = get_most_recent_patch_with_ancestors(commit_events)
64 .context("cannot get most recent patch for PR")?; 68 .context("cannot get most recent patch for proposal")?;
65 69
66 let branch_tip = git_repo.get_tip_of_local_branch(&branch_name)?; 70 let branch_tip = git_repo.get_tip_of_local_branch(&branch_name)?;
67 71
68 let most_recent_patch_commit_id = str_to_sha1( 72 let most_recent_patch_commit_id = str_to_sha1(
69 &get_commit_id_from_patch(&most_recent_pr_patch_chain[0]) 73 &get_commit_id_from_patch(&most_recent_proposal_patch_chain[0])
70 .context("latest patch event doesnt have a commit tag")?, 74 .context("latest patch event doesnt have a commit tag")?,
71 ) 75 )
72 .context("latest patch event commit tag isn't a valid SHA1 hash")?; 76 .context("latest patch event commit tag isn't a valid SHA1 hash")?;
73 77
74 if most_recent_patch_commit_id.eq(&branch_tip) { 78 if most_recent_patch_commit_id.eq(&branch_tip) {
75 bail!("nostr pr already up-to-date with local branch"); 79 bail!("nostr proposal already up-to-date with local branch");
76 } 80 }
77 81
78 if most_recent_pr_patch_chain.iter().any(|e| { 82 if most_recent_proposal_patch_chain.iter().any(|e| {
79 let c = tag_value(e, "parent-commit").unwrap_or_default(); 83 let c = tag_value(e, "parent-commit").unwrap_or_default();
80 c.eq(&branch_tip.to_string()) 84 c.eq(&branch_tip.to_string())
81 }) { 85 }) {
82 bail!("nostr pr is ahead of local branch"); 86 bail!("nostr proposal is ahead of local branch");
83 } 87 }
84 88
85 let (ahead, behind) = git_repo 89 let (ahead, behind) = git_repo
86 .get_commits_ahead_behind(&most_recent_patch_commit_id, &branch_tip) 90 .get_commits_ahead_behind(&most_recent_patch_commit_id, &branch_tip)
87 .context("the latest patch in pr doesnt share an ancestor with your branch.")?; 91 .context("the latest patch in proposal doesnt share an ancestor with your branch.")?;
88 92
89 if !behind.is_empty() { 93 if !behind.is_empty() {
90 bail!( 94 bail!(
91 "your local pr branch is {} behind patches on nostr. consider rebasing or force pushing", 95 "your local proposal branch is {} behind patches on nostr. consider rebasing or force pushing",
92 behind.len() 96 behind.len()
93 ) 97 )
94 } 98 }
@@ -109,7 +113,7 @@ pub async fn launch(cli_args: &Cli) -> Result<()> {
109 &git_repo, 113 &git_repo,
110 &root_commit, 114 &root_commit,
111 commit, 115 commit,
112 Some(pr_event.id), 116 Some(proposal_root_event.id),
113 &keys, 117 &keys,
114 &repo_ref, 118 &repo_ref,
115 patch_events.last().map(nostr::Event::id), 119 patch_events.last().map(nostr::Event::id),
@@ -135,33 +139,34 @@ pub async fn launch(cli_args: &Cli) -> Result<()> {
135 Ok(()) 139 Ok(())
136} 140}
137 141
138pub async fn fetch_pr_and_most_recent_patch_chain( 142pub async fn fetch_proposal_root_and_most_recent_patch_chain(
139 #[cfg(test)] client: &crate::client::MockConnect, 143 #[cfg(test)] client: &crate::client::MockConnect,
140 #[cfg(not(test))] client: &Client, 144 #[cfg(not(test))] client: &Client,
141 repo_ref: &RepoRef, 145 repo_ref: &RepoRef,
142 root_commit: &Sha1Hash, 146 root_commit: &Sha1Hash,
143 branch_name: &String, 147 branch_name: &String,
144) -> Result<(nostr::Event, Vec<nostr::Event>)> { 148) -> Result<(nostr::Event, Vec<nostr::Event>)> {
145 println!("finding PR event..."); 149 println!("finding proposal root event...");
146 150
147 let pr_events: Vec<nostr::Event> = find_pr_events(client, repo_ref, &root_commit.to_string()) 151 let proposal_events: Vec<nostr::Event> =
148 .await 152 find_proposal_events(client, repo_ref, &root_commit.to_string())
149 .context("cannot get pr events for repo")?; 153 .await
154 .context("cannot get proposal events for repo")?;
150 155
151 let pr_event: nostr::Event = pr_events 156 let proposal_root_event: nostr::Event = proposal_events
152 .iter() 157 .iter()
153 .find(|e| { 158 .find(|e| {
154 event_to_cover_letter(e).is_ok_and(|cl| cl.branch_name.eq(branch_name)) 159 event_to_cover_letter(e).is_ok_and(|cl| cl.branch_name.eq(branch_name))
155 // TODO remove the dependancy on same branch name and replace with 160 // TODO remove the dependancy on same branch name and replace with
156 // references stored in .git/ngit 161 // references stored in .git/ngit
157 }) 162 })
158 .context("cannot find a PR event associated with the checked out branch name")? 163 .context("cannot find a proposal root event associated with the checked out branch name")?
159 .to_owned(); 164 .to_owned();
160 165
161 println!("found PR event. finding commits..."); 166 println!("found proposal root event. finding commits...");
162 167
163 let commits_events: Vec<nostr::Event> = 168 let commits_events: Vec<nostr::Event> =
164 find_commits_for_pr_event(client, &pr_event, repo_ref).await?; 169 find_commits_for_proposal_root_event(client, &proposal_root_event, repo_ref).await?;
165 170
166 Ok((pr_event, commits_events)) 171 Ok((proposal_root_event, commits_events))
167} 172}
diff --git a/src/sub_commands/send.rs b/src/sub_commands/send.rs
index b8cb271..3a9da4b 100644
--- a/src/sub_commands/send.rs
+++ b/src/sub_commands/send.rs
@@ -140,7 +140,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
140 // oldest first 140 // oldest first
141 ahead.reverse(); 141 ahead.reverse();
142 142
143 let events = generate_pr_and_patch_events( 143 let events = generate_cover_letter_and_patch_events(
144 cover_letter_title_description.clone(), 144 cover_letter_title_description.clone(),
145 &git_repo, 145 &git_repo,
146 &ahead, 146 &ahead,
@@ -369,7 +369,7 @@ mod tests_unique_and_duplicate {
369 369
370pub static PATCH_KIND: u64 = 1617; 370pub static PATCH_KIND: u64 = 1617;
371 371
372pub fn generate_pr_and_patch_events( 372pub fn generate_cover_letter_and_patch_events(
373 cover_letter_title_description: Option<(String, String)>, 373 cover_letter_title_description: Option<(String, String)>,
374 git_repo: &Repo, 374 git_repo: &Repo,
375 commits: &Vec<Sha1Hash>, 375 commits: &Vec<Sha1Hash>,