Infer the repository name from a URL. Extracts a suitable directory name from various URL formats: - `https://example.com/org/project/code` → `project` - `https://example.com/repo.git` → `repo` - `https://example.com/tenant/t/portfolio/p/project/pr/code` → `pr` # Arguments `url` - The remote URL to parse # Returns `Some(name)` if a name could be inferred, `None` otherwise. # Example ```rus
(url: &str)
| 60 | /// assert_eq!(infer_repo_name("https://example.com/tenant/t/portfolio/p/project/pr/code"), Some("pr".to_string())); |
| 61 | /// ``` |
| 62 | pub fn infer_repo_name(url: &str) -> Option<String> { |
| 63 | // Remove trailing slashes |
| 64 | let url = url.trim_end_matches('/'); |
| 65 | |
| 66 | // Try to parse as URL |
| 67 | if let Ok(parsed) = url::Url::parse(url) { |
| 68 | let path = parsed.path(); |
| 69 | let segments: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect(); |
| 70 | |
| 71 | // Check for atomic-api URL pattern: /tenant/t/portfolio/p/project/pr/code |
| 72 | if segments.len() >= 6 && segments.last() == Some(&"code") { |
| 73 | // Project name is the second-to-last segment (pr in the pattern) |
| 74 | return segments.get(segments.len() - 2).map(|s| s.to_string()); |
| 75 | } |
| 76 | |
| 77 | // Check for .git suffix |
| 78 | if let Some(last) = segments.last() { |
| 79 | let name = last.trim_end_matches(".git"); |
| 80 | if !name.is_empty() && name != "code" { |
| 81 | return Some(name.to_string()); |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | // Use second-to-last segment if last is "code" or empty |
| 86 | if segments.len() >= 2 { |
| 87 | if let Some(second_last) = segments.get(segments.len() - 2) { |
| 88 | if !second_last.is_empty() { |
| 89 | return Some(second_last.to_string()); |
| 90 | } |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | // Fallback to last non-empty segment |
| 95 | for segment in segments.iter().rev() { |
| 96 | if !segment.is_empty() && *segment != "code" { |
| 97 | return Some(segment.to_string()); |
| 98 | } |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | // If URL parsing failed, try simple path extraction |
| 103 | let parts: Vec<&str> = url.rsplit('/').collect(); |
| 104 | for part in parts { |
| 105 | let name = part.trim_end_matches(".git"); |
| 106 | if !name.is_empty() && name != "code" { |
| 107 | return Some(name.to_string()); |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | None |
| 112 | } |
| 113 | |
| 114 | // Path Validation |
| 115 |