upleb.uk

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

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2024-07-19 21:20:53 +0100
committerDanConwayDev <DanConwayDev@protonmail.com>2024-07-19 21:20:53 +0100
commit8531328558c7f5870be3571f63a952743eb0b9e6 (patch)
treef72b57d2a6e571181d21a55fb03aca70d899cec3
parentfca1d193a46eba17255b5372adffac2396e48c04 (diff)
feat: integrate `fetch` into `push`
as part of a project to use `fetch` and the stored cache everywhere
-rw-r--r--src/main.rs2
-rw-r--r--src/sub_commands/push.rs98
-rw-r--r--src/sub_commands/send.rs6
-rw-r--r--tests/push.rs35
4 files changed, 44 insertions, 97 deletions
diff --git a/src/main.rs b/src/main.rs
index 1790c21..81eaf2f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -62,7 +62,7 @@ async fn main() -> Result<()> {
62 Commands::Fetch(args) => sub_commands::fetch::launch(&cli, args).await, 62 Commands::Fetch(args) => sub_commands::fetch::launch(&cli, args).await,
63 Commands::Login(args) => sub_commands::login::launch(&cli, args).await, 63 Commands::Login(args) => sub_commands::login::launch(&cli, args).await,
64 Commands::Init(args) => sub_commands::init::launch(&cli, args).await, 64 Commands::Init(args) => sub_commands::init::launch(&cli, args).await,
65 Commands::Send(args) => sub_commands::send::launch(&cli, args).await, 65 Commands::Send(args) => sub_commands::send::launch(&cli, args, false).await,
66 Commands::List => sub_commands::list::launch().await, 66 Commands::List => sub_commands::list::launch().await,
67 Commands::Pull => sub_commands::pull::launch().await, 67 Commands::Pull => sub_commands::pull::launch().await,
68 Commands::Push(args) => sub_commands::push::launch(&cli, args).await, 68 Commands::Push(args) => sub_commands::push::launch(&cli, args).await,
diff --git a/src/sub_commands/push.rs b/src/sub_commands/push.rs
index 9e3e041..111a14a 100644
--- a/src/sub_commands/push.rs
+++ b/src/sub_commands/push.rs
@@ -1,25 +1,22 @@
1use anyhow::{bail, Context, Result}; 1use anyhow::{bail, Context, Result};
2use nostr_sdk::hashes::sha1::Hash as Sha1Hash;
3 2
4#[cfg(not(test))] 3#[cfg(not(test))]
5use crate::client::Client; 4use crate::client::Client;
6#[cfg(test)] 5#[cfg(test)]
7use crate::client::MockConnect; 6use crate::client::MockConnect;
8use crate::{ 7use crate::{
9 client::Connect, 8 client::{fetching_with_report, get_repo_ref_from_cache, Connect},
10 git::{str_to_sha1, Repo, RepoActions}, 9 git::{str_to_sha1, Repo, RepoActions},
11 login, 10 login,
12 repo_ref::{self, RepoRef}, 11 repo_ref::get_repo_coordinates,
13 sub_commands::{ 12 sub_commands::{
14 self, 13 self,
15 list::{ 14 list::{
16 find_commits_for_proposal_root_events, find_proposal_and_status_events, 15 get_all_proposal_patch_events_from_cache, get_commit_id_from_patch,
17 get_commit_id_from_patch, get_most_recent_patch_with_ancestors, tag_value, 16 get_most_recent_patch_with_ancestors, get_proposals_and_revisions_from_cache,
18 }, 17 tag_value,
19 send::{
20 event_is_revision_root, event_to_cover_letter, generate_patch_event, send_events,
21 PATCH_KIND,
22 }, 18 },
19 send::{event_to_cover_letter, generate_patch_event, send_events},
23 }, 20 },
24 Cli, 21 Cli,
25}; 22};
@@ -37,6 +34,7 @@ pub struct SubCommandArgs {
37#[allow(clippy::too_many_lines)] 34#[allow(clippy::too_many_lines)]
38pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { 35pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
39 let git_repo = Repo::discover().context("cannot find a git repository")?; 36 let git_repo = Repo::discover().context("cannot find a git repository")?;
37 let git_repo_path = git_repo.get_path()?;
40 38
41 let (main_or_master_branch_name, _) = git_repo 39 let (main_or_master_branch_name, _) = git_repo
42 .get_main_or_master_branch() 40 .get_main_or_master_branch()
@@ -58,20 +56,24 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
58 #[cfg(test)] 56 #[cfg(test)]
59 let mut client = <MockConnect as std::default::Default>::default(); 57 let mut client = <MockConnect as std::default::Default>::default();
60 58
61 let repo_ref = repo_ref::fetch( 59 let repo_coordinates = get_repo_coordinates(&git_repo, &client).await?;
62 &git_repo,
63 root_commit.to_string(),
64 &client,
65 client.get_fallback_relays().clone(),
66 true,
67 )
68 .await?;
69 60
70 let (proposal_root_event, commit_events) = fetch_proposal_root_and_most_recent_patch_chain( 61 fetching_with_report(git_repo_path, &client, &repo_coordinates).await?;
71 &client, 62
63 let repo_ref = get_repo_ref_from_cache(git_repo_path, &repo_coordinates).await?;
64
65 let proposal_root_event =
66 get_proposals_and_revisions_from_cache(git_repo_path, repo_ref.coordinates())
67 .await?
68 .iter()
69 .find(|e| event_to_cover_letter(e).is_ok_and(|cl| cl.branch_name.eq(&branch_name)))
70 .context("cannot find proposal that matches the current branch name")?
71 .clone();
72
73 let commit_events = get_all_proposal_patch_events_from_cache(
74 git_repo_path,
72 &repo_ref, 75 &repo_ref,
73 &root_commit, 76 &proposal_root_event.id(),
74 &branch_name,
75 ) 77 )
76 .await?; 78 .await?;
77 79
@@ -116,6 +118,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
116 description: None, 118 description: None,
117 no_cover_letter: args.no_cover_letter, 119 no_cover_letter: args.no_cover_letter,
118 }, 120 },
121 true,
119 ) 122 )
120 .await?; 123 .await?;
121 println!("force pushed proposal revision"); 124 println!("force pushed proposal revision");
@@ -199,56 +202,3 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
199 202
200 Ok(()) 203 Ok(())
201} 204}
202
203pub async fn fetch_proposal_root_and_most_recent_patch_chain(
204 #[cfg(test)] client: &crate::client::MockConnect,
205 #[cfg(not(test))] client: &Client,
206 repo_ref: &RepoRef,
207 root_commit: &Sha1Hash,
208 branch_name: &String,
209) -> Result<(nostr::Event, Vec<nostr::Event>)> {
210 println!("finding proposal root event...");
211
212 let proposal_events_and_revisions: Vec<nostr::Event> =
213 find_proposal_and_status_events(client, repo_ref, &root_commit.to_string())
214 .await
215 .context("cannot get proposal events for repo")?;
216
217 let proposal_events: Vec<&nostr::Event> = proposal_events_and_revisions
218 .iter()
219 .filter(|e| !event_is_revision_root(e) && e.kind().as_u16().eq(&PATCH_KIND))
220 .collect::<Vec<&nostr::Event>>();
221
222 let proposal_root_event: &nostr::Event = proposal_events
223 .iter()
224 .find(|e| {
225 event_to_cover_letter(e).is_ok_and(|cl| cl.branch_name.eq(branch_name))
226 // TODO remove the dependancy on same branch name and replace with
227 // references stored in .git/ngit
228 })
229 .context("cannot find a proposal root event associated with the checked out branch name")?
230 .to_owned();
231
232 println!("found proposal root event. finding commits...");
233
234 let commits_events: Vec<nostr::Event> = find_commits_for_proposal_root_events(
235 client,
236 &[
237 vec![proposal_root_event],
238 proposal_events_and_revisions
239 .iter()
240 .filter(|e| {
241 e.tags.iter().any(|t| {
242 t.as_vec().len().gt(&1)
243 && t.as_vec()[1].eq(&proposal_root_event.id.to_string())
244 })
245 })
246 .collect::<Vec<&nostr::Event>>(),
247 ]
248 .concat(),
249 repo_ref,
250 )
251 .await?;
252
253 Ok((proposal_root_event.clone(), commits_events))
254}
diff --git a/src/sub_commands/send.rs b/src/sub_commands/send.rs
index d093cb6..f94eed3 100644
--- a/src/sub_commands/send.rs
+++ b/src/sub_commands/send.rs
@@ -53,7 +53,7 @@ pub struct SubCommandArgs {
53} 53}
54 54
55#[allow(clippy::too_many_lines)] 55#[allow(clippy::too_many_lines)]
56pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { 56pub async fn launch(cli_args: &Cli, args: &SubCommandArgs, no_fetch: bool) -> Result<()> {
57 let git_repo = Repo::discover().context("cannot find a git repository")?; 57 let git_repo = Repo::discover().context("cannot find a git repository")?;
58 let git_repo_path = git_repo.get_path()?; 58 let git_repo_path = git_repo.get_path()?;
59 59
@@ -68,7 +68,9 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
68 68
69 let repo_coordinates = get_repo_coordinates(&git_repo, &client).await?; 69 let repo_coordinates = get_repo_coordinates(&git_repo, &client).await?;
70 70
71 fetching_with_report(git_repo_path, &client, &repo_coordinates).await?; 71 if !no_fetch {
72 fetching_with_report(git_repo_path, &client, &repo_coordinates).await?;
73 }
72 74
73 let (root_proposal_id, mention_tags) = 75 let (root_proposal_id, mention_tags) =
74 get_root_proposal_id_and_mentions_from_in_reply_to(git_repo.get_path()?, &args.in_reply_to) 76 get_root_proposal_id_and_mentions_from_in_reply_to(git_repo.get_path()?, &args.in_reply_to)
diff --git a/tests/push.rs b/tests/push.rs
index 65c92e9..1f09d28 100644
--- a/tests/push.rs
+++ b/tests/push.rs
@@ -143,13 +143,11 @@ mod when_proposal_isnt_associated_with_branch_name {
143 test_repo.checkout("random-name")?; 143 test_repo.checkout("random-name")?;
144 144
145 let mut p = CliTester::new_from_dir(&test_repo.dir, ["push"]); 145 let mut p = CliTester::new_from_dir(&test_repo.dir, ["push"]);
146 p.expect("finding proposal root event...\r\n")?; 146 p.expect("fetching updates...\r\n")?;
147 p.expect( 147 p.expect_eventually("\r\n")?; // some updates listed here
148 "Error: cannot find a proposal root event associated with the checked out branch name\r\n", 148 p.expect_end_with(
149 "Error: cannot find proposal that matches the current branch name\r\n",
149 )?; 150 )?;
150
151 p.expect_end()?;
152
153 for p in [51, 52, 53, 55, 56] { 151 for p in [51, 52, 53, 55, 56] {
154 relay::shutdown_relay(8000 + p)?; 152 relay::shutdown_relay(8000 + p)?;
155 } 153 }
@@ -206,10 +204,9 @@ mod when_branch_is_checked_out {
206 create_and_populate_branch(&test_repo, FEATURE_BRANCH_NAME_1, "a", false)?; 204 create_and_populate_branch(&test_repo, FEATURE_BRANCH_NAME_1, "a", false)?;
207 205
208 let mut p = CliTester::new_from_dir(&test_repo.dir, ["push"]); 206 let mut p = CliTester::new_from_dir(&test_repo.dir, ["push"]);
209 p.expect("finding proposal root event...\r\n")?; 207 p.expect("fetching updates...\r\n")?;
210 p.expect("found proposal root event. finding commits...\r\n")?; 208 p.expect_eventually("\r\n")?; // some updates listed here
211 p.expect("Error: proposal already up-to-date with local branch\r\n")?; 209 p.expect_end_with("Error: proposal already up-to-date with local branch\r\n")?;
212 p.expect_end()?;
213 210
214 for p in [51, 52, 53, 55, 56] { 211 for p in [51, 52, 53, 55, 56] {
215 relay::shutdown_relay(8000 + p)?; 212 relay::shutdown_relay(8000 + p)?;
@@ -265,8 +262,8 @@ mod when_branch_is_checked_out {
265 create_and_populate_branch(&test_repo, FEATURE_BRANCH_NAME_1, "a", true)?; 262 create_and_populate_branch(&test_repo, FEATURE_BRANCH_NAME_1, "a", true)?;
266 263
267 let mut p = CliTester::new_from_dir(&test_repo.dir, ["push"]); 264 let mut p = CliTester::new_from_dir(&test_repo.dir, ["push"]);
268 p.expect("finding proposal root event...\r\n")?; 265 p.expect("fetching updates...\r\n")?;
269 p.expect("found proposal root event. finding commits...\r\n")?; 266 p.expect_eventually("\r\n")?; // some updates listed here
270 p.expect("Error: proposal is ahead of local branch\r\n")?; 267 p.expect("Error: proposal is ahead of local branch\r\n")?;
271 p.expect_end()?; 268 p.expect_end()?;
272 269
@@ -341,12 +338,11 @@ mod when_branch_is_checked_out {
341 "push", 338 "push",
342 ], 339 ],
343 ); 340 );
344 p.expect("finding proposal root event...\r\n")?; 341 p.expect("fetching updates...\r\n")?;
345 p.expect("found proposal root event. finding commits...\r\n")?; 342 p.expect_eventually("\r\n")?; // some updates listed here
346 p.expect( 343 p.expect(
347 "1 commits ahead. preparing to create creating patch events.\r\n", 344 "1 commits ahead. preparing to create creating patch events.\r\n",
348 )?; 345 )?;
349 p.expect("searching for profile...\r\n")?;
350 p.expect("logged in as fred\r\n")?; 346 p.expect("logged in as fred\r\n")?;
351 p.expect("pushing 1 commits\r\n")?; 347 p.expect("pushing 1 commits\r\n")?;
352 348
@@ -497,8 +493,8 @@ mod when_branch_is_checked_out {
497 let mut p = CliTester::new_from_dir(&test_repo.dir, ["push"]); 493 let mut p = CliTester::new_from_dir(&test_repo.dir, ["push"]);
498 // p.expect_end_eventually_and_print()?; 494 // p.expect_end_eventually_and_print()?;
499 495
500 p.expect("finding proposal root event...\r\n")?; 496 p.expect("fetching updates...\r\n")?;
501 p.expect("found proposal root event. finding commits...\r\n")?; 497 p.expect_eventually("\r\n")?; // some updates listed here
502 p.expect("Error: local unpublished proposal has been rebased. consider force pushing\r\n")?; 498 p.expect("Error: local unpublished proposal has been rebased. consider force pushing\r\n")?;
503 p.expect_end()?; 499 p.expect_end()?;
504 500
@@ -568,8 +564,8 @@ mod when_branch_is_checked_out {
568 "--no-cover-letter", 564 "--no-cover-letter",
569 ], 565 ],
570 ); 566 );
571 p.expect("finding proposal root event...\r\n")?; 567 p.expect("fetching updates...\r\n")?;
572 p.expect("found proposal root event. finding commits...\r\n")?; 568 p.expect_eventually("\r\n")?; // some updates listed here
573 p.expect("preparing to force push proposal revision...\r\n")?; 569 p.expect("preparing to force push proposal revision...\r\n")?;
574 // standard output from `ngit send` 570 // standard output from `ngit send`
575 p.expect("creating proposal revision for: ")?; 571 p.expect("creating proposal revision for: ")?;
@@ -591,7 +587,6 @@ mod when_branch_is_checked_out {
591 p.expect("creating proposal from 2 commits:\r\n")?; 587 p.expect("creating proposal from 2 commits:\r\n")?;
592 p.expect("355bdf1 add a4.md\r\n")?; 588 p.expect("355bdf1 add a4.md\r\n")?;
593 p.expect("dbd1115 add a3.md\r\n")?; 589 p.expect("dbd1115 add a3.md\r\n")?;
594 p.expect("searching for profile...\r\n")?;
595 p.expect("logged in as fred\r\n")?; 590 p.expect("logged in as fred\r\n")?;
596 p.expect("posting 2 patches without a covering letter...\r\n")?; 591 p.expect("posting 2 patches without a covering letter...\r\n")?;
597 592