diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2024-02-14 16:44:56 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2024-02-14 16:44:56 +0000 |
| commit | 115eca3d69310a58e8357fe091183d0a8e723967 (patch) | |
| tree | 51860d62bdcde1d466d99134a41b767ac24eff52 | |
| parent | a1d67c50c8ebc5395b069e30b60d66e0c7de5a5a (diff) | |
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
| -rw-r--r-- | src/repo_ref.rs | 65 | ||||
| -rw-r--r-- | src/sub_commands/list.rs | 5 | ||||
| -rw-r--r-- | 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 @@ | |||
| 1 | use std::{fs::File, io::BufReader, str::FromStr}; | 1 | use std::{fs::File, io::BufReader, str::FromStr}; |
| 2 | 2 | ||
| 3 | use anyhow::{bail, Context, Result}; | 3 | use anyhow::{bail, Context, Result}; |
| 4 | use nostr::{secp256k1::XOnlyPublicKey, FromBech32, Tag, ToBech32}; | 4 | use nostr::{nips::nip19::Nip19, secp256k1::XOnlyPublicKey, FromBech32, Tag, ToBech32}; |
| 5 | use serde::{Deserialize, Serialize}; | 5 | use serde::{Deserialize, Serialize}; |
| 6 | 6 | ||
| 7 | #[cfg(not(test))] | 7 | #[cfg(not(test))] |
| @@ -9,6 +9,7 @@ use crate::client::Client; | |||
| 9 | #[cfg(test)] | 9 | #[cfg(test)] |
| 10 | use crate::client::MockConnect; | 10 | use crate::client::MockConnect; |
| 11 | use crate::{ | 11 | use crate::{ |
| 12 | cli_interactor::{Interactor, InteractorPrompt, PromptInputParms}, | ||
| 12 | client::Connect, | 13 | client::Connect, |
| 13 | git::{Repo, RepoActions}, | 14 | git::{Repo, RepoActions}, |
| 14 | }; | 15 | }; |
| @@ -168,25 +169,59 @@ pub async fn fetch( | |||
| 168 | relays = repo_config.relays.clone(); | 169 | relays = repo_config.relays.clone(); |
| 169 | } | 170 | } |
| 170 | 171 | ||
| 171 | let events: Vec<nostr::Event> = client.get_events(relays, vec![repo_event_filter]).await?; | 172 | let event = loop { |
| 173 | let events: Vec<nostr::Event> = client | ||
| 174 | .get_events(relays.clone(), vec![repo_event_filter.clone()]) | ||
| 175 | .await?; | ||
| 172 | 176 | ||
| 173 | // TODO: fallback to ask user for nevent - to capture | 177 | // TODO: if maintainers.yaml isn't present, as the user to select from the |
| 178 | // pubkeys they want to use. could use WoT as an indicator as well as the repo | ||
| 179 | // and user name. | ||
| 174 | 180 | ||
| 175 | // TODO: if maintainers.yaml isn't present, as the user to select from the | 181 | // TODO: if maintainers.yaml isn't present, save the selected repo pubkey |
| 176 | // pubkeys they want to use. could use WoT as an indicator as well as the repo | 182 | // somewhere within .git folder for future use and seek to get that next time |
| 177 | // and user name. | 183 | if let Some(event) = events |
| 178 | |||
| 179 | // TODO: if maintainers.yaml isn't present, save the selected repo pubkey | ||
| 180 | // somewhere within .git folder for future use and seek to get that next time | ||
| 181 | |||
| 182 | RepoRef::try_from( | ||
| 183 | events | ||
| 184 | .iter() | 184 | .iter() |
| 185 | .filter(|e| e.kind.as_u64() == REPO_REF_KIND) | 185 | .filter(|e| e.kind.as_u64() == REPO_REF_KIND) |
| 186 | .max_by_key(|e| e.created_at) | 186 | .max_by_key(|e| e.created_at) |
| 187 | .context("cannot find repository reference event")? | 187 | { |
| 188 | .clone(), | 188 | break event.clone(); |
| 189 | ) | 189 | } |
| 190 | println!("cannot find repo event"); | ||
| 191 | loop { | ||
| 192 | let bech32 = Interactor::default() | ||
| 193 | .input(PromptInputParms::default().with_prompt("repository naddr or nevent"))?; | ||
| 194 | if let Ok(nip19) = Nip19::from_bech32(bech32) { | ||
| 195 | repo_event_filter = | ||
| 196 | nostr::Filter::default().kind(nostr::Kind::Custom(REPO_REF_KIND)); | ||
| 197 | match nip19 { | ||
| 198 | Nip19::Coordinate(c) => { | ||
| 199 | repo_event_filter = | ||
| 200 | repo_event_filter.identifier(c.identifier).author(c.pubkey); | ||
| 201 | for r in c.relays { | ||
| 202 | relays.push(r); | ||
| 203 | } | ||
| 204 | } | ||
| 205 | Nip19::Event(n) => { | ||
| 206 | if let Some(author) = n.author { | ||
| 207 | repo_event_filter = repo_event_filter.id(n.event_id).author(author); | ||
| 208 | } | ||
| 209 | for r in n.relays { | ||
| 210 | relays.push(r); | ||
| 211 | } | ||
| 212 | } | ||
| 213 | Nip19::EventId(id) => repo_event_filter = repo_event_filter.id(id), | ||
| 214 | _ => (), | ||
| 215 | } | ||
| 216 | } else { | ||
| 217 | println!("not a valid nevent or naddr"); | ||
| 218 | continue; | ||
| 219 | } | ||
| 220 | break; | ||
| 221 | } | ||
| 222 | }; | ||
| 223 | |||
| 224 | RepoRef::try_from(event.clone()).context("cannot parse event as repo reference") | ||
| 190 | } | 225 | } |
| 191 | 226 | ||
| 192 | #[derive(Serialize, Deserialize, Default, Clone, Debug, PartialEq, Eq)] | 227 | #[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<()> { | |||
| 51 | let pr_events: Vec<nostr::Event> = | 51 | let pr_events: Vec<nostr::Event> = |
| 52 | find_pr_events(&client, &repo_ref, &root_commit.to_string()).await?; | 52 | find_pr_events(&client, &repo_ref, &root_commit.to_string()).await?; |
| 53 | 53 | ||
| 54 | if pr_events.is_empty() { | ||
| 55 | println!("no PRs found... create one? try `ngit send`"); | ||
| 56 | return Ok(()); | ||
| 57 | } | ||
| 58 | |||
| 54 | let selected_index = Interactor::default().choice( | 59 | let selected_index = Interactor::default().choice( |
| 55 | PromptChoiceParms::default() | 60 | PromptChoiceParms::default() |
| 56 | .with_prompt("All PRs") | 61 | .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( | |||
| 103 | Ok(()) | 103 | Ok(()) |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | mod cannot_find_repo_event { | ||
| 107 | use super::*; | ||
| 108 | mod cli_prompts { | ||
| 109 | use nostr::{ | ||
| 110 | nips::{nip01::Coordinate, nip19::Nip19Event}, | ||
| 111 | ToBech32, | ||
| 112 | }; | ||
| 113 | |||
| 114 | use super::*; | ||
| 115 | async fn run_async_repo_event_ref_needed( | ||
| 116 | invalid_input: bool, | ||
| 117 | nevent: bool, | ||
| 118 | naddr: bool, | ||
| 119 | ) -> Result<()> { | ||
| 120 | let (mut r51, mut r52, mut r53, mut r55, mut r56) = ( | ||
| 121 | Relay::new(8051, None, None), | ||
| 122 | Relay::new(8052, None, None), | ||
| 123 | Relay::new(8053, None, None), | ||
| 124 | Relay::new(8055, None, None), | ||
| 125 | Relay::new(8056, None, None), | ||
| 126 | ); | ||
| 127 | |||
| 128 | r51.events.push(generate_test_key_1_relay_list_event()); | ||
| 129 | r51.events.push(generate_test_key_1_metadata_event("fred")); | ||
| 130 | |||
| 131 | r55.events.push(generate_test_key_1_relay_list_event()); | ||
| 132 | r55.events.push(generate_test_key_1_metadata_event("fred")); | ||
| 133 | |||
| 134 | let repo_event = generate_repo_ref_event(); | ||
| 135 | r56.events.push(repo_event.clone()); | ||
| 136 | |||
| 137 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | ||
| 138 | let test_repo = GitTestRepo::default(); | ||
| 139 | test_repo.populate()?; | ||
| 140 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["list"]); | ||
| 141 | |||
| 142 | p.expect("cannot find repo event\r\n")?; | ||
| 143 | |||
| 144 | if invalid_input { | ||
| 145 | let mut input = p.expect_input("repository naddr or nevent")?; | ||
| 146 | input.succeeds_with("dfgvfvfzadvd")?; | ||
| 147 | p.expect("not a valid nevent or naddr\r\n")?; | ||
| 148 | let _ = p.expect_input("repository naddr or nevent")?; | ||
| 149 | p.exit()?; | ||
| 150 | } | ||
| 151 | if nevent { | ||
| 152 | let mut input = p.expect_input("repository naddr or nevent")?; | ||
| 153 | input.succeeds_with( | ||
| 154 | &Nip19Event { | ||
| 155 | event_id: repo_event.id, | ||
| 156 | author: Some(TEST_KEY_1_KEYS.public_key()), | ||
| 157 | relays: vec!["ws://localhost:8056".to_string()], | ||
| 158 | } | ||
| 159 | .to_bech32()?, | ||
| 160 | )?; | ||
| 161 | p.expect("finding PRs...\r\n")?; | ||
| 162 | p.expect_end_with("no PRs found... create one? try `ngit send`\r\n")?; | ||
| 163 | } | ||
| 164 | if naddr { | ||
| 165 | let mut input = p.expect_input("repository naddr or nevent")?; | ||
| 166 | input.succeeds_with( | ||
| 167 | &Coordinate { | ||
| 168 | kind: nostr::Kind::Custom(REPOSITORY_KIND), | ||
| 169 | pubkey: TEST_KEY_1_KEYS.public_key(), | ||
| 170 | identifier: repo_event.identifier().unwrap().to_string(), | ||
| 171 | relays: vec!["ws://localhost:8056".to_string()], | ||
| 172 | } | ||
| 173 | .to_bech32()?, | ||
| 174 | )?; | ||
| 175 | p.expect("finding PRs...\r\n")?; | ||
| 176 | p.expect_end_with("no PRs found... create one? try `ngit send`\r\n")?; | ||
| 177 | p.expect_end_eventually()?; | ||
| 178 | } | ||
| 179 | |||
| 180 | for p in [51, 52, 53, 55, 56] { | ||
| 181 | relay::shutdown_relay(8000 + p)?; | ||
| 182 | } | ||
| 183 | Ok(()) | ||
| 184 | }); | ||
| 185 | |||
| 186 | // launch relay | ||
| 187 | let _ = join!( | ||
| 188 | r51.listen_until_close(), | ||
| 189 | r52.listen_until_close(), | ||
| 190 | r53.listen_until_close(), | ||
| 191 | r55.listen_until_close(), | ||
| 192 | r56.listen_until_close(), | ||
| 193 | ); | ||
| 194 | cli_tester_handle.join().unwrap()?; | ||
| 195 | Ok(()) | ||
| 196 | } | ||
| 197 | |||
| 198 | #[tokio::test] | ||
| 199 | #[serial] | ||
| 200 | async fn warns_not_valid_input_and_asks_again() -> Result<()> { | ||
| 201 | let _ = run_async_repo_event_ref_needed(true, false, false).await; | ||
| 202 | Ok(()) | ||
| 203 | } | ||
| 204 | |||
| 205 | #[tokio::test] | ||
| 206 | #[serial] | ||
| 207 | async fn finds_based_on_nevent_on_embeded_relay() -> Result<()> { | ||
| 208 | let _ = run_async_repo_event_ref_needed(false, true, false).await; | ||
| 209 | Ok(()) | ||
| 210 | } | ||
| 211 | |||
| 212 | #[tokio::test] | ||
| 213 | #[serial] | ||
| 214 | async fn finds_based_on_naddr_on_embeded_relay() -> Result<()> { | ||
| 215 | let _ = run_async_repo_event_ref_needed(false, false, true).await; | ||
| 216 | Ok(()) | ||
| 217 | } | ||
| 218 | } | ||
| 219 | } | ||
| 106 | mod when_main_branch_is_uptodate { | 220 | mod when_main_branch_is_uptodate { |
| 107 | use super::*; | 221 | use super::*; |
| 108 | 222 | ||