diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/GitVersionTests.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/GitVersionTests.xcscheme
new file mode 100644
index 0000000..12529df
--- /dev/null
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/GitVersionTests.xcscheme
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/swift-git-version.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/swift-git-version.xcscheme
new file mode 100644
index 0000000..8d3c550
--- /dev/null
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/swift-git-version.xcscheme
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Package.swift b/Package.swift
index 65a3d3b..f02a232 100644
--- a/Package.swift
+++ b/Package.swift
@@ -24,8 +24,8 @@ let package = Package(
]
),
.testTarget(
- name: "swift-git-versionTests",
- dependencies: ["swift-git-version"]
+ name: "GitVersionTests",
+ dependencies: ["GitVersion"]
),
]
)
diff --git a/Sources/GitVersion/FileClient.swift b/Sources/GitVersion/FileClient.swift
new file mode 100644
index 0000000..95495c3
--- /dev/null
+++ b/Sources/GitVersion/FileClient.swift
@@ -0,0 +1,157 @@
+import Dependencies
+import Foundation
+#if canImport(FoundationNetworking)
+import FoundationNetworking
+#endif
+import XCTestDynamicOverlay
+
+public struct FileClient {
+
+ /// Read the file contents from the given `URL` as `Data`.
+ ///
+ public private(set) var read: (URL) throws -> Data
+
+ /// Write `Data` to a file `URL`.
+ public private(set) var write: (Data, URL) throws -> Void
+
+ /// Create a new ``GitVersion/FileClient`` instance.
+ ///
+ /// This is generally not interacted with directly, instead access as a dependency.
+ ///
+ ///```swift
+ /// @Dependency(\.fileClient) var fileClient
+ ///```
+ ///
+ /// - Parameters:
+ /// - read: Read the file contents.
+ /// - write: Write the data to a file.
+ public init(
+ read: @escaping (URL) throws -> Data,
+ write: @escaping (Data, URL) throws -> Void
+ ) {
+ self.read = read
+ self.write = write
+ }
+
+ /// Read a file at the given path.
+ ///
+ /// - Parameters:
+ /// - path: The path to read the file at.
+ public func read(path: String) throws -> Data {
+ let url = try url(for: path)
+ return try self.read(url)
+ }
+
+ /// Read the file as a string.
+ ///
+ /// - Parameters:
+ /// - url: The url for the file.
+ public func readAsString(url: URL) throws -> String {
+ let data = try read(url)
+ return String(decoding: data, as: UTF8.self)
+ }
+
+ /// Read the file as a string
+ ///
+ /// - Parameters:
+ /// - path: The file path to read.
+ public func readAsString(path: String) throws -> String {
+ try self.readAsString(url: url(for: path))
+ }
+
+ /// Read the contents of a file and decode as the decodable type.
+ ///
+ /// - Parameters:
+ /// - decodable: The type to decode.
+ /// - url: The file url.
+ /// - decoder: The decoder to use.
+ public func read(
+ _ decodable: D.Type,
+ from url: URL,
+ using decoder: JSONDecoder = .init()
+ ) throws -> D {
+ let data = try read(url)
+ return try decoder.decode(D.self, from: data)
+ }
+
+ /// Read the contents of a file and decode as the decodable type.
+ ///
+ /// - Parameters:
+ /// - decodable: The type to decode.
+ /// - path: The file path.
+ /// - decoder: The decoder to use.
+ public func read(
+ _ decodable: D.Type,
+ from path: String,
+ using decoder: JSONDecoder = .init()
+ ) throws -> D {
+ let data = try read(path: path)
+ return try decoder.decode(D.self, from: data)
+ }
+
+ /// Write the data to a file at the given path.
+ ///
+ /// - Parameters:
+ /// - data: The data to write to the file.
+ /// - path: The file path.
+ public func write(data: Data, to path: String) throws {
+ let url = try url(for: path)
+ try self.write(data, url)
+ }
+}
+
+extension FileClient: DependencyKey {
+
+ /// A ``FileClient`` that does not do anything.
+ public static let noop = FileClient.init(
+ read: { _ in Data() },
+ write: { _, _ in }
+ )
+
+ /// An `unimplemented` ``FileClient``.
+ public static let testValue = FileClient(
+ read: unimplemented("\(Self.self).read", placeholder: Data()),
+ write: unimplemented("\(Self.self).write")
+ )
+
+ /// The live ``FileClient``
+ public static let liveValue = FileClient(
+ read: { try Data(contentsOf: $0) },
+ write: { try $0.write(to: $1, options: .atomic) }
+ )
+
+}
+
+extension DependencyValues {
+
+ /// Access a basic ``FileClient`` that can read / write data to the file system.
+ ///
+ public var fileClient: FileClient {
+ get { self[FileClient.self] }
+ set { self[FileClient.self] = newValue }
+ }
+}
+
+// MARK: - Overrides
+extension FileClient {
+
+ /// Override the data that get's returned when a `read` operation is called.
+ ///
+ /// This is useful in a testing context.
+ ///
+ /// - Parameters:
+ /// - data: The data to return when a read operation is called.
+ public mutating func overrideRead(data: Data) {
+ self.read = { _ in data }
+ }
+}
+
+// MARK: - Private
+fileprivate func url(for path: String) throws -> URL {
+ if #available(macOS 13.0, *) {
+ return URL(filePath: path)
+ } else {
+ // Fallback on earlier versions
+ return URL(fileURLWithPath: path)
+ }
+}
diff --git a/Sources/swift-git-version/swift_git_version.swift b/Sources/swift-git-version/swift_git_version.swift
index dec585b..01648c5 100644
--- a/Sources/swift-git-version/swift_git_version.swift
+++ b/Sources/swift-git-version/swift_git_version.swift
@@ -1,6 +1,8 @@
import GitVersion
import ShellClient
+// An example of using the git version client.
+
@main
public struct swift_git_version {
public static func main() {
diff --git a/Tests/GitVersionTests/GitVersionTests.swift b/Tests/GitVersionTests/GitVersionTests.swift
new file mode 100644
index 0000000..1632bf4
--- /dev/null
+++ b/Tests/GitVersionTests/GitVersionTests.swift
@@ -0,0 +1,39 @@
+import XCTest
+import GitVersion
+import ShellClient
+
+final class GitVersionTests: XCTestCase {
+
+ func test_overrides_work() throws {
+ try withDependencies {
+ $0.gitVersionClient.override(with: "blob")
+ } operation: {
+ @Dependency(\.gitVersionClient) var versionClient
+
+ let version = try versionClient.currentVersion()
+ XCTAssertEqual(version, "blob")
+ }
+ }
+
+ func test_live() throws {
+ try withDependencies({
+ $0.logger.logLevel = .debug
+ $0.logger = .liveValue
+ $0.shellClient = .liveValue
+ $0.gitVersionClient = .liveValue
+ }, operation: {
+
+ @Dependency(\.gitVersionClient) var versionClient
+
+ let gitDir = URL(fileURLWithPath: #file)
+ .deletingLastPathComponent()
+ .deletingLastPathComponent()
+ .deletingLastPathComponent()
+
+ let version = try versionClient.currentVersion(in: gitDir.absoluteString)
+ // can't really have a predictable result for the live client.
+ XCTAssertNotEqual(version, "blob")
+
+ })
+ }
+}
diff --git a/Tests/swift-git-versionTests/swift_git_versionTests.swift b/Tests/swift-git-versionTests/swift_git_versionTests.swift
deleted file mode 100644
index 1f97460..0000000
--- a/Tests/swift-git-versionTests/swift_git_versionTests.swift
+++ /dev/null
@@ -1,11 +0,0 @@
-import XCTest
-@testable import swift_git_version
-
-final class swift_git_versionTests: XCTestCase {
- func testExample() throws {
- // This is an example of a functional test case.
- // Use XCTAssert and related functions to verify your tests produce the correct
- // results.
- XCTAssertEqual(swift_git_version().text, "Hello, World!")
- }
-}