diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2024-07-19 21:20:53 +0100 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2024-07-19 21:20:53 +0100 |
| commit | 8531328558c7f5870be3571f63a952743eb0b9e6 (patch) | |
| tree | f72b57d2a6e571181d21a55fb03aca70d899cec3 | |
| parent | fca1d193a46eba17255b5372adffac2396e48c04 (diff) | |
feat: integrate `fetch` into `push`
as part of a project to use `fetch` and the stored cache everywhere
| -rw-r--r-- | src/main.rs | 2 | ||||
| -rw-r--r-- | src/sub_commands/push.rs | 98 | ||||
| -rw-r--r-- | src/sub_commands/send.rs | 6 | ||||
| -rw-r--r-- | tests/push.rs | 35 |
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 @@ | |||
| 1 | use anyhow::{bail, Context, Result}; | 1 | use anyhow::{bail, Context, Result}; |
| 2 | use nostr_sdk::hashes::sha1::Hash as Sha1Hash; | ||
| 3 | 2 | ||
| 4 | #[cfg(not(test))] | 3 | #[cfg(not(test))] |
| 5 | use crate::client::Client; | 4 | use crate::client::Client; |
| 6 | #[cfg(test)] | 5 | #[cfg(test)] |
| 7 | use crate::client::MockConnect; | 6 | use crate::client::MockConnect; |
| 8 | use crate::{ | 7 | use 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)] |
| 38 | pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { | 35 | pub 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 | |||
| 203 | pub 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)] |
| 56 | pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { | 56 | pub 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 | ||