From 115eca3d69310a58e8357fe091183d0a8e723967 Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Wed, 14 Feb 2024 16:44:56 +0000 Subject: feat: find repo event by nevent or naddr if repo event cannot be found using unique commit the user can find it via a nevent or naddr also handle no PRs found --- src/repo_ref.rs | 65 ++++++++++++++++++++------- src/sub_commands/list.rs | 5 +++ tests/list.rs | 114 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 169 insertions(+), 15 deletions(-) diff --git a/src/repo_ref.rs b/src/repo_ref.rs index 87c5b75..38ea470 100644 --- a/src/repo_ref.rs +++ b/src/repo_ref.rs @@ -1,7 +1,7 @@ use std::{fs::File, io::BufReader, str::FromStr}; use anyhow::{bail, Context, Result}; -use nostr::{secp256k1::XOnlyPublicKey, FromBech32, Tag, ToBech32}; +use nostr::{nips::nip19::Nip19, secp256k1::XOnlyPublicKey, FromBech32, Tag, ToBech32}; use serde::{Deserialize, Serialize}; #[cfg(not(test))] @@ -9,6 +9,7 @@ use crate::client::Client; #[cfg(test)] use crate::client::MockConnect; use crate::{ + cli_interactor::{Interactor, InteractorPrompt, PromptInputParms}, client::Connect, git::{Repo, RepoActions}, }; @@ -168,25 +169,59 @@ pub async fn fetch( relays = repo_config.relays.clone(); } - let events: Vec = client.get_events(relays, vec![repo_event_filter]).await?; + let event = loop { + let events: Vec = client + .get_events(relays.clone(), vec![repo_event_filter.clone()]) + .await?; - // TODO: fallback to ask user for nevent - to capture + // TODO: if maintainers.yaml isn't present, as the user to select from the + // pubkeys they want to use. could use WoT as an indicator as well as the repo + // and user name. - // TODO: if maintainers.yaml isn't present, as the user to select from the - // pubkeys they want to use. could use WoT as an indicator as well as the repo - // and user name. - - // TODO: if maintainers.yaml isn't present, save the selected repo pubkey - // somewhere within .git folder for future use and seek to get that next time - - RepoRef::try_from( - events + // TODO: if maintainers.yaml isn't present, save the selected repo pubkey + // somewhere within .git folder for future use and seek to get that next time + if let Some(event) = events .iter() .filter(|e| e.kind.as_u64() == REPO_REF_KIND) .max_by_key(|e| e.created_at) - .context("cannot find repository reference event")? - .clone(), - ) + { + break event.clone(); + } + println!("cannot find repo event"); + loop { + let bech32 = Interactor::default() + .input(PromptInputParms::default().with_prompt("repository naddr or nevent"))?; + if let Ok(nip19) = Nip19::from_bech32(bech32) { + repo_event_filter = + nostr::Filter::default().kind(nostr::Kind::Custom(REPO_REF_KIND)); + match nip19 { + Nip19::Coordinate(c) => { + repo_event_filter = + repo_event_filter.identifier(c.identifier).author(c.pubkey); + for r in c.relays { + relays.push(r); + } + } + Nip19::Event(n) => { + if let Some(author) = n.author { + repo_event_filter = repo_event_filter.id(n.event_id).author(author); + } + for r in n.relays { + relays.push(r); + } + } + Nip19::EventId(id) => repo_event_filter = repo_event_filter.id(id), + _ => (), + } + } else { + println!("not a valid nevent or naddr"); + continue; + } + break; + } + }; + + RepoRef::try_from(event.clone()).context("cannot parse event as repo reference") } #[derive(Serialize, Deserialize, Default, Clone, Debug, PartialEq, Eq)] diff --git a/src/sub_commands/list.rs b/src/sub_commands/list.rs index 49cbf6d..47a8fdc 100644 --- a/src/sub_commands/list.rs +++ b/src/sub_commands/list.rs @@ -51,6 +51,11 @@ pub async fn launch(_cli_args: &Cli, _args: &SubCommandArgs) -> Result<()> { let pr_events: Vec = find_pr_events(&client, &repo_ref, &root_commit.to_string()).await?; + if pr_events.is_empty() { + println!("no PRs found... create one? try `ngit send`"); + return Ok(()); + } + let selected_index = Interactor::default().choice( PromptChoiceParms::default() .with_prompt("All PRs") diff --git a/tests/list.rs b/tests/list.rs index 0d1d4e9..4337d73 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -103,6 +103,120 @@ fn cli_tester_create_pr( Ok(()) } +mod cannot_find_repo_event { + use super::*; + mod cli_prompts { + use nostr::{ + nips::{nip01::Coordinate, nip19::Nip19Event}, + ToBech32, + }; + + use super::*; + async fn run_async_repo_event_ref_needed( + invalid_input: bool, + nevent: bool, + naddr: bool, + ) -> Result<()> { + let (mut r51, mut r52, mut r53, mut r55, mut r56) = ( + Relay::new(8051, None, None), + Relay::new(8052, None, None), + Relay::new(8053, None, None), + Relay::new(8055, None, None), + Relay::new(8056, None, None), + ); + + r51.events.push(generate_test_key_1_relay_list_event()); + r51.events.push(generate_test_key_1_metadata_event("fred")); + + r55.events.push(generate_test_key_1_relay_list_event()); + r55.events.push(generate_test_key_1_metadata_event("fred")); + + let repo_event = generate_repo_ref_event(); + r56.events.push(repo_event.clone()); + + let cli_tester_handle = std::thread::spawn(move || -> Result<()> { + let test_repo = GitTestRepo::default(); + test_repo.populate()?; + let mut p = CliTester::new_from_dir(&test_repo.dir, ["list"]); + + p.expect("cannot find repo event\r\n")?; + + if invalid_input { + let mut input = p.expect_input("repository naddr or nevent")?; + input.succeeds_with("dfgvfvfzadvd")?; + p.expect("not a valid nevent or naddr\r\n")?; + let _ = p.expect_input("repository naddr or nevent")?; + p.exit()?; + } + if nevent { + let mut input = p.expect_input("repository naddr or nevent")?; + input.succeeds_with( + &Nip19Event { + event_id: repo_event.id, + author: Some(TEST_KEY_1_KEYS.public_key()), + relays: vec!["ws://localhost:8056".to_string()], + } + .to_bech32()?, + )?; + p.expect("finding PRs...\r\n")?; + p.expect_end_with("no PRs found... create one? try `ngit send`\r\n")?; + } + if naddr { + let mut input = p.expect_input("repository naddr or nevent")?; + input.succeeds_with( + &Coordinate { + kind: nostr::Kind::Custom(REPOSITORY_KIND), + pubkey: TEST_KEY_1_KEYS.public_key(), + identifier: repo_event.identifier().unwrap().to_string(), + relays: vec!["ws://localhost:8056".to_string()], + } + .to_bech32()?, + )?; + p.expect("finding PRs...\r\n")?; + p.expect_end_with("no PRs found... create one? try `ngit send`\r\n")?; + p.expect_end_eventually()?; + } + + for p in [51, 52, 53, 55, 56] { + relay::shutdown_relay(8000 + p)?; + } + Ok(()) + }); + + // launch relay + let _ = join!( + r51.listen_until_close(), + r52.listen_until_close(), + r53.listen_until_close(), + r55.listen_until_close(), + r56.listen_until_close(), + ); + cli_tester_handle.join().unwrap()?; + Ok(()) + } + + #[tokio::test] + #[serial] + async fn warns_not_valid_input_and_asks_again() -> Result<()> { + let _ = run_async_repo_event_ref_needed(true, false, false).await; + Ok(()) + } + + #[tokio::test] + #[serial] + async fn finds_based_on_nevent_on_embeded_relay() -> Result<()> { + let _ = run_async_repo_event_ref_needed(false, true, false).await; + Ok(()) + } + + #[tokio::test] + #[serial] + async fn finds_based_on_naddr_on_embeded_relay() -> Result<()> { + let _ = run_async_repo_event_ref_needed(false, false, true).await; + Ok(()) + } + } +} mod when_main_branch_is_uptodate { use super::*; -- cgit v1.2.3