diff --git a/Sources/CliClient/Internal/CliClient+run.swift b/Sources/CliClient/Internal/CliClient+run.swift index 2a93b4c..945352a 100644 --- a/Sources/CliClient/Internal/CliClient+run.swift +++ b/Sources/CliClient/Internal/CliClient+run.swift @@ -96,45 +96,6 @@ public extension CliClient.SharedOptions { } } -// TODO: Add optional property for currentVersion (loaded version from file) -// and rename version to nextVersion. - -@_spi(Internal) -public struct CurrentVersionContainer: Sendable { - - let targetUrl: URL - let currentVersion: CurrentVersion? - let version: Version - - var usesOptionalType: Bool { - switch version { - case .string: return false - case let .semvar(_, usesOptionalType, _): return usesOptionalType - } - } - - public enum CurrentVersion: Sendable { - case branch(String, usesOptionalType: Bool) - case semvar(SemVar, usesOptionalType: Bool) - } - - public enum Version: Sendable { - // TODO: Call this branch for consistency. - case string(String) - // TODO: Remove has changes when currentVersion/nextVersion is implemented. - case semvar(SemVar, usesOptionalType: Bool = true, hasChanges: Bool) - - func string(allowPreReleaseTag: Bool) throws -> String { - switch self { - case let .string(string): - return string - case let .semvar(semvar, usesOptionalType: _, hasChanges: _): - return semvar.versionString(withPreReleaseTag: allowPreReleaseTag) - } - } - } -} - extension CliClient.SharedOptions { func build(_ environment: [String: String]) async throws -> String { diff --git a/Sources/CliClient/Internal/ConfigurationExtensions.swift b/Sources/CliClient/Internal/ConfigurationExtensions.swift index 85263b2..6871fa5 100644 --- a/Sources/CliClient/Internal/ConfigurationExtensions.swift +++ b/Sources/CliClient/Internal/ConfigurationExtensions.swift @@ -1,4 +1,5 @@ import ConfigurationClient +import CustomDump import Dependencies import Foundation import GitClient @@ -119,6 +120,38 @@ public extension Configuration.SemVar { } } +extension Configuration.VersionStrategy { + + func loadNextVersion(gitDirectory: String?) async throws -> CurrentVersionContainer.Version { + @Dependency(\.gitClient) var gitClient + @Dependency(\.logger) var logger + + switch self { + case let .branch(includeCommitSha: includeCommitSha): + logger.trace("Loading next version for branch strategy...") + let next = try await gitClient.version(includeCommitSha: includeCommitSha, gitDirectory: gitDirectory) + logger.trace("Next version: \(next)") + return .string(next) + case .semvar: + logger.trace("Loading next version for semvar strategy...") + let semvar = semvar! + guard let strategy = semvar.strategy else { + // TODO: Error here. + fatalError() + } + let next = try await strategy.getSemvar(gitDirectory: gitDirectory) + var nextString = "" + customDump(next, to: &nextString) + logger.trace("Next version:\n\(nextString)") + + // TODO: Need to check for pre-release and load it here. + + // TODO: Fix optional type / has changes. + return .semvar(next, usesOptionalType: true, hasChanges: true) + } + } +} + private extension Configuration.VersionStrategy { // TODO: This should just load the `nextVersion`, and should probably live on CurrentVersionContainer. @@ -246,6 +279,7 @@ private extension Configuration.PreRelease { private extension Configuration.SemVar { + // TODO: Move this to SemVar, not Configuration.SemVar func applyingPreRelease(_ semvar: SemVar, _ gitDirectory: String?) async throws -> SemVar { @Dependency(\.logger) var logger logger.trace("Start apply pre-release to: \(semvar)") diff --git a/Sources/CliClient/Internal/CurrentVersionContainer.swift b/Sources/CliClient/Internal/CurrentVersionContainer.swift new file mode 100644 index 0000000..d025604 --- /dev/null +++ b/Sources/CliClient/Internal/CurrentVersionContainer.swift @@ -0,0 +1,103 @@ +import ConfigurationClient +import CustomDump +import Dependencies +import FileClient +import Foundation + +// TODO: Add optional property for currentVersion (loaded version from file) +// and rename version to nextVersion. + +/// An internal type that holds onto the loaded version from a file (if found), +/// the computed next version, and the target file url. +/// +@_spi(Internal) +public struct CurrentVersionContainer: Sendable { + + let targetUrl: URL + let currentVersion: CurrentVersion? + let version: Version + + // TODO: Derive from current version. + var usesOptionalType: Bool { + switch version { + case .string: return false + case let .semvar(_, usesOptionalType, _): return usesOptionalType + } + } + + var hasChanges: Bool { + guard let currentVersion else { return false } + switch (currentVersion, version) { + case let (.branch(currentString, _), .string(nextString)): + return currentString == nextString + case let (.semvar(currentSemvar, _), .semvar(nextSemvar, _, _)): + return currentSemvar == nextSemvar + // TODO: What to do with mis-matched values. + case (.branch, .semvar), + (.semvar, .string): + return true + } + } + + public enum CurrentVersion: Sendable { + case branch(String, usesOptionalType: Bool) + case semvar(SemVar, usesOptionalType: Bool) + } + + public enum Version: Sendable { + // TODO: Call this branch for consistency. + case string(String) + // TODO: Remove has changes when currentVersion/nextVersion is implemented. + case semvar(SemVar, usesOptionalType: Bool = true, hasChanges: Bool) + + func string(allowPreReleaseTag: Bool) throws -> String { + switch self { + case let .string(string): + return string + case let .semvar(semvar, usesOptionalType: _, hasChanges: _): + return semvar.versionString(withPreReleaseTag: allowPreReleaseTag) + } + } + } +} + +extension CurrentVersionContainer { + + static func load( + configuration: Configuration, + sharedOptions: CliClient.SharedOptions + ) async throws -> Self { + @Dependency(\.fileClient) var fileClient + @Dependency(\.logger) var logger + + let targetUrl = try configuration.targetUrl(gitDirectory: sharedOptions.projectDirectory) + logger.trace("Begin loading current version from: \(targetUrl.cleanFilePath)") + + let currentVersion = try await fileClient.loadCurrentVersion( + url: targetUrl, + gitDirectory: sharedOptions.projectDirectory, + expectsBranch: configuration.strategy?.branch != nil + ) + var currentVersionString = "" + customDump(currentVersion, to: ¤tVersionString) + logger.trace("Loaded current version:\n\(currentVersionString)") + + if configuration.strategy?.semvar?.requireExistingFile == true { + guard currentVersion != nil else { + // TODO: Better error. + throw CliClientError.semVarNotFound + } + } + + // Check that there's a valid strategy to get the next version. + guard let strategy = configuration.strategy else { + // TODO: Return without a next version here when nextVersion is optional. + fatalError() + } + + // TODO: make optional? + let next = try await strategy.loadNextVersion(gitDirectory: sharedOptions.projectDirectory) + + fatalError() + } +} diff --git a/gum b/gum new file mode 100644 index 0000000..a688463 --- /dev/null +++ b/gum @@ -0,0 +1 @@ +foo,bar,baz table