Skip to content

Commit 1cc491e

Browse files
committed
git: properly parse urls with scp-like syntax #1094
1 parent 46d888e commit 1cc491e

File tree

2 files changed

+42
-4
lines changed

2 files changed

+42
-4
lines changed

CodeApp/Managers/FileSystem/Local/LocalGitCredentialsHelper.swift

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,15 +210,33 @@ final class LocalGitCredentialsHelper {
210210
return try credentialsForRemoteURL(url: url)
211211
}
212212

213-
private func parseRemoteURL(url: URL) -> URL? {
214-
if url.absoluteString.starts(with: "git@") {
215-
return URL(string: "ssh://\(url.absoluteString)")
213+
static func parseRemoteURL(url: URL) -> URL? {
214+
if url.scheme == nil {
215+
// Handle scp-like syntax urls.
216+
// Reference: https://gitirc.eu/git-clone.html#URLS
217+
218+
// From: [<user>@]<host>:/<path-to-git-repo> [<user>@]<host>:~<user>/<path-to-git-repo>
219+
// To: git://<host>[:<port>]/~<user>/<path-to-git-repo>
220+
guard
221+
let userAtHost = url.absoluteString.split(separator: ":").first,
222+
let pathToGitRepo = url.absoluteString.split(separator: "/", maxSplits: 1).last
223+
else {
224+
return nil
225+
}
226+
let user = url.absoluteString.dropFirst(userAtHost.count + 1).dropLast(
227+
pathToGitRepo.count + 1)
228+
229+
if user.count > 0 {
230+
return URL(string: "ssh://\(userAtHost)/\(user)/\(pathToGitRepo)")
231+
} else {
232+
return URL(string: "ssh://\(userAtHost)/\(pathToGitRepo)")
233+
}
216234
}
217235
return url
218236
}
219237

220238
func credentialsForRemoteURL(url: URL) throws -> Credentials {
221-
guard let url = parseRemoteURL(url: url),
239+
guard let url = LocalGitCredentialsHelper.parseRemoteURL(url: url),
222240
let hostname = url.host,
223241
let _scheme = url.scheme,
224242
let scheme = SchemeType(rawValue: _scheme)

CodeUITests/CodeUITests.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,24 @@ final class CodeUITests: XCTestCase {
6060

6161
UserDefaults.standard.removeObject(forKey: "alwaysOpenInNewTab")
6262
}
63+
64+
func testParseRemoteURL_userExtension() throws {
65+
let url = URL(string: "git@github.com:thebaselab/codeapp.git")!
66+
let parsed = LocalGitCredentialsHelper.parseRemoteURL(url: url)
67+
68+
XCTAssertNotNil(parsed)
69+
XCTAssertEqual(parsed!.host, "github.com")
70+
XCTAssertEqual(parsed!.scheme, "ssh")
71+
XCTAssertEqual(parsed!.path, "/thebaselab/codeapp.git")
72+
}
73+
74+
func testParseRemoteURL_noUserExtension() throws {
75+
let url = URL(string: "git@github.com:/codeapp.git")!
76+
let parsed = LocalGitCredentialsHelper.parseRemoteURL(url: url)
77+
78+
XCTAssertNotNil(parsed)
79+
XCTAssertEqual(parsed!.host, "github.com")
80+
XCTAssertEqual(parsed!.scheme, "ssh")
81+
XCTAssertEqual(parsed!.path, "/codeapp.git")
82+
}
6383
}

0 commit comments

Comments
 (0)