feat: Prep to update current version container in cli-client.

This commit is contained in:
2024-12-28 10:09:34 -05:00
parent b9cf913528
commit 6fe459c39e
4 changed files with 138 additions and 39 deletions

View File

@@ -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 {

View File

@@ -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)")

View File

@@ -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: &currentVersionString)
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()
}
}

1
gum Normal file
View File

@@ -0,0 +1 @@
foo,bar,baz table