feat: Working create command.
This commit is contained in:
@@ -12,7 +12,6 @@ let package = Package(
|
|||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.3.0"),
|
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.3.0"),
|
||||||
.package(url: "https://github.com/apple/swift-log", from: "1.6.0"),
|
|
||||||
.package(url: "https://github.com/pointfreeco/swift-dependencies", from: "1.5.2"),
|
.package(url: "https://github.com/pointfreeco/swift-dependencies", from: "1.5.2"),
|
||||||
.package(url: "https://github.com/m-housh/swift-shell-client.git", from: "0.1.0")
|
.package(url: "https://github.com/m-housh/swift-shell-client.git", from: "0.1.0")
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import Dependencies
|
import Dependencies
|
||||||
import DependenciesMacros
|
import DependenciesMacros
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import ShellClient
|
||||||
|
|
||||||
public extension DependencyValues {
|
public extension DependencyValues {
|
||||||
var cliClient: CliClient {
|
var cliClient: CliClient {
|
||||||
@@ -14,6 +15,23 @@ public struct CliClient: Sendable {
|
|||||||
public var decoder: @Sendable () -> JSONDecoder = { .init() }
|
public var decoder: @Sendable () -> JSONDecoder = { .init() }
|
||||||
public var encoder: @Sendable () -> JSONEncoder = { .init() }
|
public var encoder: @Sendable () -> JSONEncoder = { .init() }
|
||||||
public var loadConfiguration: @Sendable () throws -> Configuration
|
public var loadConfiguration: @Sendable () throws -> Configuration
|
||||||
|
public var runCommand: @Sendable ([String], Bool, ShellCommand.Shell) async throws -> Void
|
||||||
|
|
||||||
|
public func runCommand(
|
||||||
|
quiet: Bool,
|
||||||
|
shell: ShellCommand.Shell,
|
||||||
|
_ args: [String]
|
||||||
|
) async throws {
|
||||||
|
try await runCommand(args, quiet, shell)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func runCommand(
|
||||||
|
quiet: Bool,
|
||||||
|
shell: ShellCommand.Shell,
|
||||||
|
_ args: String...
|
||||||
|
) async throws {
|
||||||
|
try await runCommand(args, quiet, shell)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension CliClient: DependencyKey {
|
extension CliClient: DependencyKey {
|
||||||
@@ -41,6 +59,22 @@ extension CliClient: DependencyKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return try .fromEnv(env, encoder: encoder, decoder: decoder)
|
return try .fromEnv(env, encoder: encoder, decoder: decoder)
|
||||||
|
} runCommand: { args, quiet, shell in
|
||||||
|
@Dependency(\.asyncShellClient) var shellClient
|
||||||
|
if !quiet {
|
||||||
|
try await shellClient.foreground(.init(
|
||||||
|
shell: shell,
|
||||||
|
environment: ProcessInfo.processInfo.environment,
|
||||||
|
in: nil,
|
||||||
|
args
|
||||||
|
))
|
||||||
|
}
|
||||||
|
try await shellClient.background(.init(
|
||||||
|
shell: shell,
|
||||||
|
environment: ProcessInfo.processInfo.environment,
|
||||||
|
in: nil,
|
||||||
|
args
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,13 +66,13 @@ private struct LiveFileClient: @unchecked Sendable {
|
|||||||
@Dependency(\.logger) var logger
|
@Dependency(\.logger) var logger
|
||||||
logger.trace("Begin load file for: \(path(for: url))")
|
logger.trace("Begin load file for: \(path(for: url))")
|
||||||
|
|
||||||
// if url.absoluteString.split(separator: ".json").count > 0 {
|
if url.absoluteString.contains(".json") {
|
||||||
// // Handle json file.
|
// Handle json file.
|
||||||
// let data = try Data(contentsOf: url)
|
let data = try Data(contentsOf: url)
|
||||||
// let dict = (try? decoder.decode([String: String].self, from: data)) ?? [:]
|
let dict = (try? decoder.decode([String: String].self, from: data)) ?? [:]
|
||||||
// env.merge(dict, uniquingKeysWith: { $1 })
|
env.merge(dict, uniquingKeysWith: { $1 })
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
|
|
||||||
let string = try String(contentsOfFile: path(for: url), encoding: .utf8)
|
let string = try String(contentsOfFile: path(for: url), encoding: .utf8)
|
||||||
|
|
||||||
@@ -82,7 +82,9 @@ private struct LiveFileClient: @unchecked Sendable {
|
|||||||
for line in lines {
|
for line in lines {
|
||||||
logger.trace("Line: \(line)")
|
logger.trace("Line: \(line)")
|
||||||
let strippedLine = line.trimmingCharacters(in: .whitespacesAndNewlines)
|
let strippedLine = line.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
let splitLine = strippedLine.split(separator: "=")
|
let splitLine = strippedLine.split(separator: "=").map {
|
||||||
|
$0.replacingOccurrences(of: "\"", with: "")
|
||||||
|
}
|
||||||
logger.trace("Split Line: \(splitLine)")
|
logger.trace("Split Line: \(splitLine)")
|
||||||
guard splitLine.count >= 2 else { continue }
|
guard splitLine.count >= 2 else { continue }
|
||||||
|
|
||||||
|
|||||||
@@ -8,13 +8,14 @@ struct BuildCommand: AsyncParsableCommand {
|
|||||||
|
|
||||||
static let configuration = CommandConfiguration.playbookCommandConfiguration(
|
static let configuration = CommandConfiguration.playbookCommandConfiguration(
|
||||||
commandName: commandName,
|
commandName: commandName,
|
||||||
abstract: "Build a home performance assesment project."
|
abstract: "Build a home performance assesment project.",
|
||||||
|
examples: (label: "Build Project", example: "\(commandName) /path/to/project")
|
||||||
)
|
)
|
||||||
|
|
||||||
@OptionGroup var globals: GlobalOptions
|
@OptionGroup var globals: GlobalOptions
|
||||||
|
|
||||||
@Argument(
|
@Argument(
|
||||||
help: "The project directory.",
|
help: "Path to the project directory.",
|
||||||
completion: .directory
|
completion: .directory
|
||||||
)
|
)
|
||||||
var projectDir: String
|
var projectDir: String
|
||||||
@@ -25,11 +26,12 @@ struct BuildCommand: AsyncParsableCommand {
|
|||||||
var extraArgs: [String] = []
|
var extraArgs: [String] = []
|
||||||
|
|
||||||
mutating func run() async throws {
|
mutating func run() async throws {
|
||||||
let args = [
|
try await runPlaybook(
|
||||||
|
commandName: Self.commandName,
|
||||||
|
globals: globals,
|
||||||
|
extraArgs: extraArgs,
|
||||||
"--tags", "build-project",
|
"--tags", "build-project",
|
||||||
"--extra-vars", "project_dir=\(projectDir)"
|
"--extra-vars", "project_dir=\(projectDir)"
|
||||||
] + extraArgs
|
)
|
||||||
|
|
||||||
try await runPlaybook(commandName: Self.commandName, globals: globals, args: args)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,170 @@
|
|||||||
import ArgumentParser
|
import ArgumentParser
|
||||||
|
import CliClient
|
||||||
|
import Dependencies
|
||||||
|
import Foundation
|
||||||
|
import Logging
|
||||||
|
|
||||||
struct CreateProjectCommand: AsyncParsableCommand {
|
struct CreateProjectCommand: AsyncParsableCommand {
|
||||||
|
|
||||||
static let configuration = CommandConfiguration(
|
static let commandName = "create"
|
||||||
commandName: "create-project",
|
|
||||||
abstract: "Create a home performance assesment project."
|
static let configuration = CommandConfiguration.playbookCommandConfiguration(
|
||||||
|
commandName: commandName,
|
||||||
|
abstract: "Create a home performance assesment project.",
|
||||||
|
examples: (
|
||||||
|
label: "Create Assesment",
|
||||||
|
example: "\(commandName) /new/assement/path"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@OptionGroup var globals: GlobalOptions
|
@OptionGroup var globals: GlobalOptions
|
||||||
|
|
||||||
|
@Option(
|
||||||
|
name: .shortAndLong,
|
||||||
|
help: "The template repository to use."
|
||||||
|
)
|
||||||
|
var repo: String?
|
||||||
|
|
||||||
|
@Option(
|
||||||
|
name: .shortAndLong,
|
||||||
|
help: "The repo branch or version to use."
|
||||||
|
)
|
||||||
|
var branch: String?
|
||||||
|
|
||||||
|
@Option(
|
||||||
|
name: .shortAndLong,
|
||||||
|
help: "Path to local template directory to use.",
|
||||||
|
completion: .directory
|
||||||
|
)
|
||||||
|
var templateDir: String?
|
||||||
|
|
||||||
|
@Flag(
|
||||||
|
name: .shortAndLong,
|
||||||
|
help: "Force using a local template directory."
|
||||||
|
)
|
||||||
|
var localTemplateDir = false
|
||||||
|
|
||||||
|
@Argument(
|
||||||
|
help: "Path to the project directory.",
|
||||||
|
completion: .directory
|
||||||
|
)
|
||||||
|
var projectDir: String
|
||||||
|
|
||||||
|
@Argument(
|
||||||
|
help: "Extra arguments passed to the playbook."
|
||||||
|
)
|
||||||
|
var extraArgs: [String] = []
|
||||||
|
|
||||||
mutating func run() async throws {
|
mutating func run() async throws {
|
||||||
fatalError()
|
try await _run()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func _run() async throws {
|
||||||
|
try await withSetupLogger(commandName: Self.commandName, globals: globals) {
|
||||||
|
@Dependency(\.cliClient) var cliClient
|
||||||
|
@Dependency(\.logger) var logger
|
||||||
|
|
||||||
|
let encoder = cliClient.encoder()
|
||||||
|
|
||||||
|
let configuration = try cliClient.loadConfiguration()
|
||||||
|
|
||||||
|
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 {
|
||||||
|
throw CreateError.encodingError
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("JSON string: \(jsonString)")
|
||||||
|
|
||||||
|
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: CreateProjectCommand,
|
||||||
|
configuration: Configuration,
|
||||||
|
logger: Logger,
|
||||||
|
encoder: JSONEncoder
|
||||||
|
) throws -> Data {
|
||||||
|
let templateDir = command.templateDir ?? configuration.templateDir
|
||||||
|
let templateRepo = command.repo ?? configuration.templateRepo
|
||||||
|
let version = (command.branch ?? configuration.templateRepoVersion) ?? "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
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,8 +15,28 @@ struct GlobalOptions: ParsableArguments {
|
|||||||
var inventoryPath: String?
|
var inventoryPath: String?
|
||||||
|
|
||||||
@Flag(
|
@Flag(
|
||||||
name: .long,
|
name: .shortAndLong,
|
||||||
help: "Increase logging level."
|
help: "Increase logging level (can be passed multiple times)."
|
||||||
)
|
)
|
||||||
var verbose: Int
|
var verbose: Int
|
||||||
|
|
||||||
|
@Flag(
|
||||||
|
name: .shortAndLong,
|
||||||
|
help: "Supress logging."
|
||||||
|
)
|
||||||
|
var quiet = false
|
||||||
|
|
||||||
|
@Flag(
|
||||||
|
name: .long,
|
||||||
|
help: "Supress only playbook logging."
|
||||||
|
)
|
||||||
|
var quietOnlyPlaybook = false
|
||||||
|
|
||||||
|
@Option(
|
||||||
|
name: .shortAndLong,
|
||||||
|
help: "Optional shell to use when calling shell commands.",
|
||||||
|
completion: .file()
|
||||||
|
)
|
||||||
|
var shell: String?
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,30 +7,47 @@ import Rainbow
|
|||||||
import ShellClient
|
import ShellClient
|
||||||
|
|
||||||
extension CommandConfiguration {
|
extension CommandConfiguration {
|
||||||
static func playbookCommandConfiguration(commandName: String, abstract: String) -> Self {
|
static func playbookCommandConfiguration(
|
||||||
Self(
|
commandName: String,
|
||||||
|
abstract: String,
|
||||||
|
examples: (label: String, example: String)...
|
||||||
|
) -> Self {
|
||||||
|
guard examples.count > 0 else {
|
||||||
|
fatalError("Did not supply any examples.")
|
||||||
|
}
|
||||||
|
return Self(
|
||||||
commandName: commandName,
|
commandName: commandName,
|
||||||
abstract: "\(abstract.blue)",
|
abstract: "\(abstract.blue)",
|
||||||
discussion: """
|
discussion: """
|
||||||
\("IMPORTANT NOTE:".red) Any extra arguments to pass to the playbook invocation have to
|
\("NOTE:".yellow) Most options are not required if you have a configuration file setup.
|
||||||
be at the end with `--` before any arguments otherwise there will
|
|
||||||
be an "Unkown option" error.
|
|
||||||
|
|
||||||
\("Example of passing extra args to the playbook:".yellow)
|
\("Examples:".yellow)
|
||||||
|
|
||||||
$ hpa \(commandName) /my/project -- --vault-id "myId@$SCRIPTS/vault-gopass-client"
|
\(examples.map { "\($0.label.green.italic)\n $ hpa \($0.example)" }.joined(separator: "\n"))
|
||||||
|
|
||||||
\("See Also:".yellow)
|
\("Passing extra args to the playbook.".green.italic)
|
||||||
|
$ hpa \(examples[0].example) -- --vault-id "myId@$SCRIPTS/vault-gopass-client"
|
||||||
|
|
||||||
You can run the following command to see the options that can be passed to the playbook
|
\("See Also:".yellow) \("Ansible playbook options.".italic)
|
||||||
invocation.
|
|
||||||
|
|
||||||
$ ansible-playbook --help
|
$ ansible-playbook --help
|
||||||
|
|
||||||
|
\("IMPORTANT NOTE:".red) Any extra arguments to pass to the playbook invocation have to
|
||||||
|
be at the end with `--` before any arguments otherwise there will
|
||||||
|
be an "Unkown option" error. See examples above.
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension GlobalOptions {
|
||||||
|
|
||||||
|
var shellOrDefault: ShellCommand.Shell {
|
||||||
|
guard let shell else { return .zsh(useDashC: true) }
|
||||||
|
return .custom(path: shell, useDashC: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func ensureString(
|
func ensureString(
|
||||||
globals: GlobalOptions,
|
globals: GlobalOptions,
|
||||||
configuration: Configuration,
|
configuration: Configuration,
|
||||||
@@ -41,37 +58,78 @@ func ensureString(
|
|||||||
return global
|
return global
|
||||||
}
|
}
|
||||||
guard let configuration = configuration[keyPath: configurationKeyPath] else {
|
guard let configuration = configuration[keyPath: configurationKeyPath] else {
|
||||||
throw PlaybookNotFound()
|
throw RunPlaybookError.playbookNotFound
|
||||||
}
|
}
|
||||||
return configuration
|
return configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
func runPlaybook(
|
func withSetupLogger(
|
||||||
commandName: String,
|
commandName: String,
|
||||||
globals: GlobalOptions,
|
globals: GlobalOptions,
|
||||||
args: [String]
|
dependencies setupDependencies: (inout DependencyValues) -> Void = { _ in },
|
||||||
) async throws {
|
operation: @escaping () async throws -> Void
|
||||||
|
) async rethrows {
|
||||||
try await withDependencies {
|
try await withDependencies {
|
||||||
$0.logger = .init(label: "\("hpa".yellow)")
|
$0.logger = .init(label: "\("hpa".yellow)")
|
||||||
|
if globals.quietOnlyPlaybook || !globals.quiet {
|
||||||
switch globals.verbose {
|
switch globals.verbose {
|
||||||
case 0:
|
case 0:
|
||||||
$0.logger.logLevel = .info
|
$0.logger.logLevel = .info
|
||||||
case 1:
|
case 1:
|
||||||
$0.logger.logLevel = .debug
|
$0.logger.logLevel = .debug
|
||||||
case 2:
|
case 2...:
|
||||||
$0.logger.logLevel = .trace
|
$0.logger.logLevel = .trace
|
||||||
default:
|
default:
|
||||||
$0.logger.logLevel = .info
|
$0.logger.logLevel = .info
|
||||||
}
|
}
|
||||||
|
}
|
||||||
$0.logger[metadataKey: "command"] = "\(commandName.blue)"
|
$0.logger[metadataKey: "command"] = "\(commandName.blue)"
|
||||||
} operation: {
|
} operation: {
|
||||||
|
try await operation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runPlaybook(
|
||||||
|
commandName: String,
|
||||||
|
globals: GlobalOptions,
|
||||||
|
configuration: Configuration? = nil,
|
||||||
|
extraArgs: [String],
|
||||||
|
_ args: String...
|
||||||
|
) async throws {
|
||||||
|
try await runPlaybook(
|
||||||
|
commandName: commandName,
|
||||||
|
globals: globals,
|
||||||
|
configuration: configuration,
|
||||||
|
extraArgs: extraArgs,
|
||||||
|
args
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension CliClient {
|
||||||
|
func ensuredConfiguration(_ configuration: Configuration?) throws -> Configuration {
|
||||||
|
guard let configuration else {
|
||||||
|
return try loadConfiguration()
|
||||||
|
}
|
||||||
|
return configuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runPlaybook(
|
||||||
|
commandName: String,
|
||||||
|
globals: GlobalOptions,
|
||||||
|
configuration: Configuration? = nil,
|
||||||
|
extraArgs: [String],
|
||||||
|
_ args: [String]
|
||||||
|
) async throws {
|
||||||
|
try await withSetupLogger(commandName: commandName, globals: globals) {
|
||||||
@Dependency(\.cliClient) var cliClient
|
@Dependency(\.cliClient) var cliClient
|
||||||
@Dependency(\.logger) var logger
|
@Dependency(\.logger) var logger
|
||||||
@Dependency(\.asyncShellClient) var shellClient
|
|
||||||
|
|
||||||
logger.debug("Begin run playbook: \(globals)")
|
logger.debug("Begin run playbook: \(globals)")
|
||||||
let configuration = try cliClient.loadConfiguration()
|
|
||||||
logger.debug("Loaded configuration: \(configuration)")
|
let configuration = try cliClient.ensuredConfiguration(configuration)
|
||||||
|
|
||||||
|
logger.debug("Configuration: \(configuration)")
|
||||||
|
|
||||||
let playbookDir = try ensureString(
|
let playbookDir = try ensureString(
|
||||||
globals: globals,
|
globals: globals,
|
||||||
@@ -91,19 +149,21 @@ func runPlaybook(
|
|||||||
var playbookArgs = [
|
var playbookArgs = [
|
||||||
"ansible-playbook", playbook,
|
"ansible-playbook", playbook,
|
||||||
"--inventory", inventory
|
"--inventory", inventory
|
||||||
] + args
|
]
|
||||||
|
|
||||||
if let defaultArgs = configuration.defaultPlaybookArgs {
|
if let defaultArgs = configuration.defaultPlaybookArgs {
|
||||||
playbookArgs.append(defaultArgs)
|
playbookArgs.append(defaultArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
try await shellClient.foreground(.init(
|
try await cliClient.runCommand(
|
||||||
shell: .zsh(useDashC: true),
|
quiet: globals.quietOnlyPlaybook ? true : globals.quiet,
|
||||||
environment: ProcessInfo.processInfo.environment,
|
shell: globals.shellOrDefault,
|
||||||
in: nil,
|
playbookArgs + args + extraArgs
|
||||||
playbookArgs
|
)
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PlaybookNotFound: Error {}
|
enum RunPlaybookError: Error {
|
||||||
|
case playbookNotFound
|
||||||
|
case configurationError
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ func testFindConfigPaths() throws {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
func loadConfiguration() throws {
|
func loadConfiguration() throws {
|
||||||
try withTestLogger(key: "loadConfiguration", logLevel: .trace) {
|
try withTestLogger(key: "loadConfiguration", logLevel: .debug) {
|
||||||
$0.cliClient = .liveValue
|
$0.cliClient = .liveValue
|
||||||
$0.fileClient = .liveValue
|
$0.fileClient = .liveValue
|
||||||
} operation: {
|
} operation: {
|
||||||
@@ -37,7 +37,7 @@ func withTestLogger(
|
|||||||
) rethrows {
|
) rethrows {
|
||||||
try withDependencies {
|
try withDependencies {
|
||||||
$0.logger = .init(label: label)
|
$0.logger = .init(label: label)
|
||||||
$0.logger[metadataKey: "instance"] = "\(key)"
|
$0.logger[metadataKey: "test"] = "\(key)"
|
||||||
$0.logger.logLevel = logLevel
|
$0.logger.logLevel = logLevel
|
||||||
} operation: {
|
} operation: {
|
||||||
try operation()
|
try operation()
|
||||||
@@ -53,7 +53,7 @@ func withTestLogger(
|
|||||||
) rethrows {
|
) rethrows {
|
||||||
try withDependencies {
|
try withDependencies {
|
||||||
$0.logger = .init(label: label)
|
$0.logger = .init(label: label)
|
||||||
$0.logger[metadataKey: "instance"] = "\(key)"
|
$0.logger[metadataKey: "test"] = "\(key)"
|
||||||
$0.logger.logLevel = logLevel
|
$0.logger.logLevel = logLevel
|
||||||
setupDependencies(&$0)
|
setupDependencies(&$0)
|
||||||
} operation: {
|
} operation: {
|
||||||
|
|||||||
Reference in New Issue
Block a user