From 771f944af447c202eba045936a36dee71ab797ac Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Wed, 4 Sep 2024 11:32:05 +0100 Subject: refactor: fix imports, etc based on restructure move some functions out of ngit and into lib/mod and lib/git_events remove MockConnect from binaries so it is only used in the library. this was done: * mainly because automocks were not being imported from lib into each binary * but also because the these functions were being tested with MockConnect --- src/lib/git/mod.rs | 266 ++--------------------------------------------------- 1 file changed, 7 insertions(+), 259 deletions(-) (limited to 'src/lib/git/mod.rs') diff --git a/src/lib/git/mod.rs b/src/lib/git/mod.rs index 5919667..f92272f 100644 --- a/src/lib/git/mod.rs +++ b/src/lib/git/mod.rs @@ -1,18 +1,16 @@ use std::{ - collections::HashSet, env::current_dir, path::{Path, PathBuf}, }; use anyhow::{bail, Context, Result}; use git2::{DiffOptions, Oid, Revwalk}; -use nostr::nips::nip01::Coordinate; -use nostr_sdk::{ - hashes::{sha1::Hash as Sha1Hash, Hash}, - PublicKey, Url, -}; +pub use identify_ahead_behind::identify_ahead_behind; +use nostr_sdk::hashes::{sha1::Hash as Sha1Hash, Hash}; -use crate::sub_commands::list::{get_commit_id_from_patch, tag_value}; +use crate::git_events::{get_commit_id_from_patch, tag_value}; +pub mod identify_ahead_behind; +pub mod nostr_url; pub struct Repo { pub git_repo: git2::Repository, @@ -835,188 +833,6 @@ fn extract_sig_from_patch_tags<'a>( .context("failed to create git signature") } -#[derive(Debug, PartialEq)] -pub enum ServerProtocol { - Ssh, - Https, - Http, - Git, -} - -#[derive(Debug, PartialEq)] -pub struct NostrUrlDecoded { - pub coordinates: HashSet, - pub protocol: Option, - pub user: Option, -} - -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"; - -impl NostrUrlDecoded { - pub fn from_str(url: &str) -> Result { - let mut coordinates = HashSet::new(); - let mut protocol = None; - let mut user = None; - let mut relays = vec![]; - - if !url.starts_with("nostr://") { - bail!("nostr git url must start with nostr://"); - } - // process get url parameters if present - for (name, value) in Url::parse(url)?.query_pairs() { - if name.contains("relay") { - let mut decoded = urlencoding::decode(&value) - .context("could not parse relays in nostr git url")? - .to_string(); - if !decoded.starts_with("ws://") && !decoded.starts_with("wss://") { - decoded = format!("wss://{decoded}"); - } - let url = - Url::parse(&decoded).context("could not parse relays in nostr git url")?; - relays.push(url.to_string()); - } else if name == "protocol" { - protocol = match value.as_ref() { - "ssh" => Some(ServerProtocol::Ssh), - "https" => Some(ServerProtocol::Https), - "http" => Some(ServerProtocol::Http), - "git" => Some(ServerProtocol::Git), - _ => None, - }; - } else if name == "user" { - user = Some(value.to_string()); - } - } - - let mut parts: Vec<&str> = url[8..] - .split('?') - .next() - .unwrap_or("") - .split('/') - .collect(); - - // extract optional protocol - if protocol.is_none() { - let part = parts.first().context(INCORRECT_NOSTR_URL_FORMAT_ERROR)?; - let protocol_str = if let Some(at_index) = part.find('@') { - user = Some(part[..at_index].to_string()); - &part[at_index + 1..] - } else { - part - }; - protocol = match protocol_str { - "ssh" => Some(ServerProtocol::Ssh), - "https" => Some(ServerProtocol::Https), - "http" => Some(ServerProtocol::Http), - "git" => Some(ServerProtocol::Git), - _ => protocol, - }; - if protocol.is_some() { - parts.remove(0); - } - } - // extract naddr npub//identifer - let part = parts.first().context(INCORRECT_NOSTR_URL_FORMAT_ERROR)?; - // naddr used - if let Ok(coordinate) = Coordinate::parse(part) { - if coordinate.kind.eq(&nostr_sdk::Kind::GitRepoAnnouncement) { - coordinates.insert(coordinate); - } else { - bail!("naddr doesnt point to a git repository announcement"); - } - // npub//identifer used - } else if let Ok(public_key) = PublicKey::parse(part) { - parts.remove(0); - let identifier = parts - .pop() - .context("nostr url must have an identifier eg. nostr://npub123/repo-identifier")? - .to_string(); - for relay in parts { - let mut decoded = urlencoding::decode(relay) - .context("could not parse relays in nostr git url")? - .to_string(); - if !decoded.starts_with("ws://") && !decoded.starts_with("wss://") { - decoded = format!("wss://{decoded}"); - } - let url = - Url::parse(&decoded).context("could not parse relays in nostr git url")?; - relays.push(url.to_string()); - } - coordinates.insert(Coordinate { - identifier, - public_key, - kind: nostr_sdk::Kind::GitRepoAnnouncement, - relays, - }); - } else { - bail!(INCORRECT_NOSTR_URL_FORMAT_ERROR); - } - - Ok(Self { - coordinates, - protocol, - user, - }) - } -} - -/** produce error when using local repo or custom protocols */ -pub fn convert_clone_url_to_https(url: &str) -> Result { - // Strip credentials if present - let stripped_url = strip_credentials(url); - - // Check if the URL is already in HTTPS format - if stripped_url.starts_with("https://") { - return Ok(stripped_url); - } - // Convert http:// to https:// - else if stripped_url.starts_with("http://") { - return Ok(stripped_url.replace("http://", "https://")); - } - // Check if the URL starts with SSH - else if stripped_url.starts_with("ssh://") { - // Convert SSH to HTTPS - let parts: Vec<&str> = stripped_url - .trim_start_matches("ssh://") - .split('/') - .collect(); - if parts.len() >= 2 { - // Construct the HTTPS URL - return Ok(format!("https://{}/{}", parts[0], parts[1..].join("/"))); - } - bail!("Invalid SSH URL format: {}", url); - } - // Convert ftp:// to https:// - else if stripped_url.starts_with("ftp://") { - return Ok(stripped_url.replace("ftp://", "https://")); - } - // Convert git:// to https:// - else if stripped_url.starts_with("git://") { - return Ok(stripped_url.replace("git://", "https://")); - } - - // If the URL is neither HTTPS, SSH, nor git@, return an error - bail!("Unsupported URL protocol: {}", url); -} - -// Function to strip username and password from the URL -fn strip_credentials(url: &str) -> String { - if let Some(pos) = url.find("://") { - let (protocol, rest) = url.split_at(pos + 3); // Split at "://" - let rest_parts: Vec<&str> = rest.split('@').collect(); - if rest_parts.len() > 1 { - // If there are credentials, return the URL without them - return format!("{}{}", protocol, rest_parts[1]); - } - } else if let Some(at_pos) = url.find('@') { - // Handle user@host:path format - let (_, rest) = url.split_at(at_pos); - // This is a git@ syntax - let host_and_repo = &rest[1..]; // Skip the ':' - return format!("ssh://{}", host_and_repo.replace(':', "/")); - } - url.to_string() // Return the original URL if no credentials are found -} - #[cfg(test)] mod tests { use std::fs; @@ -1813,7 +1629,7 @@ mod tests { use test_utils::TEST_KEY_1_SIGNER; use super::*; - use crate::{repo_ref::RepoRef, sub_commands::send::generate_patch_event}; + use crate::{git_events::generate_patch_event, repo_ref::RepoRef}; async fn generate_patch_from_head_commit(test_repo: &GitTestRepo) -> Result { let original_oid = test_repo.git_repo.head()?.peel_to_commit()?.id(); @@ -1959,9 +1775,7 @@ mod tests { use test_utils::TEST_KEY_1_SIGNER; use super::*; - use crate::{ - repo_ref::RepoRef, sub_commands::send::generate_cover_letter_and_patch_events, - }; + use crate::{git_events::generate_cover_letter_and_patch_events, repo_ref::RepoRef}; static BRANCH_NAME: &str = "add-example-feature"; // returns original_repo, cover_letter_event, patch_events @@ -2497,70 +2311,4 @@ mod tests { Ok(()) } } - mod convert_clone_url_to_https { - use super::*; - - #[test] - fn test_https_url() { - let url = "https://github.com/user/repo.git"; - let result = convert_clone_url_to_https(url).unwrap(); - assert_eq!(result, "https://github.com/user/repo.git"); - } - - #[test] - fn test_http_url() { - let url = "http://github.com/user/repo.git"; - let result = convert_clone_url_to_https(url).unwrap(); - assert_eq!(result, "https://github.com/user/repo.git"); - } - - #[test] - fn test_http_url_with_credentials() { - let url = "http://username:password@github.com/user/repo.git"; - let result = convert_clone_url_to_https(url).unwrap(); - assert_eq!(result, "https://github.com/user/repo.git"); - } - - #[test] - fn test_git_at_url() { - let url = "git@github.com:user/repo.git"; - let result = convert_clone_url_to_https(url).unwrap(); - assert_eq!(result, "https://github.com/user/repo.git"); - } - - #[test] - fn test_user_at_url() { - let url = "user1@github.com:user/repo.git"; - let result = convert_clone_url_to_https(url).unwrap(); - assert_eq!(result, "https://github.com/user/repo.git"); - } - - #[test] - fn test_ssh_url() { - let url = "ssh://github.com/user/repo.git"; - let result = convert_clone_url_to_https(url).unwrap(); - assert_eq!(result, "https://github.com/user/repo.git"); - } - - #[test] - fn test_ftp_url() { - let url = "ftp://example.com/repo.git"; - let result = convert_clone_url_to_https(url).unwrap(); - assert_eq!(result, "https://example.com/repo.git"); - } - - #[test] - fn test_git_protocol_url() { - let url = "git://example.com/repo.git"; - let result = convert_clone_url_to_https(url).unwrap(); - assert_eq!(result, "https://example.com/repo.git"); - } - - #[test] - fn test_invalid_url() { - let url = "unsupported://example.com/repo.git"; - let result = convert_clone_url_to_https(url); - assert!(result.is_err()); - } - } } -- cgit v1.2.3