|
1 | 1 | function parseRepositoryURL(repoURL) { |
| 2 | + // Remove any trailing .git suffix and trim whitespace |
2 | 3 | repoURL = repoURL.trim().replace(/\.git$/i, ""); |
3 | 4 |
|
4 | | - // SSH and git protocol (e.g., git@github.com:owner/repo or git://host/owner/repo) |
5 | | - const m = repoURL.match( |
6 | | - /^(git@|ssh:\/\/git@|git:\/\/)([^:/]+)[:/]((?:[^/]+\/)+[^/]+)$/i, |
7 | | - ); |
| 5 | + // Normalize all input to HTTP(S) URL for easier parsing |
| 6 | + let m = repoURL.match(/^(git@|ssh:\/\/git@|git:\/\/)([^:/]+)[:\/]((?:[^/]+\/)+[^/]+)$/i); |
8 | 7 | if (m) { |
9 | | - const host = m[2]; |
10 | | - const parts = m[3].split("/").filter(Boolean); |
11 | | - // GitHub Enterprise SSH URL: git@github.com:enterprises/enterprise/owner/repo |
12 | | - if ( |
13 | | - host.toLowerCase() === "github.com" && |
14 | | - parts[0] === "enterprises" && |
15 | | - parts.length >= 4 |
16 | | - ) { |
17 | | - return { |
18 | | - origin: `https://github.com`, |
19 | | - enterprise: parts[1], |
20 | | - owner: parts[2], |
21 | | - repo: parts[3], |
22 | | - }; |
23 | | - } else if (parts.length === 2) { |
24 | | - // Standard SSH URL: git@host:owner/repo |
25 | | - return { |
26 | | - origin: `https://${host}`, |
27 | | - owner: parts[0], |
28 | | - repo: parts[1], |
29 | | - }; |
30 | | - } |
31 | | - // Unrecognized SSH format |
32 | | - return null; |
33 | | - } |
34 | | - |
35 | | - // Shorthand and domain/owner/repo (e.g., owner/repo or host/owner/repo) |
36 | | - if (!/^\w+:\/\//.test(repoURL)) { |
| 8 | + // SSH or git: git@github.com:owner/repo or ssh://git@github.com/owner/repo or git://github.com/owner/repo |
| 9 | + repoURL = `https://${m[2]}/${m[3]}`; |
| 10 | + } else if (!/^\w+:\/\//.test(repoURL)) { |
| 11 | + // Shorthand: owner/repo or host/owner/repo |
37 | 12 | const parts = repoURL.split("/").filter(Boolean); |
38 | | - if (parts.length === 2) { |
39 | | - // owner/repo shorthand (assume github.com) |
40 | | - return { |
41 | | - origin: "https://github.com", |
42 | | - owner: parts[0], |
43 | | - repo: parts[1], |
44 | | - }; |
45 | | - } else if (parts.length >= 3 && parts[0].includes(".")) { |
46 | | - // treat as URL, fall through to URL parsing |
47 | | - repoURL = "https://" + repoURL; |
48 | | - } else { |
49 | | - // Unrecognized shorthand |
50 | | - return null; |
| 13 | + if (parts.length >= 3 && parts[0].includes(".")) { |
| 14 | + // host/owner/repo |
| 15 | + repoURL = `https://${repoURL}`; |
| 16 | + } else if (parts.length >= 2 && !parts[0].includes(".")) { |
| 17 | + // owner/repo |
| 18 | + repoURL = `https://github.com/${parts[0]}/${parts[1]}`; |
51 | 19 | } |
52 | 20 | } |
53 | 21 |
|
54 | | - // HTTP(S) URLs (e.g., https://github.com/owner/repo) |
| 22 | + // Parse the normalized URL and extract components |
55 | 23 | try { |
56 | 24 | const url = new URL(repoURL); |
57 | 25 | const parts = url.pathname.split("/").filter(Boolean); |
58 | | - // GitHub Enterprise HTTP URL: https://github.com/enterprises/enterprise/owner/repo |
59 | 26 | if ( |
60 | 27 | url.host.toLowerCase() === "github.com" && |
61 | 28 | parts[0] === "enterprises" && |
62 | 29 | parts.length >= 4 |
63 | 30 | ) { |
| 31 | + // Enterprise: http(s)://github.com/enterprises/enterprise/owner/repo |
64 | 32 | return { |
65 | 33 | origin: url.origin, |
66 | 34 | enterprise: parts[1], |
67 | 35 | owner: parts[2], |
68 | 36 | repo: parts[3], |
69 | 37 | }; |
70 | 38 | } else if (parts.length >= 2) { |
71 | | - // Standard HTTP(S) URL: https://host/owner/repo |
| 39 | + // Standard: http(s)://host/owner/repo |
72 | 40 | return { |
73 | 41 | origin: url.origin, |
74 | 42 | owner: parts[0], |
75 | 43 | repo: parts[1], |
76 | 44 | }; |
77 | 45 | } |
78 | 46 | } catch { |
79 | | - // Not a valid URL, fall through |
| 47 | + // Not a valid URL |
80 | 48 | } |
81 | | - |
82 | | - // If none of the above matched, return null |
83 | 49 | return null; |
84 | 50 | } |
85 | 51 |
|
|
0 commit comments