From b6407944cc8f670d33b828f7b77836ceeed2fcfa Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Thu, 22 May 2025 17:37:54 +0100 Subject: feat(init): add blossom add a blossom tag to the repo announcement --- src/bin/ngit/sub_commands/init.rs | 66 +++++++++++++++++++++++++++++++++++++-- src/lib/repo_ref.rs | 20 +++++++++++- 2 files changed, 83 insertions(+), 3 deletions(-) diff --git a/src/bin/ngit/sub_commands/init.rs b/src/bin/ngit/sub_commands/init.rs index 83e434f..4f82d5e 100644 --- a/src/bin/ngit/sub_commands/init.rs +++ b/src/bin/ngit/sub_commands/init.rs @@ -48,6 +48,9 @@ pub struct SubCommandArgs { /// relays contributors push patches and comments to relays: Vec, #[clap(short, long, value_parser, num_args = 1..)] + /// blossom servers + blossoms: Vec, + #[clap(short, long, value_parser, num_args = 1..)] /// npubs of other maintainers other_maintainers: Vec, #[clap(long)] @@ -222,6 +225,24 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { }; + let mut blossoms_defaults = if args.blossoms.is_empty() { + if let Some(repo_ref) = &repo_ref { + repo_ref + .blossoms + .iter() + .map(std::string::ToString::to_string) + .collect::>() + // } else if user_ref.blossoms.read().is_empty() { + // client.get_fallback_relays().clone() + } else { + vec![] + // user_ref.relays.read().clone() + } + } else { + args.blossoms.clone() + }; + + let selected_ngit_relays = if has_server_and_relay_flags { // ignore so a script running `ngit init` can contiue without prompts vec![] @@ -261,13 +282,18 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { git_server_defaults.push(clone_url); } } - if args.clone_url.is_empty() { + if args.relays.is_empty() { let relay_url = format_ngit_relay_url_as_relay_url(ngit_relay)?; if !relay_defaults.contains(&relay_url) { relay_defaults.push(relay_url); } } - // TODO blossom + if args.blossoms.is_empty() { + let blossom = format_ngit_blossom_url_as_relay_url(ngit_relay)?; + if !blossoms_defaults.contains(&blossom) { + blossoms_defaults.push(blossom); + } + } } let no_state = if let Ok(Some(s)) = git_repo.get_git_config_item("nostr.nostate", None) { @@ -416,6 +442,33 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { } }; + let blossoms: Vec = { + if simple_mode || has_server_and_relay_flags { + blossoms_defaults + .iter().filter_map(|b| Url::parse(b).ok()).collect() + } else { + let selections: Vec = vec![true; blossoms_defaults.len()]; + if args.blossoms.is_empty() { + let selected = multi_select_with_custom_value( + "blossom servers", + "blossom server", + blossoms_defaults, + selections, + |s| { + Url::parse(s) + .map(|_| s.to_string()) + .context(format!("Invalid blossom URL format: {s}")) + }, + )?; + show_multi_input_prompt_success("nostr relays", &selected); + selected.iter().filter_map(|b| Url::parse(b).ok()).collect() + } else { + blossoms_defaults.iter().filter_map(|b| Url::parse(b).ok()).collect() + } + } + }; + + let default_maintainers = { let mut maintainers = vec![user_ref.public_key]; if args.other_maintainers.is_empty() { @@ -593,6 +646,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { git_server, web, relays: relays.clone(), + blossoms, trusted_maintainer: user_ref.public_key, maintainers: maintainers.clone(), events: HashMap::new(), @@ -875,6 +929,14 @@ fn format_ngit_relay_url_as_relay_url(url:&str) -> Result { Ok(format!("wss://{ngit_relay_url}")) } +fn format_ngit_blossom_url_as_relay_url(url:&str) -> Result { + let ngit_relay_url = normalize_ngit_relay_url(url)?; + if ngit_relay_url.contains("http://") { + return Ok(ngit_relay_url.to_string()) + } + Ok(format!("https://{ngit_relay_url}")) +} + fn extract_npub(s: &str) -> Result<&str> { // Find the starting index of "npub1" if let Some(start) = s.find("npub1") { diff --git a/src/lib/repo_ref.rs b/src/lib/repo_ref.rs index d37d7a9..1a0fe85 100644 --- a/src/lib/repo_ref.rs +++ b/src/lib/repo_ref.rs @@ -12,7 +12,7 @@ use nostr::{ FromBech32, PublicKey, Tag, TagStandard, ToBech32, nips::{nip01::Coordinate, nip19::Nip19Coordinate}, }; -use nostr_sdk::{Kind, NostrSigner, RelayUrl, Timestamp}; +use nostr_sdk::{Kind, NostrSigner, RelayUrl, Timestamp, Url}; use serde::{Deserialize, Serialize}; #[cfg(not(test))] @@ -38,6 +38,7 @@ pub struct RepoRef { pub git_server: Vec, pub web: Vec, pub relays: Vec, + pub blossoms: Vec, pub maintainers: Vec, pub trusted_maintainer: PublicKey, pub events: HashMap, @@ -61,6 +62,7 @@ impl TryFrom<(nostr::Event, Option)> for RepoRef { git_server: Vec::new(), web: Vec::new(), relays: Vec::new(), + blossoms: Vec::new(), maintainers: Vec::new(), trusted_maintainer: trusted_maintainer.unwrap_or(event.pubkey), events: HashMap::new(), @@ -100,6 +102,13 @@ impl TryFrom<(nostr::Event, Option)> for RepoRef { } } } + [t, blossoms @ ..] if t == "blossoms" => { + for b in blossoms { + if let Ok(b) = Url::parse(b) { + r.blossoms.push(b); + } + } + } [t, maintainers @ ..] if t == "maintainers" => { if !maintainers.contains(&event.pubkey.to_string()) { r.maintainers.push(event.pubkey); @@ -190,6 +199,14 @@ impl RepoRef { vec![format!("git repository: {}", self.name.clone())], ), ], + if self.blossoms.is_empty() { + vec![] + } else { + vec![Tag::custom( + nostr::TagKind::Custom(std::borrow::Cow::Borrowed("blossoms")), + self.blossoms.iter().map(|r| r.to_string()), + )] + }, // code languages and hashtags ] .concat(), @@ -566,6 +583,7 @@ mod tests { RelayUrl::parse("ws://relay1.io").unwrap(), RelayUrl::parse("ws://relay2.io").unwrap(), ], + blossoms: vec![], trusted_maintainer: TEST_KEY_1_KEYS.public_key(), maintainers: vec![TEST_KEY_1_KEYS.public_key(), TEST_KEY_2_KEYS.public_key()], events: HashMap::new(), -- cgit v1.2.3