feat: Moves logging setup and generate-json for the create command to cli-client module.
This commit is contained in:
@@ -23,7 +23,11 @@ public extension CliClient {
|
|||||||
try await runCommand(quiet: quiet, shell: shell, args)
|
try await runCommand(quiet: quiet, shell: shell, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runPlaybookCommand(_ options: PlaybookOptions) async throws {
|
func runPlaybookCommand(
|
||||||
|
_ options: PlaybookOptions,
|
||||||
|
logging loggingOptions: LoggingOptions
|
||||||
|
) async throws {
|
||||||
|
try await withLogger(loggingOptions) {
|
||||||
@Dependency(\.configurationClient) var configurationClient
|
@Dependency(\.configurationClient) var configurationClient
|
||||||
@Dependency(\.logger) var logger
|
@Dependency(\.logger) var logger
|
||||||
|
|
||||||
@@ -62,8 +66,13 @@ public extension CliClient {
|
|||||||
arguments
|
arguments
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func runVaultCommand(_ options: VaultOptions) async throws {
|
func runVaultCommand(
|
||||||
|
_ options: VaultOptions,
|
||||||
|
logging loggingOptions: LoggingOptions
|
||||||
|
) async throws {
|
||||||
|
try await withLogger(loggingOptions) {
|
||||||
@Dependency(\.configurationClient) var configurationClient
|
@Dependency(\.configurationClient) var configurationClient
|
||||||
@Dependency(\.fileClient) var fileClient
|
@Dependency(\.fileClient) var fileClient
|
||||||
@Dependency(\.logger) var logger
|
@Dependency(\.logger) var logger
|
||||||
@@ -99,6 +108,7 @@ public extension CliClient {
|
|||||||
arguments
|
arguments
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@_spi(Internal)
|
@_spi(Internal)
|
||||||
@@ -162,9 +172,4 @@ public extension FileClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CliClientError: Error {
|
|
||||||
case playbookDirectoryNotFound
|
|
||||||
case vaultFileNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ShellCommand.Shell: @retroactive @unchecked Sendable {}
|
extension ShellCommand.Shell: @retroactive @unchecked Sendable {}
|
||||||
|
|||||||
9
Sources/CliClient/CliClientError.swift
Normal file
9
Sources/CliClient/CliClientError.swift
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
public enum CliClientError: Error {
|
||||||
|
case encodingError
|
||||||
|
case playbookDirectoryNotFound
|
||||||
|
case templateDirectoryNotFound
|
||||||
|
case templateDirectoryOrRepoNotSpecified
|
||||||
|
case vaultFileNotFound
|
||||||
|
}
|
||||||
80
Sources/CliClient/GenerateJson.swift
Normal file
80
Sources/CliClient/GenerateJson.swift
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import ConfigurationClient
|
||||||
|
import Dependencies
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
// NOTE: We're not using the `Coders` client because we generally do not
|
||||||
|
// want the output to be `prettyPrinted` or anything, unless we're running
|
||||||
|
// tests, so we use a supplied json encoder.
|
||||||
|
|
||||||
|
func createJSONData(
|
||||||
|
_ options: CliClient.GenerateJsonOptions,
|
||||||
|
logging loggingOptions: CliClient.LoggingOptions,
|
||||||
|
encoder: JSONEncoder = .init()
|
||||||
|
) async throws -> Data {
|
||||||
|
try await CliClient.withLogger(loggingOptions) {
|
||||||
|
@Dependency(\.logger) var logger
|
||||||
|
@Dependency(\.configurationClient) var configurationClient
|
||||||
|
|
||||||
|
let configuration = try await configurationClient.findAndLoad()
|
||||||
|
|
||||||
|
let templateDir = options.templateDirectory ?? configuration.template.directory
|
||||||
|
let templateRepo = options.templateRepo ?? configuration.template.url
|
||||||
|
let version = options.version ?? configuration.template.version
|
||||||
|
|
||||||
|
logger.debug("""
|
||||||
|
(\(options.useLocalTemplateDirectory), \(String(describing: templateDir)), \(String(describing: templateRepo)))
|
||||||
|
""")
|
||||||
|
|
||||||
|
switch (options.useLocalTemplateDirectory, templateDir, templateRepo) {
|
||||||
|
case (true, .none, _):
|
||||||
|
// User supplied they wanted to use a local template directory, but we could not find
|
||||||
|
// the path set from command line or in configuration.
|
||||||
|
throw CliClientError.templateDirectoryNotFound
|
||||||
|
case let (false, _, .some(repo)):
|
||||||
|
// User did not supply they wanted to use a local template directory, and we found a repo url that was
|
||||||
|
// either set by the command line or found in the configuration.
|
||||||
|
logger.debug("Using repo.")
|
||||||
|
return try encoder.encode(TemplateRepo(repo: repo, version: version))
|
||||||
|
case let (true, .some(templateDir), _):
|
||||||
|
// User supplied they wanted to use a local template directory, and we found the template directory
|
||||||
|
// either set by the command line or in the configuration.
|
||||||
|
logger.debug("Using template directory.")
|
||||||
|
return try encoder.encode(TemplateDirJson(path: templateDir))
|
||||||
|
case let (false, .some(templateDir), _):
|
||||||
|
// User supplied they did not wanted to use a local template directory, and we found the template directory
|
||||||
|
// either set by the command line or in the configuration, and no repo was found / handled previously.
|
||||||
|
logger.debug("Using template directory.")
|
||||||
|
return try encoder.encode(TemplateDirJson(path: templateDir))
|
||||||
|
case (_, .none, .none):
|
||||||
|
// We could not find a repo or template directory.
|
||||||
|
throw CliClientError.templateDirectoryOrRepoNotSpecified
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct TemplateDirJson: Encodable {
|
||||||
|
|
||||||
|
let template: Template
|
||||||
|
|
||||||
|
init(path: String) {
|
||||||
|
self.template = .init(path: path)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Template: Encodable {
|
||||||
|
let path: String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct TemplateRepo: Encodable {
|
||||||
|
|
||||||
|
let template: Template
|
||||||
|
|
||||||
|
init(repo: String, version: String?) {
|
||||||
|
self.template = .init(repo: repo, version: version ?? "main")
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Template: Encodable {
|
||||||
|
let repo: String
|
||||||
|
let version: String
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,9 +4,6 @@ import DependenciesMacros
|
|||||||
import Foundation
|
import Foundation
|
||||||
import ShellClient
|
import ShellClient
|
||||||
|
|
||||||
// TODO: Add logging options and setup in this module and remove from the
|
|
||||||
// executable `hpa` module.
|
|
||||||
|
|
||||||
public extension DependencyValues {
|
public extension DependencyValues {
|
||||||
var cliClient: CliClient {
|
var cliClient: CliClient {
|
||||||
get { self[CliClient.self] }
|
get { self[CliClient.self] }
|
||||||
@@ -16,11 +13,49 @@ public extension DependencyValues {
|
|||||||
|
|
||||||
@DependencyClient
|
@DependencyClient
|
||||||
public struct CliClient: Sendable {
|
public struct CliClient: Sendable {
|
||||||
|
|
||||||
public var runCommand: @Sendable (RunCommandOptions) async throws -> Void
|
public var runCommand: @Sendable (RunCommandOptions) async throws -> Void
|
||||||
|
public var generateJSON: @Sendable (GenerateJsonOptions, LoggingOptions, JSONEncoder) async throws -> String
|
||||||
|
|
||||||
|
public func generateJSON(
|
||||||
|
_ options: GenerateJsonOptions,
|
||||||
|
logging loggingOptions: LoggingOptions,
|
||||||
|
encoder jsonEncoder: JSONEncoder = .init()
|
||||||
|
) async throws -> String {
|
||||||
|
try await generateJSON(options, loggingOptions, jsonEncoder)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension CliClient {
|
public extension CliClient {
|
||||||
|
|
||||||
|
struct GenerateJsonOptions: Equatable, Sendable {
|
||||||
|
let templateDirectory: String?
|
||||||
|
let templateRepo: String?
|
||||||
|
let version: String?
|
||||||
|
let useLocalTemplateDirectory: Bool
|
||||||
|
|
||||||
|
public init(
|
||||||
|
templateDirectory: String?,
|
||||||
|
templateRepo: String?,
|
||||||
|
version: String?,
|
||||||
|
useLocalTemplateDirectory: Bool
|
||||||
|
) {
|
||||||
|
self.templateDirectory = templateDirectory
|
||||||
|
self.templateRepo = templateRepo
|
||||||
|
self.version = version
|
||||||
|
self.useLocalTemplateDirectory = useLocalTemplateDirectory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LoggingOptions: Equatable, Sendable {
|
||||||
|
let commandName: String
|
||||||
|
let logLevel: Logger.Level
|
||||||
|
|
||||||
|
public init(commandName: String, logLevel: Logger.Level) {
|
||||||
|
self.commandName = commandName
|
||||||
|
self.logLevel = logLevel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct PlaybookOptions: Sendable, Equatable {
|
struct PlaybookOptions: Sendable, Equatable {
|
||||||
let arguments: [String]
|
let arguments: [String]
|
||||||
let configuration: Configuration?
|
let configuration: Configuration?
|
||||||
@@ -109,6 +144,12 @@ extension CliClient: DependencyKey {
|
|||||||
options.arguments
|
options.arguments
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
} generateJSON: { options, loggingOptions, encoder in
|
||||||
|
let data = try await createJSONData(options, logging: loggingOptions, encoder: encoder)
|
||||||
|
guard let string = String(data: data, encoding: .utf8) else {
|
||||||
|
throw CliClientError.encodingError
|
||||||
|
}
|
||||||
|
return string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,6 +162,8 @@ extension CliClient: DependencyKey {
|
|||||||
public static func capturing(_ client: CapturingClient) -> Self {
|
public static func capturing(_ client: CapturingClient) -> Self {
|
||||||
.init { options in
|
.init { options in
|
||||||
await client.set(options)
|
await client.set(options)
|
||||||
|
} generateJSON: {
|
||||||
|
try await Self().generateJSON($0, $1, $2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
28
Sources/CliClient/LoggingExtensions.swift
Normal file
28
Sources/CliClient/LoggingExtensions.swift
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import Dependencies
|
||||||
|
import Logging
|
||||||
|
import ShellClient
|
||||||
|
|
||||||
|
public extension CliClient {
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
func withLogger<T>(
|
||||||
|
_ options: LoggingOptions,
|
||||||
|
operation: @Sendable @escaping () async throws -> T
|
||||||
|
) async rethrows -> T {
|
||||||
|
try await Self.withLogger(options, operation: operation)
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
static func withLogger<T>(
|
||||||
|
_ options: LoggingOptions,
|
||||||
|
operation: @Sendable @escaping () async throws -> T
|
||||||
|
) async rethrows -> T {
|
||||||
|
try await withDependencies {
|
||||||
|
$0.logger = .init(label: "\(Constants.executableName)")
|
||||||
|
$0.logger.logLevel = options.logLevel
|
||||||
|
$0.logger[metadataKey: "command"] = "\(options.commandName.blue)"
|
||||||
|
} operation: {
|
||||||
|
try await operation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,18 +38,17 @@ struct BuildCommand: AsyncParsableCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func _run() async throws {
|
private func _run() async throws {
|
||||||
try await withSetupLogger(commandName: Self.commandName, globals: globals) {
|
|
||||||
@Dependency(\.cliClient) var cliClient
|
@Dependency(\.cliClient) var cliClient
|
||||||
|
|
||||||
try await cliClient.runPlaybookCommand(
|
try await cliClient.runPlaybookCommand(
|
||||||
globals.playbookOptions(
|
globals.playbookOptions(
|
||||||
arguments: [
|
arguments: [
|
||||||
"--tags", "build-project",
|
"--tags", "build-project",
|
||||||
"--extra-vars", "project_dir=\(self.projectDir)"
|
"--extra-vars", "project_dir=\(projectDir)"
|
||||||
],
|
],
|
||||||
configuration: nil
|
configuration: nil
|
||||||
|
),
|
||||||
|
logging: globals.loggingOptions(commandName: Self.commandName)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,126 +61,46 @@ struct CreateCommand: AsyncParsableCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func _run() async throws {
|
private func _run() async throws {
|
||||||
try await withSetupLogger(commandName: Self.commandName, globals: globals) {
|
|
||||||
@Dependency(\.coders) var coders
|
@Dependency(\.coders) var coders
|
||||||
@Dependency(\.cliClient) var cliClient
|
@Dependency(\.cliClient) var cliClient
|
||||||
@Dependency(\.configurationClient) var configurationClient
|
@Dependency(\.configurationClient) var configurationClient
|
||||||
|
|
||||||
|
let loggingOptions = globals.loggingOptions(commandName: Self.commandName)
|
||||||
|
|
||||||
|
try await cliClient.withLogger(loggingOptions) {
|
||||||
@Dependency(\.logger) var logger
|
@Dependency(\.logger) var logger
|
||||||
|
|
||||||
let encoder = coders.jsonEncoder()
|
let json = try await cliClient.generateJSON(
|
||||||
|
generateJsonOptions,
|
||||||
let configuration = try await configurationClient.findAndLoad()
|
logging: loggingOptions
|
||||||
|
|
||||||
logger.debug("Configuration: \(configuration)")
|
|
||||||
|
|
||||||
let jsonData = try parseOptions(
|
|
||||||
command: self,
|
|
||||||
configuration: configuration,
|
|
||||||
logger: logger,
|
|
||||||
encoder: encoder
|
|
||||||
)
|
)
|
||||||
|
|
||||||
guard let jsonString = String(data: jsonData, encoding: .utf8) else {
|
logger.debug("JSON string: \(json)")
|
||||||
throw CreateError.encodingError
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug("JSON string: \(jsonString)")
|
|
||||||
|
|
||||||
let arguments = [
|
let arguments = [
|
||||||
"--tags", "setup-project",
|
"--tags", "setup-project",
|
||||||
"--extra-vars", "project_dir=\(self.projectDir)",
|
"--extra-vars", "project_dir=\(self.projectDir)",
|
||||||
"--extra-vars", "'\(jsonString)'"
|
"--extra-vars", "'\(json)'"
|
||||||
] + extraArgs
|
] + extraArgs
|
||||||
|
|
||||||
try await cliClient.runPlaybookCommand(
|
try await cliClient.runPlaybookCommand(
|
||||||
globals.playbookOptions(
|
globals.playbookOptions(
|
||||||
arguments: arguments,
|
arguments: arguments,
|
||||||
configuration: configuration
|
configuration: nil
|
||||||
|
),
|
||||||
|
logging: loggingOptions
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension CreateCommand {
|
||||||
|
var generateJsonOptions: CliClient.GenerateJsonOptions {
|
||||||
|
.init(
|
||||||
|
templateDirectory: templateDir,
|
||||||
|
templateRepo: repo,
|
||||||
|
version: branch,
|
||||||
|
useLocalTemplateDirectory: localTemplateDir
|
||||||
)
|
)
|
||||||
|
|
||||||
// try await runPlaybook(
|
|
||||||
// commandName: Self.commandName,
|
|
||||||
// globals: self.globals,
|
|
||||||
// configuration: configuration,
|
|
||||||
// extraArgs: extraArgs,
|
|
||||||
// "--tags", "setup-project",
|
|
||||||
// "--extra-vars", "project_dir=\(self.projectDir)",
|
|
||||||
// "--extra-vars", "'\(jsonString)'"
|
|
||||||
// )
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func parseOptions(
|
|
||||||
command: CreateCommand,
|
|
||||||
configuration: Configuration,
|
|
||||||
logger: Logger,
|
|
||||||
encoder: JSONEncoder
|
|
||||||
) throws -> Data {
|
|
||||||
let templateDir = command.templateDir ?? configuration.template.directory
|
|
||||||
let templateRepo = command.repo ?? configuration.template.url
|
|
||||||
let version = (command.branch ?? configuration.template.version) ?? "main"
|
|
||||||
|
|
||||||
logger.debug("""
|
|
||||||
(\(command.localTemplateDir), \(String(describing: templateDir)), \(String(describing: templateRepo)))
|
|
||||||
""")
|
|
||||||
|
|
||||||
switch (command.localTemplateDir, templateDir, templateRepo) {
|
|
||||||
case (true, .none, _):
|
|
||||||
// User supplied they wanted to use a local template directory, but we could not find
|
|
||||||
// the path set from command line or in configuration.
|
|
||||||
throw CreateError.templateDirNotFound
|
|
||||||
case let (false, _, .some(repo)):
|
|
||||||
// User did not supply they wanted to use a local template directory, and we found a repo url that was
|
|
||||||
// either set by the command line or found in the configuration.
|
|
||||||
logger.debug("Using repo.")
|
|
||||||
return try encoder.encode(TemplateRepo(repo: repo, version: version))
|
|
||||||
case let (true, .some(templateDir), _):
|
|
||||||
// User supplied they wanted to use a local template directory, and we found the template directory
|
|
||||||
// either set by the command line or in the configuration.
|
|
||||||
logger.debug("Using template directory.")
|
|
||||||
return try encoder.encode(TemplateDirJson(path: templateDir))
|
|
||||||
case let (false, .some(templateDir), _):
|
|
||||||
// User supplied they did not wanted to use a local template directory, and we found the template directory
|
|
||||||
// either set by the command line or in the configuration, and no repo was found / handled previously.
|
|
||||||
logger.debug("Using template directory.")
|
|
||||||
return try encoder.encode(TemplateDirJson(path: templateDir))
|
|
||||||
case (_, .none, .none):
|
|
||||||
// We could not find a repo or template directory.
|
|
||||||
throw CreateError.templateDirOrRepoNotSpecified
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct TemplateDirJson: Encodable {
|
|
||||||
|
|
||||||
let template: Template
|
|
||||||
|
|
||||||
init(path: String) {
|
|
||||||
self.template = .init(path: path)
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Template: Encodable {
|
|
||||||
let path: String
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct TemplateRepo: Encodable {
|
|
||||||
|
|
||||||
let template: Template
|
|
||||||
|
|
||||||
init(repo: String, version: String?) {
|
|
||||||
self.template = .init(repo: repo, version: version ?? "main")
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Template: Encodable {
|
|
||||||
let repo: String
|
|
||||||
let version: String
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum CreateError: Error {
|
|
||||||
case encodingError
|
|
||||||
case templateDirNotFound
|
|
||||||
case templateDirOrRepoNotSpecified
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import ArgumentParser
|
import ArgumentParser
|
||||||
|
import CliClient
|
||||||
|
|
||||||
struct BasicGlobalOptions: ParsableArguments {
|
struct BasicGlobalOptions: ParsableArguments {
|
||||||
@Flag(
|
@Flag(
|
||||||
@@ -55,3 +56,21 @@ struct GlobalOptions: ParsableArguments {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension GlobalOptions {
|
||||||
|
func loggingOptions(commandName: String) -> CliClient.LoggingOptions {
|
||||||
|
.init(
|
||||||
|
commandName: commandName,
|
||||||
|
logLevel: .init(globals: basic, quietOnlyPlaybook: quietOnlyPlaybook)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension BasicGlobalOptions {
|
||||||
|
func loggingOptions(commandName: String) -> CliClient.LoggingOptions {
|
||||||
|
.init(
|
||||||
|
commandName: commandName,
|
||||||
|
logLevel: .init(globals: self, quietOnlyPlaybook: false)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import Dependencies
|
|
||||||
import Logging
|
import Logging
|
||||||
|
|
||||||
// TODO: Move some of this to the cli-client module.
|
|
||||||
extension Logger.Level {
|
extension Logger.Level {
|
||||||
|
|
||||||
/// Set the log level based on the user's options supplied.
|
/// Set the log level based on the user's options supplied.
|
||||||
@@ -22,34 +20,3 @@ extension Logger.Level {
|
|||||||
self = .info
|
self = .info
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func withSetupLogger(
|
|
||||||
commandName: String,
|
|
||||||
globals: BasicGlobalOptions,
|
|
||||||
quietOnlyPlaybook: Bool = false,
|
|
||||||
dependencies setupDependencies: (inout DependencyValues) -> Void = { _ in },
|
|
||||||
operation: @escaping () async throws -> Void
|
|
||||||
) async rethrows {
|
|
||||||
try await withDependencies {
|
|
||||||
$0.logger = .init(label: "\("hpa".yellow)")
|
|
||||||
$0.logger.logLevel = .init(globals: globals, quietOnlyPlaybook: quietOnlyPlaybook)
|
|
||||||
$0.logger[metadataKey: "command"] = "\(commandName.blue)"
|
|
||||||
} operation: {
|
|
||||||
try await operation()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func withSetupLogger(
|
|
||||||
commandName: String,
|
|
||||||
globals: GlobalOptions,
|
|
||||||
dependencies setupDependencies: (inout DependencyValues) -> Void = { _ in },
|
|
||||||
operation: @escaping () async throws -> Void
|
|
||||||
) async rethrows {
|
|
||||||
try await withSetupLogger(
|
|
||||||
commandName: commandName,
|
|
||||||
globals: globals.basic,
|
|
||||||
quietOnlyPlaybook: globals.quietOnlyPlaybook,
|
|
||||||
dependencies: setupDependencies,
|
|
||||||
operation: operation
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -50,9 +50,8 @@ struct GenerateConfigurationCommand: AsyncParsableCommand {
|
|||||||
|
|
||||||
// FIX:
|
// FIX:
|
||||||
private func _run() async throws {
|
private func _run() async throws {
|
||||||
try await withSetupLogger(commandName: Self.commandName, globals: globals) {
|
|
||||||
@Dependency(\.cliClient) var cliClient
|
@Dependency(\.cliClient) var cliClient
|
||||||
|
try await cliClient.withLogger(globals.loggingOptions(commandName: Self.commandName)) {
|
||||||
let actualPath: String
|
let actualPath: String
|
||||||
|
|
||||||
// if let path {
|
// if let path {
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ struct DecryptCommand: AsyncParsableCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try await cliClient.runVaultCommand(
|
try await cliClient.runVaultCommand(
|
||||||
options.vaultOptions(arguments: args, configuration: nil)
|
options.vaultOptions(arguments: args, configuration: nil),
|
||||||
|
logging: options.loggingOptions(commandName: Self.commandName)
|
||||||
)
|
)
|
||||||
|
|
||||||
// try await runVault(
|
// try await runVault(
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ struct EncryptCommand: AsyncParsableCommand {
|
|||||||
args.append(contentsOf: ["--output", output])
|
args.append(contentsOf: ["--output", output])
|
||||||
}
|
}
|
||||||
try await cliClient.runVaultCommand(
|
try await cliClient.runVaultCommand(
|
||||||
options.vaultOptions(arguments: args, configuration: nil)
|
options.vaultOptions(arguments: args, configuration: nil),
|
||||||
|
logging: options.loggingOptions(commandName: Self.commandName)
|
||||||
)
|
)
|
||||||
|
|
||||||
// try await runVault(
|
// try await runVault(
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import ArgumentParser
|
import ArgumentParser
|
||||||
|
import CliClient
|
||||||
|
|
||||||
// Holds the common options for vault commands, as they all share the
|
// Holds the common options for vault commands, as they all share the
|
||||||
// same structure.
|
// same structure.
|
||||||
@@ -29,3 +30,9 @@ struct VaultOptions: ParsableArguments {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension VaultOptions {
|
||||||
|
func loggingOptions(commandName: String) -> CliClient.LoggingOptions {
|
||||||
|
globals.loggingOptions(commandName: commandName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,6 +10,12 @@ import TestSupport
|
|||||||
@Suite("CliClientTests")
|
@Suite("CliClientTests")
|
||||||
struct CliClientTests: TestCase {
|
struct CliClientTests: TestCase {
|
||||||
|
|
||||||
|
static let loggingOptions: CliClient.LoggingOptions = {
|
||||||
|
let levelString = ProcessInfo.processInfo.environment["LOGGING_LEVEL"] ?? "debug"
|
||||||
|
let logLevel = Logger.Level(rawValue: levelString) ?? .debug
|
||||||
|
return .init(commandName: "CliClientTests", logLevel: logLevel)
|
||||||
|
}()
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
func capturingClient() async throws {
|
func capturingClient() async throws {
|
||||||
let captured = CliClient.CapturingClient()
|
let captured = CliClient.CapturingClient()
|
||||||
@@ -35,7 +41,10 @@ struct CliClientTests: TestCase {
|
|||||||
@Dependency(\.cliClient) var cliClient
|
@Dependency(\.cliClient) var cliClient
|
||||||
let configuration = Configuration.mock
|
let configuration = Configuration.mock
|
||||||
|
|
||||||
try await cliClient.runVaultCommand(.init(arguments: [argument], quiet: false, shell: nil))
|
try await cliClient.runVaultCommand(
|
||||||
|
.init(arguments: [argument], quiet: false, shell: nil),
|
||||||
|
logging: Self.loggingOptions
|
||||||
|
)
|
||||||
|
|
||||||
let shell = await captured.shell
|
let shell = await captured.shell
|
||||||
#expect(shell == .zsh(useDashC: true))
|
#expect(shell == .zsh(useDashC: true))
|
||||||
@@ -74,11 +83,14 @@ struct CliClientTests: TestCase {
|
|||||||
try await withMockConfiguration(captured, configuration: configuration, key: "runPlaybook") {
|
try await withMockConfiguration(captured, configuration: configuration, key: "runPlaybook") {
|
||||||
@Dependency(\.cliClient) var cliClient
|
@Dependency(\.cliClient) var cliClient
|
||||||
|
|
||||||
try await cliClient.runPlaybookCommand(.init(
|
try await cliClient.runPlaybookCommand(
|
||||||
|
.init(
|
||||||
arguments: [],
|
arguments: [],
|
||||||
quiet: false,
|
quiet: false,
|
||||||
shell: nil
|
shell: nil
|
||||||
))
|
),
|
||||||
|
logging: Self.loggingOptions
|
||||||
|
)
|
||||||
|
|
||||||
let expectedArguments = [
|
let expectedArguments = [
|
||||||
"ansible-playbook", "playbook/main.yml",
|
"ansible-playbook", "playbook/main.yml",
|
||||||
@@ -156,6 +168,118 @@ struct CliClientTests: TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(
|
||||||
|
arguments: [
|
||||||
|
GenerateJsonTestOption(
|
||||||
|
options: .init(
|
||||||
|
templateDirectory: nil,
|
||||||
|
templateRepo: nil,
|
||||||
|
version: nil,
|
||||||
|
useLocalTemplateDirectory: true
|
||||||
|
),
|
||||||
|
configuration: nil,
|
||||||
|
expectation: .failing
|
||||||
|
),
|
||||||
|
GenerateJsonTestOption(
|
||||||
|
options: .init(
|
||||||
|
templateDirectory: nil,
|
||||||
|
templateRepo: nil,
|
||||||
|
version: nil,
|
||||||
|
useLocalTemplateDirectory: false
|
||||||
|
),
|
||||||
|
configuration: nil,
|
||||||
|
expectation: .failing
|
||||||
|
),
|
||||||
|
GenerateJsonTestOption(
|
||||||
|
options: .init(
|
||||||
|
templateDirectory: "template",
|
||||||
|
templateRepo: nil,
|
||||||
|
version: nil,
|
||||||
|
useLocalTemplateDirectory: true
|
||||||
|
),
|
||||||
|
configuration: nil,
|
||||||
|
expectation: .success("""
|
||||||
|
{
|
||||||
|
"template" : {
|
||||||
|
"path" : "template"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
),
|
||||||
|
GenerateJsonTestOption(
|
||||||
|
options: .init(
|
||||||
|
templateDirectory: nil,
|
||||||
|
templateRepo: nil,
|
||||||
|
version: nil,
|
||||||
|
useLocalTemplateDirectory: false
|
||||||
|
),
|
||||||
|
configuration: .init(template: .init(directory: "template")),
|
||||||
|
expectation: .success("""
|
||||||
|
{
|
||||||
|
"template" : {
|
||||||
|
"path" : "template"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
),
|
||||||
|
GenerateJsonTestOption(
|
||||||
|
options: .init(
|
||||||
|
templateDirectory: nil,
|
||||||
|
templateRepo: "https://git.example.com/template.git",
|
||||||
|
version: nil,
|
||||||
|
useLocalTemplateDirectory: false
|
||||||
|
),
|
||||||
|
configuration: nil,
|
||||||
|
expectation: .success("""
|
||||||
|
{
|
||||||
|
"template" : {
|
||||||
|
"repo" : "https://git.example.com/template.git",
|
||||||
|
"version" : "main"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
),
|
||||||
|
GenerateJsonTestOption(
|
||||||
|
options: .init(
|
||||||
|
templateDirectory: nil,
|
||||||
|
templateRepo: nil,
|
||||||
|
version: nil,
|
||||||
|
useLocalTemplateDirectory: false
|
||||||
|
),
|
||||||
|
configuration: .init(template: .init(url: "https://git.example.com/template.git", version: "v0.1.0")),
|
||||||
|
expectation: .success("""
|
||||||
|
{
|
||||||
|
"template" : {
|
||||||
|
"repo" : "https://git.example.com/template.git",
|
||||||
|
"version" : "v0.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
func generateJson(input: GenerateJsonTestOption) async {
|
||||||
|
await withTestLogger(key: "generateJson") {
|
||||||
|
$0.configurationClient = .mock(input.configuration ?? .init())
|
||||||
|
$0.cliClient = .liveValue
|
||||||
|
} operation: {
|
||||||
|
@Dependency(\.cliClient) var cliClient
|
||||||
|
|
||||||
|
let json = try? await cliClient.generateJSON(
|
||||||
|
input.options,
|
||||||
|
logging: Self.loggingOptions,
|
||||||
|
encoder: jsonEncoder
|
||||||
|
)
|
||||||
|
|
||||||
|
switch input.expectation {
|
||||||
|
case let .success(expected):
|
||||||
|
#expect(json == expected)
|
||||||
|
case .failing:
|
||||||
|
#expect(json == nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func withMockConfiguration(
|
func withMockConfiguration(
|
||||||
_ capturing: CliClient.CapturingClient,
|
_ capturing: CliClient.CapturingClient,
|
||||||
configuration: Configuration = .mock,
|
configuration: Configuration = .mock,
|
||||||
@@ -174,6 +298,17 @@ struct CliClientTests: TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct GenerateJsonTestOption: Sendable {
|
||||||
|
let options: CliClient.GenerateJsonOptions
|
||||||
|
let configuration: Configuration?
|
||||||
|
let expectation: GenerateJsonExpectation
|
||||||
|
}
|
||||||
|
|
||||||
|
enum GenerateJsonExpectation: Sendable {
|
||||||
|
case failing
|
||||||
|
case success(String)
|
||||||
|
}
|
||||||
|
|
||||||
extension ConfigurationClient {
|
extension ConfigurationClient {
|
||||||
static func mock(_ configuration: Configuration) -> Self {
|
static func mock(_ configuration: Configuration) -> Self {
|
||||||
var mock = Self.testValue
|
var mock = Self.testValue
|
||||||
@@ -184,3 +319,9 @@ extension ConfigurationClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct TestError: Error {}
|
struct TestError: Error {}
|
||||||
|
|
||||||
|
let jsonEncoder: JSONEncoder = {
|
||||||
|
let encoder = JSONEncoder()
|
||||||
|
encoder.outputFormatting = [.prettyPrinted, .withoutEscapingSlashes, .sortedKeys]
|
||||||
|
return encoder
|
||||||
|
}()
|
||||||
|
|||||||
Reference in New Issue
Block a user