feat: Updates configuration, uses json for configuration files and drops toml support.

This commit is contained in:
2024-12-24 09:02:38 -05:00
parent 7d23172c71
commit f2a2374c4f
14 changed files with 127 additions and 395 deletions

View File

@@ -1,19 +1,7 @@
{ {
"strategy" : { "strategy" : {
"semvar" : { "branch" : {
"preRelease" : { "includeCommitSha": true
"strategy" : {
"command" : {
"arguments" : [
"git",
"describe",
"--tags"
]
}
}
},
"requireExistingFile" : true,
"requireExistingSemVar" : true
} }
}, },
"target" : { "target" : {

View File

@@ -1,5 +1,5 @@
{ {
"originHash" : "a6f314a56cd0c1a50e5cace4aacf75ecda58c4cc00e5e13bf7ec110289f943bf", "originHash" : "077fe473b2dff48184d79b6897170a2c87f00a465e6c079889de37e6470001fb",
"pins" : [ "pins" : [
{ {
"identity" : "combine-schedulers", "identity" : "combine-schedulers",
@@ -118,15 +118,6 @@
"version" : "600.0.1" "version" : "600.0.1"
} }
}, },
{
"identity" : "tomlkit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/LebJe/TOMLKit.git",
"state" : {
"revision" : "ec6198d37d495efc6acd4dffbd262cdca7ff9b3f",
"version" : "0.6.0"
}
},
{ {
"identity" : "xctest-dynamic-overlay", "identity" : "xctest-dynamic-overlay",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",

View File

@@ -19,7 +19,6 @@ let package = Package(
.package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.0.0"), .package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.0.0"),
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.0.0"), .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.0.0"),
.package(url: "https://github.com/apple/swift-log.git", from: "1.6.2"), .package(url: "https://github.com/apple/swift-log.git", from: "1.6.2"),
.package(url: "https://github.com/LebJe/TOMLKit.git", from: "0.5.0"),
.package(url: "https://github.com/pointfreeco/swift-custom-dump.git", from: "1.3.3") .package(url: "https://github.com/pointfreeco/swift-custom-dump.git", from: "1.3.3")
], ],
targets: [ targets: [
@@ -50,8 +49,7 @@ let package = Package(
"FileClient", "FileClient",
.product(name: "CustomDump", package: "swift-custom-dump"), .product(name: "CustomDump", package: "swift-custom-dump"),
.product(name: "Dependencies", package: "swift-dependencies"), .product(name: "Dependencies", package: "swift-dependencies"),
.product(name: "DependenciesMacros", package: "swift-dependencies"), .product(name: "DependenciesMacros", package: "swift-dependencies")
.product(name: "TOMLKit", package: "TOMLKit")
] ]
), ),
.testTarget( .testTarget(

View File

@@ -68,14 +68,14 @@ extension GitClient {
} }
} }
extension Configuration.PreReleaseStrategy { extension Configuration.PreRelease {
func preReleaseString(gitDirectory: String?) async throws -> String { func preReleaseString(gitDirectory: String?) async throws -> String {
@Dependency(\.gitClient) var gitClient @Dependency(\.gitClient) var gitClient
let preReleaseString: String let preReleaseString: String
if let branch { if let branch = strategy?.branch {
preReleaseString = try await gitClient.version(branch: branch, gitDirectory: gitDirectory) preReleaseString = try await gitClient.version(branch: branch, gitDirectory: gitDirectory)
} else { } else {
preReleaseString = try await gitClient.version(.init( preReleaseString = try await gitClient.version(.init(

View File

@@ -46,7 +46,6 @@ public extension FileClient {
let (string, usesOptionalType) = try await getVersionString(fileUrl: file, gitDirectory: gitDirectory) let (string, usesOptionalType) = try await getVersionString(fileUrl: file, gitDirectory: gitDirectory)
let semvar = SemVar(string: string) let semvar = SemVar(string: string)
logger.debug("Semvar: \(String(describing: semvar))") logger.debug("Semvar: \(String(describing: semvar))")
return (semvar, usesOptionalType) return (semvar, usesOptionalType)
} }

View File

@@ -1,7 +1,6 @@
import Dependencies import Dependencies
import DependenciesMacros import DependenciesMacros
import Foundation import Foundation
import TOMLKit
public extension DependencyValues { public extension DependencyValues {
var coders: Coders { var coders: Coders {
@@ -14,17 +13,13 @@ public extension DependencyValues {
public struct Coders: Sendable { public struct Coders: Sendable {
public var jsonDecoder: @Sendable () -> JSONDecoder = { .init() } public var jsonDecoder: @Sendable () -> JSONDecoder = { .init() }
public var jsonEncoder: @Sendable () -> JSONEncoder = { .init() } public var jsonEncoder: @Sendable () -> JSONEncoder = { .init() }
public var tomlDecoder: @Sendable () -> TOMLDecoder = { .init() }
public var tomlEncoder: @Sendable () -> TOMLEncoder = { .init() }
} }
extension Coders: DependencyKey { extension Coders: DependencyKey {
public static var testValue: Coders { public static var testValue: Coders {
.init( .init(
jsonDecoder: { .init() }, jsonDecoder: { .init() },
jsonEncoder: { defaultJsonEncoder }, jsonEncoder: { defaultJsonEncoder }
tomlDecoder: { .init() },
tomlEncoder: { .init() }
) )
} }

View File

@@ -1,8 +1,5 @@
import CustomDump import CustomDump
import Foundation import Foundation
import TOMLKit
// TODO: Just use json for configuration ??
/// Represents configuration that can be set via a file, generally in the root of the /// Represents configuration that can be set via a file, generally in the root of the
/// project directory. /// project directory.
@@ -18,7 +15,7 @@ public struct Configuration: Codable, Equatable, Sendable {
public init( public init(
target: Target? = nil, target: Target? = nil,
strategy: VersionStrategy? = .init(semvar: .init()) strategy: VersionStrategy? = .semvar(.init())
) { ) {
self.target = target self.target = target
self.strategy = strategy self.strategy = strategy
@@ -27,39 +24,26 @@ public struct Configuration: Codable, Equatable, Sendable {
public static var mock: Self { public static var mock: Self {
.init( .init(
target: .init(module: .init("cli-version")), target: .init(module: .init("cli-version")),
strategy: .init() strategy: .semvar(.init())
) )
} }
public static var customPreRelease: Self { public static var customPreRelease: Self {
.init( .init(
target: .init(module: .init("cli-version")), target: .init(module: .init("cli-version")),
strategy: .init(semvar: .init( strategy: .semvar(.init(
preRelease: .customBranchPrefix("rc") preRelease: .init(prefix: "rc", strategy: .branch())
)) ))
) )
} }
} }
public struct Configuration2: Codable, Equatable, Sendable {
public let target: Configuration.Target?
public let strategy: Configuration.VersionStrategy2?
public static let mock = Self(
target: .init(module: .init("cli-version")),
strategy: .semvar(value: .init(preRelease: .init(
strategy: .branch()
)))
// strategy: .branch()
)
}
public extension Configuration { public extension Configuration {
/// Represents a branch version or pre-release strategy. /// Represents a branch version or pre-release strategy.
/// ///
/// This derives the version from the branch name and short version /// This derives the version or pre-release suffix from the branch name and
/// of the commit sha if configured. /// optionally the short version of the commit sha.
struct Branch: Codable, Equatable, Sendable { struct Branch: Codable, Equatable, Sendable {
/// Include the commit sha in the output for this strategy. /// Include the commit sha in the output for this strategy.
@@ -74,14 +58,19 @@ public extension Configuration {
} }
} }
struct PreRelease2: Codable, Equatable, Sendable { /// Represents version strategy for pre-release.
///
/// This appends a suffix to the version that get's generated from the version strategy.
/// For example: `1.0.0-rc-1`
///
struct PreRelease: Codable, Equatable, Sendable {
public let prefix: String? public let prefix: String?
public let strategy: Strategy public let strategy: Strategy?
public init( public init(
prefix: String? = nil, prefix: String? = nil,
strategy: Strategy strategy: Strategy? = nil
) { ) {
self.prefix = prefix self.prefix = prefix
self.strategy = strategy self.strategy = strategy
@@ -91,99 +80,12 @@ public extension Configuration {
case branch(includeCommitSha: Bool = true) case branch(includeCommitSha: Bool = true)
case command(arguments: [String]) case command(arguments: [String])
case gitTag case gitTag
}
}
/// Represents version strategy for pre-release. public var branch: Branch? {
/// guard case let .branch(includeCommitSha) = self
/// This appends a suffix to the version that get's generated from the version strategy. else { return nil }
/// For example: `1.0.0-rc-1` return .init(includeCommitSha: includeCommitSha)
///
struct PreReleaseStrategy: Codable, Equatable, Sendable, CustomDumpReflectable {
/// Use branch and commit sha as pre-release suffix.
public let branch: Branch?
/// Use a custom prefix string.
public let prefix: String?
/// An identifier for the type of pre-release.
public let style: StyleId
/// Whether we use `git describe --tags` for part of the suffix, this is only used
/// if we have a custom style.
public let usesGitTag: Bool?
init(
style: StyleId,
branch: Branch? = nil,
prefix: String? = nil,
usesGitTag: Bool = false
) {
self.branch = branch
self.prefix = prefix
self.style = style
self.usesGitTag = usesGitTag
}
public var customDumpMirror: Mirror {
guard let branch else {
return .init(
self,
children: [
"style": style,
"prefix": prefix as Any,
"usesGitTag": style == .gitTag ? true : (usesGitTag ?? false)
],
displayStyle: .struct
)
// return .init(reflecting: self)
} }
return .init(
self,
children: [
"style": style,
"branch": branch,
"prefix": prefix as Any
],
displayStyle: .struct
)
}
/// Represents a pre-release strategy that is derived from calling
/// `git describe --tags`.
public static let gitTag = Self(style: StyleId.gitTag)
/// Represents a pre-release strategy that is derived from the branch and commit sha.
public static func branch(_ branch: Branch = .init()) -> Self {
.init(style: .branch, branch: branch)
}
/// Represents a custom strategy that uses the given value, not deriving any other
/// data.
public static func custom(_ prefix: String) -> Self {
.init(style: .custom, prefix: prefix)
}
/// Represents a custom strategy that uses a prefix along with the branch and
/// commit sha.
public static func customBranchPrefix(
_ prefix: String,
branch: Branch = .init()
) -> Self {
.init(style: .custom, branch: branch, prefix: prefix)
}
/// Represents a custom strategy that uses a prefix along with the output from
/// calling `git describe --tags`.
public static func customGitTagPrefix(_ prefix: String) -> Self {
.init(style: StyleId.custom, prefix: prefix, usesGitTag: true)
}
public enum StyleId: String, Codable, Sendable {
case branch
case custom
case gitTag
} }
} }
@@ -194,7 +96,7 @@ public extension Configuration {
struct SemVar: Codable, Equatable, Sendable { struct SemVar: Codable, Equatable, Sendable {
/// Optional pre-releas suffix strategy. /// Optional pre-releas suffix strategy.
public let preRelease: PreReleaseStrategy? public let preRelease: PreRelease?
/// Fail if an existing version file does not exist in the target. /// Fail if an existing version file does not exist in the target.
public let requireExistingFile: Bool public let requireExistingFile: Bool
@@ -203,30 +105,7 @@ public extension Configuration {
public let requireExistingSemVar: Bool public let requireExistingSemVar: Bool
public init( public init(
preRelease: PreReleaseStrategy? = nil, preRelease: PreRelease? = nil,
requireExistingFile: Bool = true,
requireExistingSemVar: Bool = true
) {
self.preRelease = preRelease
self.requireExistingFile = requireExistingFile
self.requireExistingSemVar = requireExistingSemVar
}
}
struct SemVar2: Codable, Equatable, Sendable {
/// Optional pre-releas suffix strategy.
public let preRelease: PreRelease2?
/// Fail if an existing version file does not exist in the target.
public let requireExistingFile: Bool
/// Fail if an existing semvar is not parsed from the file or version generation strategy.
public let requireExistingSemVar: Bool
public init(
preRelease: PreRelease2? = nil,
requireExistingFile: Bool = true, requireExistingFile: Bool = true,
requireExistingSemVar: Bool = true requireExistingSemVar: Bool = true
) { ) {
@@ -313,75 +192,57 @@ public extension Configuration {
} }
} }
enum VersionStrategy2: Codable, Equatable, Sendable { /// Strategy used to generate a version.
///
/// Typically a `SemVar` strategy or `Branch`.
///
///
enum VersionStrategy: Codable, Equatable, Sendable, CustomDumpReflectable {
case branch(includeCommitSha: Bool = true) case branch(includeCommitSha: Bool = true)
case semvar( case semvar(
preRelease: PreRelease2? = nil, preRelease: PreRelease? = nil,
requireExistingFile: Bool? = nil, requireExistingFile: Bool? = nil,
requireExistingSemVar: Bool? = nil requireExistingSemVar: Bool? = nil
) )
static func semvar(value: SemVar2) -> Self { public var branch: Branch? {
guard case let .branch(includeCommitSha) = self
else { return nil }
return .init(includeCommitSha: includeCommitSha)
}
public var semvar: SemVar? {
guard case let .semvar(preRelease, requireExistingFile, requireExistingSemVar) = self
else { return nil }
return .init(
preRelease: preRelease,
requireExistingFile: requireExistingFile ?? false,
requireExistingSemVar: requireExistingSemVar ?? false
)
}
public static func branch(_ branch: Branch) -> Self {
.branch(includeCommitSha: branch.includeCommitSha)
}
public static func semvar(_ value: SemVar) -> Self {
.semvar( .semvar(
preRelease: value.preRelease, preRelease: value.preRelease,
requireExistingFile: value.requireExistingFile, requireExistingFile: value.requireExistingFile,
requireExistingSemVar: value.requireExistingSemVar requireExistingSemVar: value.requireExistingSemVar
) )
} }
}
/// Strategy used to generate a version.
///
/// Typically a `SemVar` strategy or `Branch`.
///
///
struct VersionStrategy: Codable, Equatable, Sendable, CustomDumpReflectable {
/// Set if we're using the branch and commit sha to derive the version.
public let branch: Branch?
/// Set if we're using semvar to derive the version.
public let semvar: SemVar?
/// Create a new version strategy that uses branch and commit sha to derive the version.
///
/// - Parameters:
/// - branch: The branch strategy options.
public init(branch: Branch) {
self.branch = branch
self.semvar = nil
}
/// Create a new version strategy that uses semvar to derive the version.
///
/// - Parameters:
/// - semvar: The semvar strategy options.
public init(semvar: SemVar = .init()) {
self.branch = nil
self.semvar = semvar
}
public var customDumpMirror: Mirror { public var customDumpMirror: Mirror {
if let branch { switch self {
return .init( case .branch:
self, return .init(self, children: ["branch": branch!], displayStyle: .struct)
children: [ case .semvar:
"branch": branch return .init(self, children: ["semvar": semvar!], displayStyle: .struct)
],
displayStyle: .struct
)
} else if let semvar {
return .init(
self,
children: [
"semvar": semvar
],
displayStyle: .struct
)
} else {
return .init(reflecting: self)
} }
} }
} }
} }

View File

@@ -17,20 +17,20 @@ public extension DependencyValues {
public struct ConfigurationClient: Sendable { public struct ConfigurationClient: Sendable {
/// Find a configuration file in the given directory or in current working directory. /// Find a configuration file in the given directory or in current working directory.
public var find: @Sendable (URL?) async throws -> ConfigurationFile? public var find: @Sendable (URL?) async throws -> URL?
/// Load a configuration file. /// Load a configuration file.
public var load: @Sendable (ConfigurationFile) async throws -> Configuration public var load: @Sendable (URL) async throws -> Configuration
/// Write a configuration file. /// Write a configuration file.
public var write: @Sendable (Configuration, ConfigurationFile) async throws -> Void public var write: @Sendable (Configuration, URL) async throws -> Void
/// Find a configuration file and load it if found. /// Find a configuration file and load it if found.
public func findAndLoad(_ url: URL? = nil) async throws -> Configuration { public func findAndLoad(_ url: URL? = nil) async throws -> Configuration {
guard let url = try await find(url) else { guard let url = try? await find(url) else {
throw ConfigurationClientError.configurationNotFound throw ConfigurationClientError.configurationNotFound
} }
return try await load(url) return (try? await load(url)) ?? .mock
} }
} }
@@ -40,49 +40,48 @@ extension ConfigurationClient: DependencyKey {
public static var liveValue: ConfigurationClient { public static var liveValue: ConfigurationClient {
.init( .init(
find: { try await findConfiguration($0) }, find: { try await findConfiguration($0) },
load: { try await $0.load() ?? .mock }, load: { try await loadConfiguration($0) },
write: { try await $1.write($0) } write: { try await writeConfiguration($0, to: $1) }
) )
} }
} }
private func findConfiguration(_ url: URL?) async throws -> ConfigurationFile? { private func findConfiguration(_ url: URL?) async throws -> URL? {
@Dependency(\.fileClient) var fileClient @Dependency(\.fileClient) var fileClient
let defaultFileName = ConfigurationClient.Constants.defaultFileNameWithoutExtension
var url: URL! = url var url: URL! = url
if url == nil { if url == nil {
url = try await URL(filePath: fileClient.currentDirectory()) url = try await URL(filePath: fileClient.currentDirectory())
} }
// Check if url is a valid configuration url. if try await fileClient.isDirectory(url.cleanFilePath) {
var configurationFile = ConfigurationFile(url: url) url = url.appending(path: "\(defaultFileName).json")
if let configurationFile, fileClient.fileExists(configurationFile.url) {
return configurationFile
} }
guard try await fileClient.isDirectory(url.cleanFilePath) else { if fileClient.fileExists(url) {
throw ConfigurationClientError.invalidConfigurationDirectory(path: url.cleanFilePath) return url
} }
// Check for toml file.
let tomlUrl = url.appending(path: "\(ConfigurationClient.Constants.defaultFileNameWithoutExtension).toml")
configurationFile = ConfigurationFile(url: tomlUrl)
if let configurationFile, fileClient.fileExists(configurationFile.url) {
return configurationFile
}
// Check for json file.
let jsonUrl = url.appending(path: "\(ConfigurationClient.Constants.defaultFileNameWithoutExtension).json")
configurationFile = ConfigurationFile(url: jsonUrl)
if let configurationFile, fileClient.fileExists(configurationFile.url) {
return configurationFile
}
// Couldn't find valid configuration file.
return nil return nil
} }
private func loadConfiguration(_ url: URL) async throws -> Configuration {
@Dependency(\.coders.jsonDecoder) var jsonDecoder
@Dependency(\.fileClient) var fileClient
let string = try await fileClient.read(url.cleanFilePath)
return try jsonDecoder().decode(Configuration.self, from: Data(string.utf8))
}
enum ConfigurationClientError: Error { enum ConfigurationClientError: Error {
case configurationNotFound case configurationNotFound
case invalidConfigurationDirectory(path: String) case invalidConfigurationDirectory(path: String)
} }
private func writeConfiguration(_ configuration: Configuration, to url: URL) async throws {
@Dependency(\.fileClient) var fileClient
@Dependency(\.coders.jsonEncoder) var jsonEncoder
let data = try jsonEncoder().encode(configuration)
try await fileClient.write(data, url)
}

View File

@@ -1,76 +0,0 @@
import Dependencies
import FileClient
import Foundation
/// Represents a configuration file type and location.
public enum ConfigurationFile: Equatable, Sendable {
/// A json configuration file.
case json(URL)
/// A toml configuration file.
case toml(URL)
/// Default configuration file, which is a toml file
/// with the name of '.bump-version.toml'
public static var `default`: Self {
.toml(URL(
filePath: "\(ConfigurationClient.Constants.defaultFileNameWithoutExtension).toml"
))
}
/// Create a new file location from the given url.
///
/// - Parameters:
/// - url: The url for the file.
public init?(url: URL) {
if url.pathExtension == "toml" {
self = .toml(url)
} else if url.pathExtension == "json" {
self = .json(url)
} else {
return nil
}
}
/// The url of the file.
public var url: URL {
switch self {
case let .json(url): return url
case let .toml(url): return url
}
}
}
extension ConfigurationFile {
func load() async throws -> Configuration? {
@Dependency(\.coders) var coders
@Dependency(\.fileClient) var fileClient
switch self {
case .json:
let data = try await Data(fileClient.read(url.cleanFilePath).utf8)
return try? coders.jsonDecoder().decode(Configuration.self, from: data)
case .toml:
let string = try await fileClient.read(url.cleanFilePath)
return try? coders.tomlDecoder().decode(Configuration.self, from: string)
}
}
func write(_ configuration: Configuration) async throws {
@Dependency(\.coders) var coders
@Dependency(\.fileClient) var fileClient
let data: Data
switch self {
case .json:
data = try coders.jsonEncoder().encode(configuration)
case .toml:
data = try Data(coders.tomlEncoder().encode(configuration).utf8)
}
try await fileClient.write(data, url)
}
}

View File

@@ -40,9 +40,9 @@ extension Configuration.VersionStrategy {
func merging(_ other: Self?) -> Self { func merging(_ other: Self?) -> Self {
guard let branch else { guard let branch else {
guard let semvar else { return self } guard let semvar else { return self }
return .init(semvar: semvar.merging(other?.semvar)) return .semvar(semvar.merging(other?.semvar))
} }
return .init(branch: branch.merging(other?.branch)) return .branch(branch.merging(other?.branch))
} }
} }

View File

@@ -111,7 +111,7 @@ typealias GlobalBranchOptions = GlobalOptions<Empty>
extension GlobalSemVarOptions { extension GlobalSemVarOptions {
func shared() async throws -> CliClient.SharedOptions { func shared() async throws -> CliClient.SharedOptions {
try await withConfiguration(path: configurationFile) { configuration in try await withConfiguration(path: configurationFile) { configuration in
try shared(configuration.mergingStrategy(.init(semvar: child.configSemVarOptions()))) try shared(configuration.mergingStrategy(.semvar(child.configSemVarOptions())))
} }
} }
} }
@@ -119,7 +119,7 @@ extension GlobalSemVarOptions {
extension GlobalBranchOptions { extension GlobalBranchOptions {
func shared() async throws -> CliClient.SharedOptions { func shared() async throws -> CliClient.SharedOptions {
try await withConfiguration(path: configurationFile) { configuration in try await withConfiguration(path: configurationFile) { configuration in
try shared(configuration.mergingStrategy(.init(branch: .init()))) try shared(configuration.mergingStrategy(.branch()))
} }
} }
} }
@@ -197,24 +197,26 @@ private extension TargetOptions {
extension PreReleaseOptions { extension PreReleaseOptions {
func configPreReleaseStrategy() throws -> Configuration.PreReleaseStrategy? { // FIX:
guard let custom else { func configPreReleaseStrategy() throws -> Configuration.PreRelease? {
if useBranchAsPreRelease { return nil
return .branch() // guard let custom else {
} else if useTagAsPreRelease { // if useBranchAsPreRelease {
return .gitTag // return .branch()
} else { // } else if useTagAsPreRelease {
return nil // return .gitTag
} // } else {
} // return nil
// }
if useBranchAsPreRelease { // }
return .customBranchPrefix(custom) //
} else if useTagAsPreRelease { // if useBranchAsPreRelease {
return .customGitTagPrefix(custom) // return .customBranchPrefix(custom)
} else { // } else if useTagAsPreRelease {
return .custom(custom) // return .customGitTagPrefix(custom)
} // } else {
// return .custom(custom)
// }
} }
} }

View File

@@ -21,7 +21,7 @@ struct CliClientTests {
@Dependency(\.cliClient) var client @Dependency(\.cliClient) var client
let output = try await client.build(.testOptions( let output = try await client.build(.testOptions(
target: target, target: target,
versionStrategy: .init(semvar: .init(requireExistingFile: false)) versionStrategy: .semvar(requireExistingFile: false)
)) ))
#expect(output == "/baz/Sources/bar/Version.swift") #expect(output == "/baz/Sources/bar/Version.swift")
} }
@@ -66,7 +66,7 @@ struct CliClientTests {
@Dependency(\.cliClient) var client @Dependency(\.cliClient) var client
let output = try await client.build(.testOptions( let output = try await client.build(.testOptions(
target: target, target: target,
versionStrategy: .init(semvar: .init(requireExistingFile: false)) versionStrategy: .semvar(requireExistingFile: false)
)) ))
#expect(output == "/baz/Sources/bar/Version.swift") #expect(output == "/baz/Sources/bar/Version.swift")
} }
@@ -131,7 +131,7 @@ extension CliClient.SharedOptions {
dryRun: Bool = false, dryRun: Bool = false,
target: String = "bar", target: String = "bar",
logLevel: Logger.Level = .trace, logLevel: Logger.Level = .trace,
versionStrategy: Configuration.VersionStrategy = .init(semvar: .init()) versionStrategy: Configuration.VersionStrategy = .semvar(.init())
) -> Self { ) -> Self {
.init( .init(
dryRun: dryRun, dryRun: dryRun,

View File

@@ -3,7 +3,6 @@ import Dependencies
import Foundation import Foundation
import Testing import Testing
import TestSupport import TestSupport
import TOMLKit
@Suite("ConfigurationClientTests") @Suite("ConfigurationClientTests")
struct ConfigurationClientTests { struct ConfigurationClientTests {
@@ -19,28 +18,6 @@ struct ConfigurationClientTests {
let decoded = try coders.jsonDecoder().decode(Configuration.self, from: encoded) let decoded = try coders.jsonDecoder().decode(Configuration.self, from: encoded)
#expect(decoded == configuration) #expect(decoded == configuration)
let tomlEncoded = try coders.tomlEncoder().encode(configuration)
let tomlDecoded = try coders.tomlDecoder().decode(
Configuration.self,
from: tomlEncoded
)
#expect(tomlDecoded == configuration)
}
}
@Test(arguments: ["foo", ".foo"])
func configurationFile(fileName: String) {
for ext in ["toml", "json", "bar"] {
let file = ConfigurationFile(url: URL(filePath: "\(fileName).\(ext)"))
switch ext {
case "toml":
#expect(file == .toml(URL(filePath: "\(fileName).toml")))
case "json":
#expect(file == .json(URL(filePath: "\(fileName).json")))
default:
#expect(file == nil)
}
} }
} }
@@ -50,16 +27,15 @@ struct ConfigurationClientTests {
try await run { try await run {
@Dependency(\.configurationClient) var configurationClient @Dependency(\.configurationClient) var configurationClient
for ext in ["toml", "json"] { for ext in ["json"] {
let fileUrl = url.appending(path: "test.\(ext)") let fileUrl = url.appending(path: "test.\(ext)")
let configuration = Configuration.mock let configuration = Configuration.mock
let configurationFile = ConfigurationFile(url: fileUrl)!
try await configurationClient.write(configuration, configurationFile) try await configurationClient.write(configuration, fileUrl)
let loaded = try await configurationClient.load(configurationFile) let loaded = try await configurationClient.load(fileUrl)
#expect(loaded == configuration) #expect(loaded == configuration)
let findAndLoaded = try await configurationClient.findAndLoad(configurationFile.url) let findAndLoaded = try await configurationClient.findAndLoad(fileUrl)
#expect(findAndLoaded == configuration) #expect(findAndLoaded == configuration)
try FileManager.default.removeItem(at: fileUrl) try FileManager.default.removeItem(at: fileUrl)
@@ -84,13 +60,12 @@ struct ConfigurationClientTests {
#expect(Bool(true)) #expect(Bool(true))
} }
for ext in ["toml", "json"] { for ext in ["json"] {
let fileUrl = url.appending(path: ".bump-version.\(ext)") let fileUrl = url.appending(path: ".bump-version.\(ext)")
let configuration = Configuration.mock let configuration = Configuration.mock
let configurationFile = ConfigurationFile(url: fileUrl)!
try await configurationClient.write(configuration, configurationFile) try await configurationClient.write(configuration, fileUrl)
let loaded = try await configurationClient.findAndLoad(url) let loaded = try await configurationClient.findAndLoad(fileUrl)
#expect(loaded == configuration) #expect(loaded == configuration)
try FileManager.default.removeItem(at: fileUrl) try FileManager.default.removeItem(at: fileUrl)