-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 860b85e
Showing
9 changed files
with
515 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
.DS_Store | ||
.build | ||
.swiftpm | ||
Packages | ||
*.xcodeproj | ||
Package.resolved |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
FROM swift | ||
WORKDIR /app | ||
COPY . ./ | ||
CMD swift package clean | ||
CMD swift test --parallel |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | ||
Version 2, December 2004 | ||
|
||
Copyright (C) 2018-2019 Binary Birds | ||
|
||
Authors: | ||
|
||
Tibor Bodecs <[email protected]> | ||
|
||
Everyone is permitted to copy and distribute verbatim or modified | ||
copies of this license document, and changing it is allowed as long | ||
as the name is changed. | ||
|
||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | ||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||
|
||
0. You just DO WHAT THE FUCK YOU WANT TO. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// swift-tools-version:5.2 | ||
import PackageDescription | ||
|
||
let package = Package( | ||
name: "git-kit", | ||
products: [ | ||
.library(name: "GitKit", targets: ["GitKit"]), | ||
.library(name: "GitKitDynamic", type: .dynamic, targets: ["GitKit"]) | ||
], | ||
dependencies: [ | ||
.package(url: "https://github.com/binarybirds/shell-kit", from: "1.0.0"), | ||
], | ||
targets: [ | ||
.target(name: "GitKit", dependencies: [ | ||
.product(name: "ShellKit", package: "shell-kit"), | ||
]), | ||
.testTarget(name: "GitKitTests", dependencies: ["GitKit"]), | ||
] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# GitKit (🐱) | ||
|
||
GitKit is a Swift wrapper around the git command line interface. | ||
|
||
## Usage | ||
|
||
Some basic examples: | ||
|
||
```swift | ||
import GitKit | ||
|
||
try Git().run(.cmd(.config, "--global user.name")) | ||
|
||
let git = Git(path: "~/example/") | ||
|
||
try git.run(.cmd(.initialize)) | ||
try git.run(.cmd(.status)) | ||
try git.run(.cmd(.branch, "-a")) | ||
try git.run(.cmd(.pull)) | ||
|
||
try git.run(.clone(url: "https://gitlab.com/binarybirds/shell-kit.git")) | ||
try git.run(.commit(message: "some nasty bug fixed")) | ||
try git.run(.log(1)) | ||
try git.run(.tag("1.0.0")) | ||
try git.run(.pull(remote: "origin", branch: "master")) | ||
try git.run(.push(remote: "origin", branch: "master")) | ||
try git.run(.create(branch: "dev")) | ||
try git.run(.checkout(branch: "master")) | ||
try git.run(.merge(branch: "dev")) | ||
|
||
try git.run(.raw("log -2")) | ||
try git.run(.raw("rebase -i <hash>")) | ||
|
||
``` | ||
|
||
## Install | ||
|
||
Just use the Swift Package Manager as usual: | ||
|
||
```swift | ||
.package(url: "https://github.com/binarybirds/git-kit", from: "1.0.0"), | ||
``` | ||
|
||
Don't forget to add "GitKit" to your target as a dependency: | ||
|
||
```swift | ||
.product(name: "GitKit", package: "git-kit"), | ||
``` | ||
|
||
That's it. | ||
|
||
|
||
## License | ||
|
||
[WTFPL](LICENSE) - Do what the fuck you want to. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,246 @@ | ||
/** | ||
Git.swift | ||
GitKit | ||
|
||
Created by Tibor Bödecs on 2019.01.02. | ||
Copyright Binary Birds. All rights reserved. | ||
*/ | ||
|
||
import ShellKit | ||
|
||
/// a Git wrapper class | ||
public final class Git: Shell { | ||
|
||
/// Git aliases to make the API more convenient | ||
public enum Alias { | ||
case cmd(Command, String? = nil) | ||
case addAll | ||
case commit(message: String, Bool = false) | ||
case clone(url: String) | ||
case checkout(branch: String) | ||
case log(Int? = nil) | ||
case push(remote: String? = nil, branch: String? = nil) | ||
case pull(remote: String? = nil, branch: String? = nil) | ||
case merge(branch: String) | ||
case create(branch: String) | ||
case delete(branch: String) | ||
case tag(String) | ||
case raw(String) | ||
|
||
private func commandParams() -> [String] { | ||
var params: [String] = [] | ||
switch self { | ||
case .cmd(let command, let args): | ||
params = [command.rawValue] | ||
if let args = args { | ||
params.append(args) | ||
} | ||
case .addAll: | ||
params = [Command.add.rawValue, "."] | ||
case .commit(let message, let allowEmpty): | ||
params = [Command.commit.rawValue, "-m", "\"\(message)\""] | ||
if allowEmpty { | ||
params.append("--allow-empty") | ||
} | ||
case .clone(let url): | ||
params = [Command.clone.rawValue, url] | ||
case .checkout(let branch): | ||
params = [Command.checkout.rawValue, branch] | ||
case .log(let n): | ||
params = [Command.log.rawValue] | ||
if let n = n { | ||
params.append("-\(n)") | ||
} | ||
case .push(let remote, let branch): | ||
params = [Command.push.rawValue] | ||
if let remote = remote { | ||
params.append(remote) | ||
} | ||
if let branch = branch { | ||
params.append(branch) | ||
} | ||
case .pull(let remote, let branch): | ||
params = [Command.pull.rawValue] | ||
if let remote = remote { | ||
params.append(remote) | ||
} | ||
if let branch = branch { | ||
params.append(branch) | ||
} | ||
case .merge(let branch): | ||
params = [Command.merge.rawValue, branch] | ||
case .create(let branch): | ||
params = [Command.checkout.rawValue, "-b", branch] | ||
case .delete(let branch): | ||
params = [Command.branch.rawValue, "-D", branch] | ||
case .tag(let name): | ||
params = [Command.tag.rawValue, name] | ||
case .raw(let command): | ||
params.append(command) | ||
} | ||
return params | ||
} | ||
|
||
public var rawValue: String { | ||
self.commandParams().joined(separator: " ") | ||
} | ||
} | ||
|
||
/// basic git commands | ||
public enum Command: String { | ||
|
||
// MARK: - start a working area (see also: git help tutorial) | ||
|
||
case config | ||
|
||
case clean | ||
/// Clone a repository into a new directory | ||
case clone | ||
/// Create an empty Git repository or reinitialize an existing one | ||
case initialize = "init" | ||
|
||
// MARK: - work on the current change (see also: git help everyday) | ||
|
||
/// Add file contents to the index | ||
case add | ||
/// Move or rename a file, a directory, or a symlink | ||
case mv | ||
/// Reset current HEAD to the specified state | ||
case reset | ||
/// Remove files from the working tree and from the index | ||
case rm | ||
|
||
// MARK: - examine the history and state (see also: git help revisions) | ||
|
||
/// Use binary search to find the commit that introduced a bug | ||
case bisect | ||
/// Print lines matching a pattern | ||
case grep | ||
/// Show commit logs | ||
case log | ||
/// Show various types of objects | ||
case show | ||
/// Show the working tree status | ||
case status | ||
|
||
// MARK: - grow, mark and tweak your common history | ||
|
||
/// List, create, or delete branches | ||
case branch | ||
/// Switch branches or restore working tree files | ||
case checkout | ||
/// Record changes to the repository | ||
case commit | ||
/// Show changes between commits, commit and working tree, etc | ||
case diff | ||
/// Join two or more development histories together | ||
case merge | ||
/// Reapply commits on top of another base tip | ||
case rebase | ||
/// Create, list, delete or verify a tag object signed with GPG | ||
case tag | ||
|
||
// MARK: - collaborate (see also: git help workflows) | ||
|
||
/// Download objects and refs from another repository | ||
case fetch | ||
/// Fetch from and integrate with another repository or a local branch | ||
case pull | ||
/// Update remote refs along with associated objects | ||
case push | ||
} | ||
|
||
// MARK: - private helper methods | ||
|
||
/** | ||
This method helps to assemble a Git command string from an alias | ||
|
||
If there is a git repo path (working directory) presented, proper directories | ||
will be used & created recursively if a new repository is being initialized. | ||
|
||
- Parameters: | ||
- alias: The git alias to be executed | ||
- args: Additional arguments for the Git alias | ||
|
||
- Returns: The Git command | ||
*/ | ||
private func rawCommand(_ alias: Alias) -> String { | ||
var cmd: [String] = [] | ||
// if there is a path let's change directory first | ||
if let path = self.path { | ||
// try to create work dir at given path for init or clone commands | ||
if | ||
alias.rawValue.hasPrefix(Command.initialize.rawValue) || | ||
alias.rawValue.hasPrefix(Command.clone.rawValue) | ||
{ | ||
cmd += ["mkdir", "-p", path, "&&"] | ||
} | ||
cmd += ["cd", path, "&&"] | ||
} | ||
cmd += ["git", alias.rawValue] | ||
|
||
let command = cmd.joined(separator: " ") | ||
|
||
if self.verbose { | ||
print(command) | ||
} | ||
return command | ||
} | ||
|
||
// MARK: - public api | ||
|
||
/// work directory, if peresent a directory change will occur before running any Git commands | ||
/// | ||
/// NOTE: if the git init command is called with a non-existing path, directories | ||
/// presented in the path string will be created recursively | ||
public var path: String? | ||
|
||
// prints git commands constructed from the alias before execution | ||
public var verbose = false | ||
|
||
/** | ||
Initializes a new Git object | ||
|
||
- Parameters: | ||
- path: The path of the Swift package (work directory) | ||
- type: The type of the shell, default: /bin/sh | ||
- env: Additional environment variables for the shell, default: empty | ||
|
||
*/ | ||
public init(path: String? = nil, type: String = "/bin/sh", env: [String: String] = [:]) { | ||
self.path = path | ||
|
||
super.init(type, env: env) | ||
} | ||
|
||
/** | ||
Runs a specific Git alias through the current shell. | ||
|
||
- Parameters: | ||
- alias: The git command alias to be executed | ||
|
||
- Throws: | ||
`ShellError.outputData` if the command execution succeeded but the output is empty, | ||
otherwise `ShellError.generic(Int, String)` where the first parameter is the exit code, | ||
the second is the error message | ||
|
||
- Returns: The output string of the command without trailing newlines | ||
*/ | ||
@discardableResult | ||
public func run(_ alias: Alias) throws -> String { | ||
try self.run(self.rawCommand(alias)) | ||
} | ||
|
||
/** | ||
Async version of the run function | ||
|
||
- Parameters: | ||
- alias: The git command alias to be executed | ||
- completion: The completion block with the output and error | ||
|
||
The command will be executed on a concurrent dispatch queue. | ||
*/ | ||
public func run(_ alias: Alias, completion: @escaping ((String?, Swift.Error?) -> Void)) { | ||
self.run(self.rawCommand(alias), completion: completion) | ||
} | ||
} |
Oops, something went wrong.