diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/bin/ngit/sub_commands/init.rs | 90 | ||||
| -rw-r--r-- | src/lib/client.rs | 18 | ||||
| -rw-r--r-- | src/lib/git/mod.rs | 4 | ||||
| -rw-r--r-- | src/lib/git/nostr_url.rs | 140 | ||||
| -rw-r--r-- | src/lib/repo_ref.rs | 76 |
5 files changed, 297 insertions, 31 deletions
diff --git a/src/bin/ngit/sub_commands/init.rs b/src/bin/ngit/sub_commands/init.rs index 32af619..ffee9bd 100644 --- a/src/bin/ngit/sub_commands/init.rs +++ b/src/bin/ngit/sub_commands/init.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | use std::collections::HashMap; | 1 | use std::{collections::HashMap, str::FromStr}; |
| 2 | 2 | ||
| 3 | use anyhow::{Context, Result}; | 3 | use anyhow::{Context, Result}; |
| 4 | use ngit::cli_interactor::PromptConfirmParms; | 4 | use ngit::{cli_interactor::PromptConfirmParms, git::nostr_url::NostrUrlDecoded}; |
| 5 | use nostr::{nips::nip01::Coordinate, FromBech32, PublicKey, ToBech32}; | 5 | use nostr::{nips::nip01::Coordinate, FromBech32, PublicKey, ToBech32}; |
| 6 | use nostr_sdk::{Kind, RelayUrl}; | 6 | use nostr_sdk::{Kind, RelayUrl}; |
| 7 | 7 | ||
| @@ -413,6 +413,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { | |||
| 413 | git_server, | 413 | git_server, |
| 414 | web, | 414 | web, |
| 415 | relays: relays.clone(), | 415 | relays: relays.clone(), |
| 416 | trusted_maintainer: user_ref.public_key, | ||
| 416 | maintainers: maintainers.clone(), | 417 | maintainers: maintainers.clone(), |
| 417 | events: HashMap::new(), | 418 | events: HashMap::new(), |
| 418 | }; | 419 | }; |
| @@ -431,6 +432,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { | |||
| 431 | ) | 432 | ) |
| 432 | .await?; | 433 | .await?; |
| 433 | 434 | ||
| 435 | // TODO - does this git config item do more harm than good? | ||
| 434 | git_repo.save_git_config_item( | 436 | git_repo.save_git_config_item( |
| 435 | "nostr.repo", | 437 | "nostr.repo", |
| 436 | &Coordinate { | 438 | &Coordinate { |
| @@ -448,6 +450,11 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { | |||
| 448 | .map(std::string::ToString::to_string) | 450 | .map(std::string::ToString::to_string) |
| 449 | .collect::<Vec<String>>(); | 451 | .collect::<Vec<String>>(); |
| 450 | 452 | ||
| 453 | prompt_to_set_nostr_url_as_origin(&repo_ref, &git_repo)?; | ||
| 454 | |||
| 455 | // TODO: if no state event exists and there is currently a remote called | ||
| 456 | // "origin", automtically push rather than waiting for the next commit | ||
| 457 | |||
| 451 | // no longer create a new maintainers.yaml file - its too confusing for users | 458 | // no longer create a new maintainers.yaml file - its too confusing for users |
| 452 | // as it falls out of sync with data in nostr event . update if it already | 459 | // as it falls out of sync with data in nostr event . update if it already |
| 453 | // exists | 460 | // exists |
| @@ -481,3 +488,82 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { | |||
| 481 | } | 488 | } |
| 482 | Ok(()) | 489 | Ok(()) |
| 483 | } | 490 | } |
| 491 | |||
| 492 | fn prompt_to_set_nostr_url_as_origin(repo_ref: &RepoRef, git_repo: &Repo) -> Result<()> { | ||
| 493 | println!( | ||
| 494 | "starting from your next commit, when you `git push` to a remote that uses your nostr url, it will store your repository state on nostr and update the state of the git server(s) you just listed." | ||
| 495 | ); | ||
| 496 | println!( | ||
| 497 | "in addition, any remote branches beginning with `pr/` are open PRs from contributors. they can submit these by simply pushing a branch with this `pr/` prefix." | ||
| 498 | ); | ||
| 499 | |||
| 500 | if let Ok(origin_remote) = git_repo.git_repo.find_remote("origin") { | ||
| 501 | if let Some(origin_url) = origin_remote.url() { | ||
| 502 | if let Ok(nostr_url) = NostrUrlDecoded::from_str(origin_url) { | ||
| 503 | if let Some(c) = &nostr_url.coordinates.iter().next() { | ||
| 504 | if c.identifier == repo_ref.identifier { | ||
| 505 | if nostr_url | ||
| 506 | .coordinates | ||
| 507 | .iter() | ||
| 508 | .next() | ||
| 509 | .context( | ||
| 510 | "a decoded nostr url will always have at least one coordinate", | ||
| 511 | )? | ||
| 512 | .public_key | ||
| 513 | == repo_ref.trusted_maintainer | ||
| 514 | { | ||
| 515 | return Ok(()); | ||
| 516 | } | ||
| 517 | // origin is set to a different trusted maintainer | ||
| 518 | println!( | ||
| 519 | "warning: currently git remote 'origin' is set to a different trusted maintainer with the same identifier" | ||
| 520 | ); | ||
| 521 | ask_to_set_origin_remote(repo_ref, git_repo)?; | ||
| 522 | } else { | ||
| 523 | // origin is linked to a different identifier | ||
| 524 | println!( | ||
| 525 | "warning: currently git remote 'origin' is set to a different repository identifier" | ||
| 526 | ); | ||
| 527 | ask_to_set_origin_remote(repo_ref, git_repo)?; | ||
| 528 | } | ||
| 529 | } | ||
| 530 | } else { | ||
| 531 | // remote is non-nostr url | ||
| 532 | ask_to_set_origin_remote(repo_ref, git_repo)?; | ||
| 533 | } | ||
| 534 | } else { | ||
| 535 | // no origin remote | ||
| 536 | ask_to_create_new_origin_remote(repo_ref, git_repo)?; | ||
| 537 | } | ||
| 538 | } | ||
| 539 | println!("contributors can clone your repository by installing ngit and using this clone url:"); | ||
| 540 | println!("{}", repo_ref.to_nostr_git_url()); | ||
| 541 | |||
| 542 | Ok(()) | ||
| 543 | } | ||
| 544 | |||
| 545 | fn ask_to_set_origin_remote(repo_ref: &RepoRef, git_repo: &Repo) -> Result<()> { | ||
| 546 | if Interactor::default().confirm( | ||
| 547 | PromptConfirmParms::default() | ||
| 548 | .with_default(true) | ||
| 549 | .with_prompt("set remote \"origin\" to the nostr url of your repository?"), | ||
| 550 | )? { | ||
| 551 | git_repo | ||
| 552 | .git_repo | ||
| 553 | .remote_set_url("origin", &repo_ref.to_nostr_git_url())?; | ||
| 554 | } | ||
| 555 | Ok(()) | ||
| 556 | } | ||
| 557 | |||
| 558 | fn ask_to_create_new_origin_remote(repo_ref: &RepoRef, git_repo: &Repo) -> Result<()> { | ||
| 559 | if Interactor::default().confirm( | ||
| 560 | PromptConfirmParms::default() | ||
| 561 | .with_default(true) | ||
| 562 | .with_prompt("set remote \"origin\" to the nostr url of your repository?"), | ||
| 563 | )? { | ||
| 564 | git_repo | ||
| 565 | .git_repo | ||
| 566 | .remote("origin", &repo_ref.to_nostr_git_url())?; | ||
| 567 | } | ||
| 568 | Ok(()) | ||
| 569 | } | ||
diff --git a/src/lib/client.rs b/src/lib/client.rs index 534eb9e..cd9a75c 100644 --- a/src/lib/client.rs +++ b/src/lib/client.rs | |||
| @@ -832,7 +832,13 @@ pub async fn get_repo_ref_from_cache( | |||
| 832 | ] | 832 | ] |
| 833 | .concat(); | 833 | .concat(); |
| 834 | for e in events { | 834 | for e in events { |
| 835 | if let Ok(repo_ref) = RepoRef::try_from(e.clone()) { | 835 | if let Ok(repo_ref) = RepoRef::try_from(( |
| 836 | e.clone(), | ||
| 837 | repo_coordinates | ||
| 838 | .iter() | ||
| 839 | .next() | ||
| 840 | .map(|coordinate| coordinate.public_key), | ||
| 841 | )) { | ||
| 836 | for m in repo_ref.maintainers { | 842 | for m in repo_ref.maintainers { |
| 837 | if maintainers.insert(m) { | 843 | if maintainers.insert(m) { |
| 838 | new_coordinate = true; | 844 | new_coordinate = true; |
| @@ -846,12 +852,16 @@ pub async fn get_repo_ref_from_cache( | |||
| 846 | } | 852 | } |
| 847 | } | 853 | } |
| 848 | repo_events.sort_by_key(|e| e.created_at); | 854 | repo_events.sort_by_key(|e| e.created_at); |
| 849 | let repo_ref = RepoRef::try_from( | 855 | let repo_ref = RepoRef::try_from(( |
| 850 | repo_events | 856 | repo_events |
| 851 | .first() | 857 | .first() |
| 852 | .context("no repo events at specified coordinates")? | 858 | .context("no repo events at specified coordinates")? |
| 853 | .clone(), | 859 | .clone(), |
| 854 | )?; | 860 | repo_coordinates |
| 861 | .iter() | ||
| 862 | .next() | ||
| 863 | .map(|coordinate| coordinate.public_key), | ||
| 864 | ))?; | ||
| 855 | 865 | ||
| 856 | let mut events: HashMap<Coordinate, nostr::Event> = HashMap::new(); | 866 | let mut events: HashMap<Coordinate, nostr::Event> = HashMap::new(); |
| 857 | for m in &maintainers { | 867 | for m in &maintainers { |
| @@ -1179,7 +1189,7 @@ async fn process_fetched_events( | |||
| 1179 | )); | 1189 | )); |
| 1180 | } | 1190 | } |
| 1181 | // if contains new maintainer | 1191 | // if contains new maintainer |
| 1182 | if let Ok(repo_ref) = &RepoRef::try_from(event.clone()) { | 1192 | if let Ok(repo_ref) = &RepoRef::try_from((event.clone(), None)) { |
| 1183 | for m in &repo_ref.maintainers { | 1193 | for m in &repo_ref.maintainers { |
| 1184 | if !request | 1194 | if !request |
| 1185 | .repo_coordinates_without_relays // prexisting maintainers | 1195 | .repo_coordinates_without_relays // prexisting maintainers |
diff --git a/src/lib/git/mod.rs b/src/lib/git/mod.rs index a49d306..0615213 100644 --- a/src/lib/git/mod.rs +++ b/src/lib/git/mod.rs | |||
| @@ -1716,7 +1716,7 @@ mod tests { | |||
| 1716 | &oid_to_sha1(&original_oid), | 1716 | &oid_to_sha1(&original_oid), |
| 1717 | Some(nostr::EventId::all_zeros()), | 1717 | Some(nostr::EventId::all_zeros()), |
| 1718 | &TEST_KEY_1_SIGNER, | 1718 | &TEST_KEY_1_SIGNER, |
| 1719 | &RepoRef::try_from(generate_repo_ref_event()).unwrap(), | 1719 | &RepoRef::try_from((generate_repo_ref_event(), None)).unwrap(), |
| 1720 | None, | 1720 | None, |
| 1721 | None, | 1721 | None, |
| 1722 | None, | 1722 | None, |
| @@ -1869,7 +1869,7 @@ mod tests { | |||
| 1869 | &git_repo, | 1869 | &git_repo, |
| 1870 | &[oid_to_sha1(&oid1), oid_to_sha1(&oid2), oid_to_sha1(&oid3)], | 1870 | &[oid_to_sha1(&oid1), oid_to_sha1(&oid2), oid_to_sha1(&oid3)], |
| 1871 | &TEST_KEY_1_SIGNER, | 1871 | &TEST_KEY_1_SIGNER, |
| 1872 | &RepoRef::try_from(generate_repo_ref_event()).unwrap(), | 1872 | &RepoRef::try_from((generate_repo_ref_event(), None)).unwrap(), |
| 1873 | &None, | 1873 | &None, |
| 1874 | &[], | 1874 | &[], |
| 1875 | ) | 1875 | ) |
diff --git a/src/lib/git/nostr_url.rs b/src/lib/git/nostr_url.rs index e4b6825..a501765 100644 --- a/src/lib/git/nostr_url.rs +++ b/src/lib/git/nostr_url.rs | |||
| @@ -3,7 +3,7 @@ use std::{collections::HashSet, str::FromStr}; | |||
| 3 | 3 | ||
| 4 | use anyhow::{anyhow, bail, Context, Error, Result}; | 4 | use anyhow::{anyhow, bail, Context, Error, Result}; |
| 5 | use nostr::nips::nip01::Coordinate; | 5 | use nostr::nips::nip01::Coordinate; |
| 6 | use nostr_sdk::{PublicKey, RelayUrl, Url}; | 6 | use nostr_sdk::{PublicKey, RelayUrl, ToBech32, Url}; |
| 7 | 7 | ||
| 8 | #[derive(Debug, PartialEq, Default, Clone)] | 8 | #[derive(Debug, PartialEq, Default, Clone)] |
| 9 | pub enum ServerProtocol { | 9 | pub enum ServerProtocol { |
| @@ -61,6 +61,33 @@ pub struct NostrUrlDecoded { | |||
| 61 | pub user: Option<String>, | 61 | pub user: Option<String>, |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | impl fmt::Display for NostrUrlDecoded { | ||
| 65 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
| 66 | write!(f, "nostr://")?; | ||
| 67 | if let Some(user) = &self.user { | ||
| 68 | write!(f, "{}@", user)?; | ||
| 69 | } | ||
| 70 | if let Some(protocol) = &self.protocol { | ||
| 71 | write!(f, "{}/", protocol)?; | ||
| 72 | } | ||
| 73 | let c = self.coordinates.iter().next().unwrap(); | ||
| 74 | write!(f, "{}/", c.public_key.to_bech32().unwrap())?; | ||
| 75 | if let Some(relay) = c.relays.first() { | ||
| 76 | write!( | ||
| 77 | f, | ||
| 78 | "{}/", | ||
| 79 | urlencoding::encode( | ||
| 80 | relay | ||
| 81 | .as_str_without_trailing_slash() | ||
| 82 | .replace("wss://", "") | ||
| 83 | .as_str() | ||
| 84 | ) | ||
| 85 | )?; | ||
| 86 | } | ||
| 87 | write!(f, "{}", c.identifier) | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 64 | static INCORRECT_NOSTR_URL_FORMAT_ERROR: &str = "incorrect nostr git url format. try nostr://naddr123 or nostr://npub123/my-repo or nostr://ssh/npub123/relay.damus.io/my-repo"; | 91 | static INCORRECT_NOSTR_URL_FORMAT_ERROR: &str = "incorrect nostr git url format. try nostr://naddr123 or nostr://npub123/my-repo or nostr://ssh/npub123/relay.damus.io/my-repo"; |
| 65 | 92 | ||
| 66 | impl std::str::FromStr for NostrUrlDecoded { | 93 | impl std::str::FromStr for NostrUrlDecoded { |
| @@ -837,8 +864,117 @@ mod tests { | |||
| 837 | assert!(result.is_err()); | 864 | assert!(result.is_err()); |
| 838 | } | 865 | } |
| 839 | } | 866 | } |
| 867 | mod nostr_git_url_format { | ||
| 868 | use std::collections::HashSet; | ||
| 869 | |||
| 870 | use nostr::nips::nip01::Coordinate; | ||
| 871 | use nostr_sdk::PublicKey; | ||
| 872 | |||
| 873 | use super::*; | ||
| 874 | use crate::git::nostr_url::NostrUrlDecoded; | ||
| 875 | |||
| 876 | #[test] | ||
| 877 | fn standard() -> Result<()> { | ||
| 878 | assert_eq!( | ||
| 879 | format!( | ||
| 880 | "{}", | ||
| 881 | NostrUrlDecoded { | ||
| 882 | original_string: String::new(), | ||
| 883 | coordinates: HashSet::from_iter(vec![Coordinate { | ||
| 884 | identifier: "ngit".to_string(), | ||
| 885 | public_key: PublicKey::parse( | ||
| 886 | "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", | ||
| 887 | ) | ||
| 888 | .unwrap(), | ||
| 889 | kind: nostr_sdk::Kind::GitRepoAnnouncement, | ||
| 890 | relays: vec![RelayUrl::parse("wss://nos.lol").unwrap()], | ||
| 891 | }]), | ||
| 892 | protocol: None, | ||
| 893 | user: None, | ||
| 894 | } | ||
| 895 | ), | ||
| 896 | "nostr://npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/nos.lol/ngit", | ||
| 897 | ); | ||
| 898 | Ok(()) | ||
| 899 | } | ||
| 900 | |||
| 901 | #[test] | ||
| 902 | fn no_relay() -> Result<()> { | ||
| 903 | assert_eq!( | ||
| 904 | format!( | ||
| 905 | "{}", | ||
| 906 | NostrUrlDecoded { | ||
| 907 | original_string: String::new(), | ||
| 908 | coordinates: HashSet::from_iter(vec![Coordinate { | ||
| 909 | identifier: "ngit".to_string(), | ||
| 910 | public_key: PublicKey::parse( | ||
| 911 | "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", | ||
| 912 | ) | ||
| 913 | .unwrap(), | ||
| 914 | kind: nostr_sdk::Kind::GitRepoAnnouncement, | ||
| 915 | relays: vec![], | ||
| 916 | }]), | ||
| 917 | protocol: None, | ||
| 918 | user: None, | ||
| 919 | } | ||
| 920 | ), | ||
| 921 | "nostr://npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/ngit", | ||
| 922 | ); | ||
| 923 | Ok(()) | ||
| 924 | } | ||
| 925 | |||
| 926 | #[test] | ||
| 927 | fn with_protocol() -> Result<()> { | ||
| 928 | assert_eq!( | ||
| 929 | format!( | ||
| 930 | "{}", | ||
| 931 | NostrUrlDecoded { | ||
| 932 | original_string: String::new(), | ||
| 933 | coordinates: HashSet::from_iter(vec![Coordinate { | ||
| 934 | identifier: "ngit".to_string(), | ||
| 935 | public_key: PublicKey::parse( | ||
| 936 | "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", | ||
| 937 | ) | ||
| 938 | .unwrap(), | ||
| 939 | kind: nostr_sdk::Kind::GitRepoAnnouncement, | ||
| 940 | relays: vec![RelayUrl::parse("wss://nos.lol").unwrap()], | ||
| 941 | }]), | ||
| 942 | protocol: Some(ServerProtocol::Ssh), | ||
| 943 | user: None, | ||
| 944 | } | ||
| 945 | ), | ||
| 946 | "nostr://ssh/npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/nos.lol/ngit", | ||
| 947 | ); | ||
| 948 | Ok(()) | ||
| 949 | } | ||
| 950 | |||
| 951 | #[test] | ||
| 952 | fn with_protocol_and_user() -> Result<()> { | ||
| 953 | assert_eq!( | ||
| 954 | format!( | ||
| 955 | "{}", | ||
| 956 | NostrUrlDecoded { | ||
| 957 | original_string: String::new(), | ||
| 958 | coordinates: HashSet::from_iter(vec![Coordinate { | ||
| 959 | identifier: "ngit".to_string(), | ||
| 960 | public_key: PublicKey::parse( | ||
| 961 | "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", | ||
| 962 | ) | ||
| 963 | .unwrap(), | ||
| 964 | kind: nostr_sdk::Kind::GitRepoAnnouncement, | ||
| 965 | relays: vec![RelayUrl::parse("wss://nos.lol").unwrap()], | ||
| 966 | }]), | ||
| 967 | protocol: Some(ServerProtocol::Ssh), | ||
| 968 | user: Some("bla".to_string()), | ||
| 969 | } | ||
| 970 | ), | ||
| 971 | "nostr://bla@ssh/npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/nos.lol/ngit", | ||
| 972 | ); | ||
| 973 | Ok(()) | ||
| 974 | } | ||
| 975 | } | ||
| 840 | 976 | ||
| 841 | mod nostr_git_url_paramemters_from_str { | 977 | mod nostr_url_decoded_paramemters_from_str { |
| 842 | use std::str::FromStr; | 978 | use std::str::FromStr; |
| 843 | 979 | ||
| 844 | use super::*; | 980 | use super::*; |
diff --git a/src/lib/repo_ref.rs b/src/lib/repo_ref.rs index 2ef4b8c..d566b43 100644 --- a/src/lib/repo_ref.rs +++ b/src/lib/repo_ref.rs | |||
| @@ -20,7 +20,7 @@ use crate::{ | |||
| 20 | git::{nostr_url::NostrUrlDecoded, Repo, RepoActions}, | 20 | git::{nostr_url::NostrUrlDecoded, Repo, RepoActions}, |
| 21 | }; | 21 | }; |
| 22 | 22 | ||
| 23 | #[derive(Default, Clone)] | 23 | #[derive(Clone)] |
| 24 | pub struct RepoRef { | 24 | pub struct RepoRef { |
| 25 | pub name: String, | 25 | pub name: String, |
| 26 | pub description: String, | 26 | pub description: String, |
| @@ -30,18 +30,30 @@ pub struct RepoRef { | |||
| 30 | pub web: Vec<String>, | 30 | pub web: Vec<String>, |
| 31 | pub relays: Vec<RelayUrl>, | 31 | pub relays: Vec<RelayUrl>, |
| 32 | pub maintainers: Vec<PublicKey>, | 32 | pub maintainers: Vec<PublicKey>, |
| 33 | pub trusted_maintainer: PublicKey, | ||
| 33 | pub events: HashMap<Coordinate, nostr::Event>, | 34 | pub events: HashMap<Coordinate, nostr::Event>, |
| 34 | // code languages and hashtags | ||
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | impl TryFrom<nostr::Event> for RepoRef { | 37 | impl TryFrom<(nostr::Event, Option<PublicKey>)> for RepoRef { |
| 38 | type Error = anyhow::Error; | 38 | type Error = anyhow::Error; |
| 39 | 39 | ||
| 40 | fn try_from(event: nostr::Event) -> Result<Self> { | 40 | fn try_from((event, trusted_maintainer): (nostr::Event, Option<PublicKey>)) -> Result<Self> { |
| 41 | if !event.kind.eq(&Kind::GitRepoAnnouncement) { | 41 | if !event.kind.eq(&Kind::GitRepoAnnouncement) { |
| 42 | bail!("incorrect kind"); | 42 | bail!("incorrect kind"); |
| 43 | } | 43 | } |
| 44 | let mut r = Self::default(); | 44 | |
| 45 | let mut r = Self { | ||
| 46 | name: String::new(), | ||
| 47 | description: String::new(), | ||
| 48 | identifier: String::new(), | ||
| 49 | root_commit: String::new(), | ||
| 50 | git_server: Vec::new(), | ||
| 51 | web: Vec::new(), | ||
| 52 | relays: Vec::new(), | ||
| 53 | maintainers: Vec::new(), | ||
| 54 | trusted_maintainer: trusted_maintainer.unwrap_or(event.pubkey), | ||
| 55 | events: HashMap::new(), | ||
| 56 | }; | ||
| 45 | 57 | ||
| 46 | for tag in event.tags.iter() { | 58 | for tag in event.tags.iter() { |
| 47 | match tag.as_slice() { | 59 | match tag.as_slice() { |
| @@ -183,11 +195,7 @@ impl RepoRef { | |||
| 183 | pub fn coordinate_with_hint(&self) -> Coordinate { | 195 | pub fn coordinate_with_hint(&self) -> Coordinate { |
| 184 | Coordinate { | 196 | Coordinate { |
| 185 | kind: Kind::GitRepoAnnouncement, | 197 | kind: Kind::GitRepoAnnouncement, |
| 186 | public_key: *self | 198 | public_key: self.trusted_maintainer, |
| 187 | .maintainers | ||
| 188 | .first() | ||
| 189 | .context("no maintainers in repo ref") | ||
| 190 | .unwrap(), | ||
| 191 | identifier: self.identifier.clone(), | 199 | identifier: self.identifier.clone(), |
| 192 | relays: if let Some(relay) = self.relays.first() { | 200 | relays: if let Some(relay) = self.relays.first() { |
| 193 | vec![relay.clone()] | 201 | vec![relay.clone()] |
| @@ -204,6 +212,18 @@ impl RepoRef { | |||
| 204 | .map(|c| (c.clone(), self.events.get(c).map(|e| e.created_at))) | 212 | .map(|c| (c.clone(), self.events.get(c).map(|e| e.created_at))) |
| 205 | .collect::<Vec<(Coordinate, Option<Timestamp>)>>() | 213 | .collect::<Vec<(Coordinate, Option<Timestamp>)>>() |
| 206 | } | 214 | } |
| 215 | |||
| 216 | pub fn to_nostr_git_url(&self) -> String { | ||
| 217 | format!( | ||
| 218 | "{}", | ||
| 219 | NostrUrlDecoded { | ||
| 220 | original_string: String::new(), | ||
| 221 | coordinates: HashSet::from_iter(vec![self.coordinate_with_hint()]), | ||
| 222 | protocol: None, | ||
| 223 | user: None, | ||
| 224 | } | ||
| 225 | ) | ||
| 226 | } | ||
| 207 | } | 227 | } |
| 208 | 228 | ||
| 209 | pub async fn get_repo_coordinates( | 229 | pub async fn get_repo_coordinates( |
| @@ -469,6 +489,7 @@ mod tests { | |||
| 469 | RelayUrl::parse("ws://relay1.io").unwrap(), | 489 | RelayUrl::parse("ws://relay1.io").unwrap(), |
| 470 | RelayUrl::parse("ws://relay2.io").unwrap(), | 490 | RelayUrl::parse("ws://relay2.io").unwrap(), |
| 471 | ], | 491 | ], |
| 492 | trusted_maintainer: TEST_KEY_1_KEYS.public_key(), | ||
| 472 | maintainers: vec![TEST_KEY_1_KEYS.public_key(), TEST_KEY_2_KEYS.public_key()], | 493 | maintainers: vec![TEST_KEY_1_KEYS.public_key(), TEST_KEY_2_KEYS.public_key()], |
| 473 | events: HashMap::new(), | 494 | events: HashMap::new(), |
| 474 | } | 495 | } |
| @@ -482,20 +503,27 @@ mod tests { | |||
| 482 | #[tokio::test] | 503 | #[tokio::test] |
| 483 | async fn identifier() { | 504 | async fn identifier() { |
| 484 | assert_eq!( | 505 | assert_eq!( |
| 485 | RepoRef::try_from(create().await).unwrap().identifier, | 506 | RepoRef::try_from((create().await, None)) |
| 507 | .unwrap() | ||
| 508 | .identifier, | ||
| 486 | "123412341", | 509 | "123412341", |
| 487 | ) | 510 | ) |
| 488 | } | 511 | } |
| 489 | 512 | ||
| 490 | #[tokio::test] | 513 | #[tokio::test] |
| 491 | async fn name() { | 514 | async fn name() { |
| 492 | assert_eq!(RepoRef::try_from(create().await).unwrap().name, "test name",) | 515 | assert_eq!( |
| 516 | RepoRef::try_from((create().await, None)).unwrap().name, | ||
| 517 | "test name", | ||
| 518 | ) | ||
| 493 | } | 519 | } |
| 494 | 520 | ||
| 495 | #[tokio::test] | 521 | #[tokio::test] |
| 496 | async fn description() { | 522 | async fn description() { |
| 497 | assert_eq!( | 523 | assert_eq!( |
| 498 | RepoRef::try_from(create().await).unwrap().description, | 524 | RepoRef::try_from((create().await, None)) |
| 525 | .unwrap() | ||
| 526 | .description, | ||
| 499 | "test description", | 527 | "test description", |
| 500 | ) | 528 | ) |
| 501 | } | 529 | } |
| @@ -503,7 +531,9 @@ mod tests { | |||
| 503 | #[tokio::test] | 531 | #[tokio::test] |
| 504 | async fn root_commit_is_r_tag() { | 532 | async fn root_commit_is_r_tag() { |
| 505 | assert_eq!( | 533 | assert_eq!( |
| 506 | RepoRef::try_from(create().await).unwrap().root_commit, | 534 | RepoRef::try_from((create().await, None)) |
| 535 | .unwrap() | ||
| 536 | .root_commit, | ||
| 507 | "5e664e5a7845cd1373c79f580ca4fe29ab5b34d2", | 537 | "5e664e5a7845cd1373c79f580ca4fe29ab5b34d2", |
| 508 | ) | 538 | ) |
| 509 | } | 539 | } |
| @@ -526,7 +556,7 @@ mod tests { | |||
| 526 | async fn less_than_40_characters() { | 556 | async fn less_than_40_characters() { |
| 527 | let s = "5e664e5a7845cd1373"; | 557 | let s = "5e664e5a7845cd1373"; |
| 528 | assert_eq!( | 558 | assert_eq!( |
| 529 | RepoRef::try_from(create_with_incorrect_first_commit_ref(s).await) | 559 | RepoRef::try_from((create_with_incorrect_first_commit_ref(s).await, None)) |
| 530 | .unwrap() | 560 | .unwrap() |
| 531 | .root_commit, | 561 | .root_commit, |
| 532 | "", | 562 | "", |
| @@ -537,7 +567,7 @@ mod tests { | |||
| 537 | async fn more_than_40_characters() { | 567 | async fn more_than_40_characters() { |
| 538 | let s = "5e664e5a7845cd1373c79f580ca4fe29ab5b34d2111111111"; | 568 | let s = "5e664e5a7845cd1373c79f580ca4fe29ab5b34d2111111111"; |
| 539 | assert_eq!( | 569 | assert_eq!( |
| 540 | RepoRef::try_from(create_with_incorrect_first_commit_ref(s).await) | 570 | RepoRef::try_from((create_with_incorrect_first_commit_ref(s).await, None)) |
| 541 | .unwrap() | 571 | .unwrap() |
| 542 | .root_commit, | 572 | .root_commit, |
| 543 | "", | 573 | "", |
| @@ -548,7 +578,7 @@ mod tests { | |||
| 548 | async fn not_hex_characters() { | 578 | async fn not_hex_characters() { |
| 549 | let s = "xxx64e5a7845cd1373c79f580ca4fe29ab5b34d2"; | 579 | let s = "xxx64e5a7845cd1373c79f580ca4fe29ab5b34d2"; |
| 550 | assert_eq!( | 580 | assert_eq!( |
| 551 | RepoRef::try_from(create_with_incorrect_first_commit_ref(s).await) | 581 | RepoRef::try_from((create_with_incorrect_first_commit_ref(s).await, None)) |
| 552 | .unwrap() | 582 | .unwrap() |
| 553 | .root_commit, | 583 | .root_commit, |
| 554 | "", | 584 | "", |
| @@ -559,7 +589,9 @@ mod tests { | |||
| 559 | #[tokio::test] | 589 | #[tokio::test] |
| 560 | async fn git_server() { | 590 | async fn git_server() { |
| 561 | assert_eq!( | 591 | assert_eq!( |
| 562 | RepoRef::try_from(create().await).unwrap().git_server, | 592 | RepoRef::try_from((create().await, None)) |
| 593 | .unwrap() | ||
| 594 | .git_server, | ||
| 563 | vec!["https://localhost:1000"], | 595 | vec!["https://localhost:1000"], |
| 564 | ) | 596 | ) |
| 565 | } | 597 | } |
| @@ -567,7 +599,7 @@ mod tests { | |||
| 567 | #[tokio::test] | 599 | #[tokio::test] |
| 568 | async fn web() { | 600 | async fn web() { |
| 569 | assert_eq!( | 601 | assert_eq!( |
| 570 | RepoRef::try_from(create().await).unwrap().web, | 602 | RepoRef::try_from((create().await, None)).unwrap().web, |
| 571 | vec![ | 603 | vec![ |
| 572 | "https://exampleproject.xyz".to_string(), | 604 | "https://exampleproject.xyz".to_string(), |
| 573 | "https://gitworkshop.dev/123".to_string() | 605 | "https://gitworkshop.dev/123".to_string() |
| @@ -578,7 +610,7 @@ mod tests { | |||
| 578 | #[tokio::test] | 610 | #[tokio::test] |
| 579 | async fn relays() { | 611 | async fn relays() { |
| 580 | assert_eq!( | 612 | assert_eq!( |
| 581 | RepoRef::try_from(create().await).unwrap().relays, | 613 | RepoRef::try_from((create().await, None)).unwrap().relays, |
| 582 | vec![ | 614 | vec![ |
| 583 | RelayUrl::parse("ws://relay1.io").unwrap(), | 615 | RelayUrl::parse("ws://relay1.io").unwrap(), |
| 584 | RelayUrl::parse("ws://relay2.io").unwrap(), | 616 | RelayUrl::parse("ws://relay2.io").unwrap(), |
| @@ -589,7 +621,9 @@ mod tests { | |||
| 589 | #[tokio::test] | 621 | #[tokio::test] |
| 590 | async fn maintainers() { | 622 | async fn maintainers() { |
| 591 | assert_eq!( | 623 | assert_eq!( |
| 592 | RepoRef::try_from(create().await).unwrap().maintainers, | 624 | RepoRef::try_from((create().await, None)) |
| 625 | .unwrap() | ||
| 626 | .maintainers, | ||
| 593 | vec![TEST_KEY_1_KEYS.public_key(), TEST_KEY_2_KEYS.public_key()], | 627 | vec![TEST_KEY_1_KEYS.public_key(), TEST_KEY_2_KEYS.public_key()], |
| 594 | ) | 628 | ) |
| 595 | } | 629 | } |