Skip to content

Commit 3fe6da2

Browse files
committed
Improved and added new git functions
1 parent 631dc63 commit 3fe6da2

File tree

7 files changed

+445
-244
lines changed

7 files changed

+445
-244
lines changed

Sources/Version-Control/Base/Actions/GitHub/GitHubActions.swift

+23-3
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,18 @@ public enum GitHubViewType: String {
1515

1616
public struct GitHubActions {
1717

18-
internal func getBranchName(directoryURL: URL) throws -> String {
19-
return try Branch().getCurrentBranch(directoryURL: directoryURL)
18+
internal func getBranchName(
19+
directoryURL: URL,
20+
completion: @escaping (Result<String, Error>) -> Void
21+
) {
22+
Task {
23+
do {
24+
let branchName = try await Branch().getCurrentBranch(directoryURL: directoryURL)
25+
completion(.success(branchName))
26+
} catch {
27+
completion(.failure(error))
28+
}
29+
}
2030
}
2131

2232
internal func getCurrentRepositoryGitHubURL(directoryURL: URL) throws -> String {
@@ -52,7 +62,17 @@ public struct GitHubActions {
5262
public func openBranchOnGitHub(viewType: GitHubViewType,
5363
directoryURL: URL) throws {
5464
let htmlURL = try getCurrentRepositoryGitHubURL(directoryURL: directoryURL)
55-
let branchName = try getBranchName(directoryURL: directoryURL)
65+
66+
var branchName = ""
67+
68+
getBranchName(directoryURL: directoryURL) { result in
69+
switch result {
70+
case .success(let name):
71+
branchName = name
72+
case .failure(let error):
73+
branchName = ""
74+
}
75+
}
5676

5777
let urlEncodedBranchName = branchName.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)
5878

Sources/Version-Control/Base/Commands/Branch.swift

+15-131
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,19 @@ public struct Branch { // swiftlint:disable:this type_body_length
1818
/// - Parameter directoryURL: The URL of the directory where the Git repository is located.
1919
/// - Returns: A string representing the name of the current branch.
2020
/// - Throws: An error if the shell command fails.
21-
public func getCurrentBranch(directoryURL: URL) throws -> String {
22-
return try ShellClient.live().run(
23-
"cd \(directoryURL.relativePath.escapedWhiteSpaces());git branch --show-current"
24-
).removingNewLines()
21+
public func getCurrentBranch(directoryURL: URL) async throws -> String {
22+
let args = [
23+
"branch",
24+
"--show-current"
25+
]
26+
27+
let result = try await GitShell().git(
28+
args: args,
29+
path: directoryURL,
30+
name: #function
31+
)
32+
33+
return result.stdout.removingNewLines()
2534
}
2635

2736
/// Fetches all branches in the given directory, optionally filtering by prefixes.
@@ -31,7 +40,7 @@ public struct Branch { // swiftlint:disable:this type_body_length
3140
/// - prefixes: An array of strings representing branch name prefixes to filter by. Defaults to an empty array.
3241
/// - Returns: An array of `GitBranch` instances representing the fetched branches.
3342
/// - Throws: An error if the shell command fails.
34-
public func getBranches(directoryURL: URL, prefixes: [String] = []) throws -> [GitBranch] {
43+
public func getBranches(directoryURL: URL, prefixes: [String] = []) async throws -> [GitBranch] {
3544
let fields = ["fullName": "%(refname)",
3645
"shortName": "%(refname:short)",
3746
"upstreamShortName": "%(upstream:short)",
@@ -51,7 +60,7 @@ public struct Branch { // swiftlint:disable:this type_body_length
5160
let gitCommand = ["for-each-ref"] + args + prefixArgs
5261

5362
// Execute the git command using the GitShell utility
54-
let result = try GitShell().git(
63+
let result = try await GitShell().git(
5564
args: gitCommand,
5665
path: directoryURL,
5766
name: #function,
@@ -177,77 +186,6 @@ public struct Branch { // swiftlint:disable:this type_body_length
177186
return eligibleBranches
178187
}
179188

180-
/// Retrieves a list of the most recently modified branches, up to a specified limit.
181-
///
182-
/// - Parameters:
183-
/// - directoryURL: The URL of the directory where the Git repository is located.
184-
/// - limit: An integer specifying the maximum number of branches to retrieve.
185-
/// - Returns: An array of strings representing the names of the recent branches.
186-
/// - Throws: An error if the shell command fails.
187-
public func getRecentBranches(directoryURL: URL, limit: Int) throws -> [String] {
188-
let regex = try NSRegularExpression(
189-
// swiftlint:disable:next line_length
190-
pattern: #"^.*? (renamed|checkout)(?:: moving from|\s*) (?:refs/heads/|\s*)(.*?) to (?:refs/heads/|\s*)(.*?)$"#,
191-
options: []
192-
)
193-
194-
let args = [
195-
"log",
196-
"-g",
197-
"--no-abbrev-commit",
198-
"--pretty=oneline",
199-
"HEAD",
200-
"-n",
201-
"2500",
202-
"--"
203-
]
204-
205-
let result = try GitShell().git(args: args,
206-
path: directoryURL,
207-
name: #function)
208-
209-
if result.exitCode == 128 {
210-
// error code 128 is returned if the branch is unborn
211-
return []
212-
}
213-
214-
let lines = result.stdout.components(separatedBy: "\n")
215-
var names = Set<String>()
216-
var excludedNames = Set<String>()
217-
218-
for line in lines {
219-
if let match = regex.firstMatch(
220-
in: line,
221-
options: [],
222-
range: NSRange(location: 0, length: line.utf16.count)
223-
),
224-
match.numberOfRanges == 4 {
225-
let operationTypeRange = Range(match.range(at: 1), in: line)!
226-
let excludeBranchNameRange = Range(match.range(at: 2), in: line)!
227-
let branchNameRange = Range(match.range(at: 3), in: line)!
228-
229-
let operationType = String(line[operationTypeRange])
230-
let excludeBranchName = String(line[excludeBranchNameRange])
231-
let branchName = String(line[branchNameRange])
232-
233-
if operationType == "renamed" {
234-
// exclude intermediate-state renaming branch from recent branches
235-
excludedNames.insert(excludeBranchName)
236-
}
237-
238-
if !excludedNames.contains(branchName) {
239-
names.insert(branchName)
240-
}
241-
}
242-
243-
if names.count >= limit {
244-
break
245-
}
246-
}
247-
248-
return Array(names)
249-
}
250-
251189
func getCommitsOnBranch() {
252190
guard let noCommitsOnBranchRe = try? NSRegularExpression(
253191
pattern: "fatal: your current branch '.*' does not have any commits yet"
@@ -257,59 +195,6 @@ public struct Branch { // swiftlint:disable:this type_body_length
257195
}
258196
}
259197

260-
/// Asynchronously fetches the names and dates of branches checked out after a specified date.
261-
///
262-
/// - Parameters:
263-
/// - directoryURL: The URL of the directory where the Git repository is located.
264-
/// - afterDate: A `Date` object representing the starting point for the search.
265-
/// - Returns: A dictionary mapping branch names to the dates they were checked out.
266-
/// - Throws: An error if the shell command fails.
267-
func getBranchCheckouts(directoryURL: URL, afterDate: Date) async throws -> [String: Date] {
268-
let regexPattern = #"^[a-z0-9]{40}\sHEAD@{(.*)}\scheckout: moving from\s.*\sto\s(.*)$"# // regexr.com/46n1v
269-
let regex = try NSRegularExpression(pattern: regexPattern, options: [])
270-
271-
let args = [
272-
"reflog",
273-
"--date=iso",
274-
"--after=\(afterDate.timeIntervalSince1970)",
275-
"--pretty=%H %gd %gs",
276-
"--grep-reflog=checkout: moving from .* to .*$",
277-
"--"
278-
]
279-
280-
let result = try GitShell().git(args: args,
281-
path: directoryURL,
282-
name: #function)
283-
284-
var checkouts = [String: Date]()
285-
286-
if result.exitCode == 128 {
287-
return checkouts
288-
}
289-
290-
let lines = result.stdout.components(separatedBy: "\n")
291-
for line in lines {
292-
if let match = regex.firstMatch(
293-
in: line,
294-
options: [],
295-
range: NSRange(location: 0, length: line.utf16.count)
296-
),
297-
match.numberOfRanges == 3 {
298-
let timestampRange = Range(match.range(at: 1), in: line)!
299-
let branchNameRange = Range(match.range(at: 2), in: line)!
300-
301-
let timestampString = String(line[timestampRange])
302-
let branchName = String(line[branchNameRange])
303-
304-
if let timestamp = ISO8601DateFormatter().date(from: timestampString) {
305-
checkouts[branchName] = timestamp
306-
}
307-
}
308-
}
309-
310-
return checkouts
311-
}
312-
313198
/// Creates a new branch in the specified directory.
314199
///
315200
/// This function creates a new branch in the specified Git repository directory. It allows
@@ -446,7 +331,6 @@ public struct Branch { // swiftlint:disable:this type_body_length
446331
remoteName: String,
447332
remoteBranchName: String) throws -> Bool {
448333
let args = [
449-
gitNetworkArguments.joined(),
450334
"push",
451335
remoteName,
452336
":\(remoteBranchName)"

Sources/Version-Control/Base/Commands/Checkout.swift

+11-32
Original file line numberDiff line numberDiff line change
@@ -32,39 +32,19 @@ public struct GitCheckout {
3232
branch: GitBranch,
3333
enableRecurseSubmodulesFlag: Bool = false
3434
) -> [String] {
35-
var baseArgs: [String] = []
35+
var args = [branch.name]
36+
37+
if branch.type == .remote {
38+
args.append(contentsOf: ["-b", branch.nameWithoutRemote])
39+
}
3640

3741
if enableRecurseSubmodulesFlag {
38-
if branch.type == BranchType.remote {
39-
return baseArgs + [
40-
branch.name,
41-
"-b",
42-
branch.nameWithoutRemote,
43-
"--recurse-submodules",
44-
"--"
45-
]
46-
} else {
47-
return baseArgs + [
48-
branch.name,
49-
"--recurse-submodules",
50-
"--"
51-
]
52-
}
53-
} else {
54-
if branch.type == BranchType.remote {
55-
return baseArgs + [
56-
branch.name,
57-
"-b",
58-
branch.nameWithoutRemote,
59-
"--"
60-
]
61-
} else {
62-
return baseArgs + [
63-
branch.name,
64-
"--"
65-
]
66-
}
42+
args.append("--recurse-submodules")
6743
}
44+
45+
args.append("--")
46+
47+
return args
6848
}
6949

7050
public func getCheckoutOpts( // swiftlint:disable:this function_parameter_count
@@ -153,8 +133,7 @@ public struct GitCheckout {
153133

154134
try GitShell().git(args: args,
155135
path: directoryURL,
156-
name: #function,
157-
options: opts)
136+
name: #function)
158137
return true
159138
}
160139

0 commit comments

Comments
 (0)