From 1cc491e8e13807ef9826eaad1c942e991a95adef Mon Sep 17 00:00:00 2001 From: Chung Shing Hin Date: Tue, 18 Jun 2024 01:19:32 +0800 Subject: [PATCH] git: properly parse urls with scp-like syntax #1094 --- .../Local/LocalGitCredentialsHelper.swift | 26 ++++++++++++++++--- CodeUITests/CodeUITests.swift | 20 ++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/CodeApp/Managers/FileSystem/Local/LocalGitCredentialsHelper.swift b/CodeApp/Managers/FileSystem/Local/LocalGitCredentialsHelper.swift index ffad83ddb..23f636de7 100644 --- a/CodeApp/Managers/FileSystem/Local/LocalGitCredentialsHelper.swift +++ b/CodeApp/Managers/FileSystem/Local/LocalGitCredentialsHelper.swift @@ -210,15 +210,33 @@ final class LocalGitCredentialsHelper { return try credentialsForRemoteURL(url: url) } - private func parseRemoteURL(url: URL) -> URL? { - if url.absoluteString.starts(with: "git@") { - return URL(string: "ssh://\(url.absoluteString)") + static func parseRemoteURL(url: URL) -> URL? { + if url.scheme == nil { + // Handle scp-like syntax urls. + // Reference: https://gitirc.eu/git-clone.html#URLS + + // From: [@]:/ [@]:~/ + // To: git://[:]/~/ + guard + let userAtHost = url.absoluteString.split(separator: ":").first, + let pathToGitRepo = url.absoluteString.split(separator: "/", maxSplits: 1).last + else { + return nil + } + let user = url.absoluteString.dropFirst(userAtHost.count + 1).dropLast( + pathToGitRepo.count + 1) + + if user.count > 0 { + return URL(string: "ssh://\(userAtHost)/\(user)/\(pathToGitRepo)") + } else { + return URL(string: "ssh://\(userAtHost)/\(pathToGitRepo)") + } } return url } func credentialsForRemoteURL(url: URL) throws -> Credentials { - guard let url = parseRemoteURL(url: url), + guard let url = LocalGitCredentialsHelper.parseRemoteURL(url: url), let hostname = url.host, let _scheme = url.scheme, let scheme = SchemeType(rawValue: _scheme) diff --git a/CodeUITests/CodeUITests.swift b/CodeUITests/CodeUITests.swift index 195d41349..b2beab417 100644 --- a/CodeUITests/CodeUITests.swift +++ b/CodeUITests/CodeUITests.swift @@ -60,4 +60,24 @@ final class CodeUITests: XCTestCase { UserDefaults.standard.removeObject(forKey: "alwaysOpenInNewTab") } + + func testParseRemoteURL_userExtension() throws { + let url = URL(string: "git@github.com:thebaselab/codeapp.git")! + let parsed = LocalGitCredentialsHelper.parseRemoteURL(url: url) + + XCTAssertNotNil(parsed) + XCTAssertEqual(parsed!.host, "github.com") + XCTAssertEqual(parsed!.scheme, "ssh") + XCTAssertEqual(parsed!.path, "/thebaselab/codeapp.git") + } + + func testParseRemoteURL_noUserExtension() throws { + let url = URL(string: "git@github.com:/codeapp.git")! + let parsed = LocalGitCredentialsHelper.parseRemoteURL(url: url) + + XCTAssertNotNil(parsed) + XCTAssertEqual(parsed!.host, "github.com") + XCTAssertEqual(parsed!.scheme, "ssh") + XCTAssertEqual(parsed!.path, "/codeapp.git") + } }