From e745046b7176dae43e3f689fe6a9556693ec5f56 Mon Sep 17 00:00:00 2001 From: Jon Edvald Date: Fri, 21 Sep 2018 15:07:53 +0200 Subject: [PATCH] refactor: rename logEntry to log and require for tests, cmds and actions This leverages the recent changes to the logger that allow for empty log entries. --- garden-service/src/actions.ts | 42 +++++++------ garden-service/src/cli/cli.ts | 2 + garden-service/src/commands/base.ts | 2 + garden-service/src/commands/build.ts | 6 +- garden-service/src/commands/call.ts | 4 +- garden-service/src/commands/delete.ts | 14 +++-- garden-service/src/commands/deploy.ts | 6 +- garden-service/src/commands/dev.ts | 10 +-- garden-service/src/commands/exec.ts | 4 +- garden-service/src/commands/get.ts | 8 ++- garden-service/src/commands/init.ts | 4 +- garden-service/src/commands/logs.ts | 4 +- garden-service/src/commands/publish.ts | 8 ++- garden-service/src/commands/run/module.ts | 7 ++- garden-service/src/commands/run/service.ts | 14 +++-- garden-service/src/commands/run/test.ts | 7 ++- garden-service/src/commands/set.ts | 9 ++- garden-service/src/commands/test.ts | 8 +-- .../src/commands/update-remote/all.ts | 16 ++++- .../src/commands/update-remote/modules.ts | 2 +- .../src/commands/update-remote/sources.ts | 2 +- garden-service/src/config/config-context.ts | 4 +- garden-service/src/garden.ts | 6 +- .../logger/writers/fancy-terminal-writer.ts | 14 ++--- garden-service/src/plugins/container.ts | 16 ++--- garden-service/src/plugins/google/common.ts | 6 +- .../src/plugins/google/google-app-engine.ts | 8 +-- .../plugins/google/google-cloud-functions.ts | 4 +- .../src/plugins/kubernetes/actions.ts | 12 ++-- .../src/plugins/kubernetes/deployment.ts | 20 +++--- garden-service/src/plugins/kubernetes/helm.ts | 48 +++++++-------- garden-service/src/plugins/kubernetes/init.ts | 47 +++++++------- .../src/plugins/kubernetes/local.ts | 8 +-- .../src/plugins/kubernetes/status.ts | 10 +-- .../src/plugins/local/local-docker-swarm.ts | 18 +++--- .../src/plugins/openfaas/openfaas.ts | 25 ++++---- garden-service/src/tasks/base.ts | 4 ++ garden-service/src/tasks/build.ts | 17 +++--- garden-service/src/tasks/deploy.ts | 31 +++++----- garden-service/src/tasks/publish.ts | 19 +++--- garden-service/src/tasks/push.ts | 17 +++--- garden-service/src/tasks/test.ts | 50 +++++++-------- garden-service/src/types/plugin/params.ts | 8 +-- garden-service/src/types/plugin/plugin.ts | 2 +- garden-service/src/types/service.ts | 8 ++- garden-service/src/util/ext-tools.ts | 18 +++--- garden-service/src/vcs/base.ts | 2 +- garden-service/src/vcs/git.ts | 10 +-- garden-service/test/helpers.ts | 3 +- garden-service/test/src/actions.ts | 43 +++++++------ garden-service/test/src/build-dir.ts | 3 + garden-service/test/src/commands/build.ts | 4 ++ garden-service/test/src/commands/call.ts | 48 +++++++++++++-- .../test/src/commands/create/module.ts | 46 ++++++++++++-- .../test/src/commands/create/project.ts | 24 +++++--- garden-service/test/src/commands/delete.ts | 24 +++++--- garden-service/test/src/commands/deploy.ts | 4 ++ garden-service/test/src/commands/get.ts | 23 ++++++- garden-service/test/src/commands/link.ts | 9 +++ garden-service/test/src/commands/publish.ts | 15 +++++ .../test/src/commands/run/module.ts | 4 ++ .../test/src/commands/run/service.ts | 4 ++ garden-service/test/src/commands/scan.ts | 8 ++- garden-service/test/src/commands/set.ts | 10 ++- garden-service/test/src/commands/test.ts | 4 ++ garden-service/test/src/commands/unlink.ts | 15 +++++ .../test/src/commands/update-remote.ts | 61 ++++++++++++++++--- garden-service/test/src/commands/validate.ts | 16 ++++- .../test/src/config/config-context.ts | 1 + garden-service/test/src/plugins/container.ts | 17 +++--- garden-service/test/src/plugins/generic.ts | 7 ++- garden-service/test/src/task-graph.ts | 1 + garden-service/test/src/tasks/test.ts | 4 ++ 73 files changed, 667 insertions(+), 342 deletions(-) diff --git a/garden-service/src/actions.ts b/garden-service/src/actions.ts index 66f6a8ce299..2667cdc602e 100644 --- a/garden-service/src/actions.ts +++ b/garden-service/src/actions.ts @@ -81,7 +81,8 @@ export interface ContextStatus { } export interface DeployServicesParams { - serviceNames?: string[], + log: LogEntry + serviceNames?: string[] force?: boolean forceBuild?: boolean } @@ -119,11 +120,11 @@ export class ActionHelper implements TypeGuard { * run `garden init` */ async prepareEnvironment( - { force = false, pluginName, logEntry, allowUserInput = false }: - { force?: boolean, pluginName?: string, logEntry?: LogEntry, allowUserInput?: boolean }, + { force = false, pluginName, log, allowUserInput = false }: + { force?: boolean, pluginName?: string, log: LogEntry, allowUserInput?: boolean }, ) { const handlers = this.garden.getActionHandlers("prepareEnvironment", pluginName) - const statuses = await this.getEnvironmentStatus({ pluginName }) + const statuses = await this.getEnvironmentStatus({ pluginName, log }) const needUserInput = Object.entries(statuses) .map(([name, status]) => ({ ...status, name })) @@ -151,13 +152,13 @@ export class ActionHelper implements TypeGuard { continue } - const envLogEntry = (logEntry || this.garden.log).info({ + const envLogEntry = (log || this.garden.log).info({ status: "active", section: name, msg: "Preparing environment...", }) - await handler({ ...this.commonParams(handler), force, status, logEntry: envLogEntry }) + await handler({ ...this.commonParams(handler), force, status, log: envLogEntry }) envLogEntry.setSuccess("Configured") @@ -168,11 +169,11 @@ export class ActionHelper implements TypeGuard { } async cleanupEnvironment( - { pluginName }: ActionHelperParams, + { pluginName, log }: ActionHelperParams, ): Promise { const handlers = this.garden.getActionHandlers("cleanupEnvironment", pluginName) await Bluebird.each(values(handlers), h => h({ ...this.commonParams(h) })) - return this.getEnvironmentStatus({ pluginName }) + return this.getEnvironmentStatus({ pluginName, log }) } async getSecret(params: RequirePluginName>): Promise { @@ -254,13 +255,13 @@ export class ActionHelper implements TypeGuard { } async deleteService(params: ServiceActionHelperParams): Promise { - const logEntry = this.garden.log.info({ + const log = this.garden.log.info({ section: params.service.name, msg: "Deleting...", status: "active", }) return this.callServiceHandler({ - params: { ...params, logEntry }, + params: { ...params, log }, actionType: "deleteService", defaultHandler: dummyDeleteServiceHandler, }) @@ -292,14 +293,14 @@ export class ActionHelper implements TypeGuard { //region Helper Methods //=========================================================================== - async getStatus(): Promise { - const envStatus: EnvironmentStatusMap = await this.getEnvironmentStatus({}) + async getStatus({ log }: { log: LogEntry }): Promise { + const envStatus: EnvironmentStatusMap = await this.getEnvironmentStatus({ log }) const services = keyBy(await this.garden.getServices(), "name") const serviceStatus = await Bluebird.props(mapValues(services, async (service: Service) => { const dependencies = await this.garden.getServices(service.config.dependencies) const runtimeContext = await prepareRuntimeContext(this.garden, service.module, dependencies) - return this.getServiceStatus({ service, runtimeContext }) + return this.getServiceStatus({ service, runtimeContext, log }) })) return { @@ -309,7 +310,7 @@ export class ActionHelper implements TypeGuard { } async deployServices( - { serviceNames, force = false, forceBuild = false }: DeployServicesParams, + { serviceNames, force = false, forceBuild = false, log }: DeployServicesParams, ): Promise { const services = await this.garden.getServices(serviceNames) @@ -319,6 +320,7 @@ export class ActionHelper implements TypeGuard { watch: false, handler: async (module) => getDeployTasks({ garden: this.garden, + log, module, serviceNames, force, @@ -331,11 +333,11 @@ export class ActionHelper implements TypeGuard { //endregion // TODO: find a nicer way to do this (like a type-safe wrapper function) - private commonParams(handler, logEntry?: LogEntry): PluginActionParamsBase { + private commonParams(handler, log?: LogEntry): PluginActionParamsBase { return { ctx: createPluginContext(this.garden, handler["pluginName"]), // TODO: find a better way for handlers to log during execution - logEntry, + log: log || this.garden.log.info(), } } @@ -410,8 +412,8 @@ export class ActionHelper implements TypeGuard { } } -const dummyLogStreamer = async ({ service, logEntry }: GetServiceLogsParams) => { - logEntry && logEntry.warn({ +const dummyLogStreamer = async ({ service, log }: GetServiceLogsParams) => { + log.warn({ section: service.name, msg: chalk.yellow(`No handler for log retrieval available for module type ${service.module.type}`), }) @@ -429,8 +431,8 @@ const dummyPublishHandler = async ({ module }) => { } } -const dummyDeleteServiceHandler = async ({ module, logEntry }: DeleteServiceParams) => { +const dummyDeleteServiceHandler = async ({ module, log }: DeleteServiceParams) => { const msg = `No delete service handler available for module type ${module.type}` - logEntry && logEntry.setError(msg) + log.setError(msg) return {} } diff --git a/garden-service/src/cli/cli.ts b/garden-service/src/cli/cli.ts index 8bd527a2181..bdc53240bd5 100644 --- a/garden-service/src/cli/cli.ts +++ b/garden-service/src/cli/cli.ts @@ -238,9 +238,11 @@ export class GardenCli { contextOpts.config = MOCK_CONFIG } garden = await Garden.factory(root, contextOpts) + const log = garden.log.info() // TODO: enforce that commands always output DeepPrimitiveMap result = await command.action({ garden, + log, args: parsedArgs, opts: parsedOpts, }) diff --git a/garden-service/src/commands/base.ts b/garden-service/src/commands/base.ts index e10bebb9ad0..6b046746eaf 100644 --- a/garden-service/src/commands/base.ts +++ b/garden-service/src/commands/base.ts @@ -14,6 +14,7 @@ import { TaskResults } from "../task-graph" import { LoggerType } from "../logger/logger" import { ProcessResults } from "../process" import { Garden } from "../garden" +import { LogEntry } from "../logger/log-entry" export class ValidationError extends Error { } @@ -188,6 +189,7 @@ export interface CommandParams opts: ParameterValues garden: Garden + log: LogEntry } export abstract class Command { diff --git a/garden-service/src/commands/build.ts b/garden-service/src/commands/build.ts index a4f9c5cc0ee..b2ec750b568 100644 --- a/garden-service/src/commands/build.ts +++ b/garden-service/src/commands/build.ts @@ -55,7 +55,7 @@ export class BuildCommand extends Command { options = buildOptions async action( - { args, opts, garden }: CommandParams, + { args, opts, garden, log }: CommandParams, ): Promise> { await garden.clearBuilds() @@ -70,11 +70,11 @@ export class BuildCommand extends Command { garden, modules, watch: opts.watch, - handler: async (module) => [new BuildTask({ garden, module, force: opts.force })], + handler: async (module) => [new BuildTask({ garden, log, module, force: opts.force })], changeHandler: async (module: Module) => { return (await withDependants(garden, [module], autoReloadDependants)) .filter(m => moduleNames.includes(m.name)) - .map(m => new BuildTask({ garden, module: m, force: true })) + .map(m => new BuildTask({ garden, log, module: m, force: true })) }, }) diff --git a/garden-service/src/commands/call.ts b/garden-service/src/commands/call.ts index d755bffa30b..459b3a13cc4 100644 --- a/garden-service/src/commands/call.ts +++ b/garden-service/src/commands/call.ts @@ -49,12 +49,12 @@ export class CallCommand extends Command { arguments = callArgs - async action({ garden, args }: CommandParams): Promise { + async action({ garden, log, args }: CommandParams): Promise { let [serviceName, path] = splitFirst(args.serviceAndPath, "/") // TODO: better error when service doesn't exist const service = await garden.getService(serviceName) - const status = await garden.actions.getServiceStatus({ service }) + const status = await garden.actions.getServiceStatus({ service, log }) if (status.state !== "ready") { throw new RuntimeError(`Service ${service.name} is not running`, { diff --git a/garden-service/src/commands/delete.ts b/garden-service/src/commands/delete.ts index c9d367b381e..0df26867fad 100644 --- a/garden-service/src/commands/delete.ts +++ b/garden-service/src/commands/delete.ts @@ -64,9 +64,11 @@ export class DeleteSecretCommand extends Command { arguments = deleteSecretArgs - async action({ garden, args }: CommandParams): Promise> { + async action( + { garden, log, args }: CommandParams, + ): Promise> { const key = args.key! - const result = await garden.actions.deleteSecret({ pluginName: args.provider!, key }) + const result = await garden.actions.deleteSecret({ log, pluginName: args.provider!, key }) if (result.found) { garden.log.info(`Deleted config key ${args.key}`) @@ -91,11 +93,11 @@ export class DeleteEnvironmentCommand extends Command { resources. ` - async action({ garden }: CommandParams): Promise> { + async action({ garden, log }: CommandParams): Promise> { const { name } = garden.environment garden.log.header({ emoji: "skull_and_crossbones", command: `Deleting ${name} environment` }) - const result = await garden.actions.cleanupEnvironment({}) + const result = await garden.actions.cleanupEnvironment({ log }) garden.log.finish() @@ -126,7 +128,7 @@ export class DeleteServiceCommand extends Command { garden delete service my-service # deletes my-service ` - async action({ garden, args }: CommandParams): Promise { + async action({ garden, log, args }: CommandParams): Promise { const services = await garden.getServices(args.service) if (services.length === 0) { @@ -139,7 +141,7 @@ export class DeleteServiceCommand extends Command { const result: { [key: string]: ServiceStatus } = {} await Bluebird.map(services, async service => { - result[service.name] = await garden.actions.deleteService({ service }) + result[service.name] = await garden.actions.deleteService({ log, service }) }) garden.log.finish() diff --git a/garden-service/src/commands/deploy.ts b/garden-service/src/commands/deploy.ts index 177c342a063..ba2fe8d9af9 100644 --- a/garden-service/src/commands/deploy.ts +++ b/garden-service/src/commands/deploy.ts @@ -58,7 +58,7 @@ export class DeployCommand extends Command { arguments = deployArgs options = deployOpts - async action({ garden, args, opts }: CommandParams): Promise> { + async action({ garden, log, args, opts }: CommandParams): Promise> { const services = await garden.getServices(args.service) const serviceNames = getNames(services) @@ -70,7 +70,7 @@ export class DeployCommand extends Command { garden.log.header({ emoji: "rocket", command: "Deploy" }) // TODO: make this a task - await garden.actions.prepareEnvironment({}) + await garden.actions.prepareEnvironment({ log }) const results = await processServices({ garden, @@ -78,6 +78,7 @@ export class DeployCommand extends Command { watch: opts.watch, handler: async (module) => getDeployTasks({ garden, + log, module, serviceNames, force: opts.force, @@ -86,6 +87,7 @@ export class DeployCommand extends Command { }), changeHandler: async (module) => getDeployTasks({ garden, + log, module, serviceNames, force: true, diff --git a/garden-service/src/commands/dev.ts b/garden-service/src/commands/dev.ts index 4a297c3f9d2..871808a4598 100644 --- a/garden-service/src/commands/dev.ts +++ b/garden-service/src/commands/dev.ts @@ -44,14 +44,14 @@ export class DevCommand extends Command { garden dev ` - async action({ garden }: CommandParams): Promise { + async action({ garden, log }: CommandParams): Promise { // print ANSI banner image const data = await readFile(ansiBannerPath) console.log(data.toString()) garden.log.info(chalk.gray.italic(`\nGood ${getGreetingTime()}! Let's get your environment wired up...\n`)) - await garden.actions.prepareEnvironment({}) + await garden.actions.prepareEnvironment({ log }) const autoReloadDependants = await computeAutoReloadDependants(garden) const modules = await garden.getModules() @@ -72,15 +72,15 @@ export class DevCommand extends Command { : [module] const testTasks: Task[] = flatten(await Bluebird.map( - testModules, m => getTestTasks({ garden, module: m }))) + testModules, m => getTestTasks({ garden, log, module: m }))) const deployTasks = await getDeployTasks({ - garden, module, force: watch, forceBuild: watch, includeDependants: watch, + garden, log, module, force: watch, forceBuild: watch, includeDependants: watch, }) const tasks = testTasks.concat(deployTasks) if (tasks.length === 0) { - return [new BuildTask({ garden, module, force: watch })] + return [new BuildTask({ garden, log, module, force: watch })] } else { return tasks } diff --git a/garden-service/src/commands/exec.ts b/garden-service/src/commands/exec.ts index 8271a532280..e5aa8d4cf87 100644 --- a/garden-service/src/commands/exec.ts +++ b/garden-service/src/commands/exec.ts @@ -58,7 +58,7 @@ export class ExecCommand extends Command { options = runOpts loggerType = LoggerType.basic - async action({ garden, args }: CommandParams): Promise> { + async action({ garden, log, args }: CommandParams): Promise> { const serviceName = args.service const command = args.command || [] @@ -68,7 +68,7 @@ export class ExecCommand extends Command { }) const service = await garden.getService(serviceName) - const result = await garden.actions.execInService({ service, command }) + const result = await garden.actions.execInService({ log, service, command }) return { result } } diff --git a/garden-service/src/commands/get.ts b/garden-service/src/commands/get.ts index c888952a2cd..2f9b772ce3d 100644 --- a/garden-service/src/commands/get.ts +++ b/garden-service/src/commands/get.ts @@ -62,7 +62,11 @@ export class GetSecretCommand extends Command { async action({ garden, args }: CommandParams): Promise { const key = args.key - const { value } = await garden.actions.getSecret({ pluginName: args.provider, key }) + const { value } = await garden.actions.getSecret({ + pluginName: args.provider, + key, + log: garden.log.info(), + }) if (value === null || value === undefined) { throw new NotFoundError(`Could not find config key ${key}`, { key }) @@ -79,7 +83,7 @@ export class GetStatusCommand extends Command { help = "Outputs the status of your environment." async action({ garden }: CommandParams): Promise> { - const status = await garden.actions.getStatus() + const status = await garden.actions.getStatus({ log: garden.log.info() }) const yamlStatus = yaml.safeDump(status, { noRefs: true, skipInvalid: true }) // TODO: do a nicer print of this by default and add --yaml/--json options (maybe globally) for exporting diff --git a/garden-service/src/commands/init.ts b/garden-service/src/commands/init.ts index c93a0730fe4..c45f8811ea8 100644 --- a/garden-service/src/commands/init.ts +++ b/garden-service/src/commands/init.ts @@ -36,11 +36,11 @@ export class InitCommand extends Command { options = initOpts - async action({ garden, opts }: CommandParams<{}, Opts>): Promise> { + async action({ garden, log, opts }: CommandParams<{}, Opts>): Promise> { const { name } = garden.environment garden.log.header({ emoji: "gear", command: `Initializing ${name} environment` }) - await garden.actions.prepareEnvironment({ force: opts.force, allowUserInput: true }) + await garden.actions.prepareEnvironment({ log, force: opts.force, allowUserInput: true }) garden.log.info("") garden.log.header({ emoji: "heavy_check_mark", command: `Done!` }) diff --git a/garden-service/src/commands/logs.ts b/garden-service/src/commands/logs.ts index a02a73100d1..5a1944cecc4 100644 --- a/garden-service/src/commands/logs.ts +++ b/garden-service/src/commands/logs.ts @@ -55,7 +55,7 @@ export class LogsCommand extends Command { options = logsOpts loggerType = LoggerType.basic - async action({ garden, args, opts }: CommandParams): Promise> { + async action({ garden, log, args, opts }: CommandParams): Promise> { const tail = opts.tail const services = await garden.getServices(args.service) @@ -87,7 +87,7 @@ export class LogsCommand extends Command { // NOTE: This will work differently when we have Elasticsearch set up for logging, but is // quite servicable for now. await Bluebird.map(services, async (service: Service) => { - await garden.actions.getServiceLogs({ service, stream, tail }) + await garden.actions.getServiceLogs({ service, stream, tail, log }) }) return { result } diff --git a/garden-service/src/commands/publish.ts b/garden-service/src/commands/publish.ts index d3e6ed56571..3a2ac752cce 100644 --- a/garden-service/src/commands/publish.ts +++ b/garden-service/src/commands/publish.ts @@ -19,6 +19,7 @@ import { PublishTask } from "../tasks/publish" import { RuntimeError } from "../exceptions" import { TaskResults } from "../task-graph" import { Garden } from "../garden" +import { LogEntry } from "../logger/log-entry" import dedent = require("dedent") const publishArgs = { @@ -59,12 +60,12 @@ export class PublishCommand extends Command { arguments = publishArgs options = publishOpts - async action({ garden, args, opts }: CommandParams): Promise> { + async action({ garden, log, args, opts }: CommandParams): Promise> { garden.log.header({ emoji: "rocket", command: "Publish modules" }) const modules = await garden.getModules(args.module) - const results = await publishModules(garden, modules, !!opts["force-build"], !!opts["allow-dirty"]) + const results = await publishModules(garden, log, modules, !!opts["force-build"], !!opts["allow-dirty"]) return handleTaskResults(garden, "publish", { taskResults: results }) } @@ -72,6 +73,7 @@ export class PublishCommand extends Command { export async function publishModules( garden: Garden, + log: LogEntry, modules: Module[], forceBuild: boolean, allowDirty: boolean, @@ -87,7 +89,7 @@ export async function publishModules( ) } - const task = new PublishTask({ garden, module, forceBuild }) + const task = new PublishTask({ garden, log, module, forceBuild }) await garden.addTask(task) } diff --git a/garden-service/src/commands/run/module.ts b/garden-service/src/commands/run/module.ts index a08ebd03aff..e7f5deb9e65 100644 --- a/garden-service/src/commands/run/module.ts +++ b/garden-service/src/commands/run/module.ts @@ -67,7 +67,7 @@ export class RunModuleCommand extends Command { arguments = runArgs options = runOpts - async action({ garden, args, opts }: CommandParams): Promise> { + async action({ garden, log, args, opts }: CommandParams): Promise> { const moduleName = args.module const module = await garden.getModule(moduleName) @@ -80,9 +80,9 @@ export class RunModuleCommand extends Command { command: msg, }) - await garden.actions.prepareEnvironment({}) + await garden.actions.prepareEnvironment({ log }) - const buildTask = new BuildTask({ garden, module, force: opts["force-build"] }) + const buildTask = new BuildTask({ garden, log, module, force: opts["force-build"] }) await garden.addTask(buildTask) await garden.processTasks() @@ -99,6 +99,7 @@ export class RunModuleCommand extends Command { garden.log.info("") const result = await garden.actions.runModule({ + log, module, command, runtimeContext, diff --git a/garden-service/src/commands/run/service.ts b/garden-service/src/commands/run/service.ts index e09eaf11b79..3c8322204b5 100644 --- a/garden-service/src/commands/run/service.ts +++ b/garden-service/src/commands/run/service.ts @@ -50,7 +50,7 @@ export class RunServiceCommand extends Command { arguments = runArgs options = runOpts - async action({ garden, args, opts }: CommandParams): Promise> { + async action({ garden, log, args, opts }: CommandParams): Promise> { const serviceName = args.service const service = await garden.getService(serviceName) const module = service.module @@ -60,9 +60,9 @@ export class RunServiceCommand extends Command { command: `Running service ${chalk.cyan(serviceName)} in module ${chalk.cyan(module.name)}`, }) - await garden.actions.prepareEnvironment({}) + await garden.actions.prepareEnvironment({ log }) - const buildTask = new BuildTask({ garden, module, force: opts["force-build"] }) + const buildTask = new BuildTask({ garden, log, module, force: opts["force-build"] }) await garden.addTask(buildTask) await garden.processTasks() @@ -71,7 +71,13 @@ export class RunServiceCommand extends Command { printRuntimeContext(garden, runtimeContext) - const result = await garden.actions.runService({ service, runtimeContext, silent: false, interactive: true }) + const result = await garden.actions.runService({ + log, + service, + runtimeContext, + silent: false, + interactive: true, + }) return { result } } diff --git a/garden-service/src/commands/run/test.ts b/garden-service/src/commands/run/test.ts index c2506c77038..2ea0e70862b 100644 --- a/garden-service/src/commands/run/test.ts +++ b/garden-service/src/commands/run/test.ts @@ -64,7 +64,7 @@ export class RunTestCommand extends Command { arguments = runArgs options = runOpts - async action({ garden, args, opts }: CommandParams): Promise> { + async action({ garden, log, args, opts }: CommandParams): Promise> { const moduleName = args.module const testName = args.test const module = await garden.getModule(moduleName) @@ -84,9 +84,9 @@ export class RunTestCommand extends Command { command: `Running test ${chalk.cyan(testName)} in module ${chalk.cyan(moduleName)}`, }) - await garden.actions.prepareEnvironment({}) + await garden.actions.prepareEnvironment({ log }) - const buildTask = new BuildTask({ garden, module, force: opts["force-build"] }) + const buildTask = new BuildTask({ garden, log, module, force: opts["force-build"] }) await garden.addTask(buildTask) await garden.processTasks() @@ -97,6 +97,7 @@ export class RunTestCommand extends Command { printRuntimeContext(garden, runtimeContext) const result = await garden.actions.testModule({ + log, module, interactive, runtimeContext, diff --git a/garden-service/src/commands/set.ts b/garden-service/src/commands/set.ts index 8397f8b791a..800907f63a4 100644 --- a/garden-service/src/commands/set.ts +++ b/garden-service/src/commands/set.ts @@ -64,9 +64,14 @@ export class SetSecretCommand extends Command { arguments = setSecretArgs - async action({ garden, args }: CommandParams): Promise> { + async action({ garden, log, args }: CommandParams): Promise> { const key = args.key - const result = await garden.actions.setSecret({ pluginName: args.provider, key, value: args.value }) + const result = await garden.actions.setSecret({ + pluginName: args.provider, + key, + value: args.value, + log, + }) garden.log.info(`Set config key ${args.key}`) return { result } } diff --git a/garden-service/src/commands/test.ts b/garden-service/src/commands/test.ts index 8072f7d7b9d..b6a1ca573e7 100644 --- a/garden-service/src/commands/test.ts +++ b/garden-service/src/commands/test.ts @@ -66,7 +66,7 @@ export class TestCommand extends Command { arguments = testArgs options = testOpts - async action({ garden, args, opts }: CommandParams): Promise> { + async action({ garden, log, args, opts }: CommandParams): Promise> { const autoReloadDependants = await computeAutoReloadDependants(garden) let modules: Module[] if (args.module) { @@ -81,7 +81,7 @@ export class TestCommand extends Command { command: `Running tests`, }) - await garden.actions.prepareEnvironment({}) + await garden.actions.prepareEnvironment({ log }) const name = opts.name const force = opts.force @@ -91,12 +91,12 @@ export class TestCommand extends Command { garden, modules, watch: opts.watch, - handler: async (module) => getTestTasks({ garden, module, name, force, forceBuild }), + handler: async (module) => getTestTasks({ garden, log, module, name, force, forceBuild }), changeHandler: async (module) => { const modulesToProcess = await withDependants(garden, [module], autoReloadDependants) return flatten(await Bluebird.map( modulesToProcess, - m => getTestTasks({ garden, module: m, name, force, forceBuild }))) + m => getTestTasks({ garden, log, module: m, name, force, forceBuild }))) }, }) diff --git a/garden-service/src/commands/update-remote/all.ts b/garden-service/src/commands/update-remote/all.ts index 90ced17490d..9a8edeae2f8 100644 --- a/garden-service/src/commands/update-remote/all.ts +++ b/garden-service/src/commands/update-remote/all.ts @@ -32,15 +32,25 @@ export class UpdateRemoteAllCommand extends Command { garden update-remote all # update all remote sources and modules in the project ` - async action({ garden }: CommandParams): Promise> { + async action({ garden, log }: CommandParams): Promise> { garden.log.header({ emoji: "hammer_and_wrench", command: "update-remote all" }) const sourcesCmd = new UpdateRemoteSourcesCommand() const modulesCmd = new UpdateRemoteModulesCommand() - const { result: projectSources } = await sourcesCmd.action({ garden, args: { source: undefined }, opts: {} }) - const { result: moduleSources } = await modulesCmd.action({ garden, args: { module: undefined }, opts: {} }) + const { result: projectSources } = await sourcesCmd.action({ + garden, + log, + args: { source: undefined }, + opts: {}, + }) + const { result: moduleSources } = await modulesCmd.action({ + garden, + log, + args: { module: undefined }, + opts: {}, + }) return { result: { projectSources: projectSources!, moduleSources: moduleSources! } } } diff --git a/garden-service/src/commands/update-remote/modules.ts b/garden-service/src/commands/update-remote/modules.ts index a377ca259a2..f9e4e11cc96 100644 --- a/garden-service/src/commands/update-remote/modules.ts +++ b/garden-service/src/commands/update-remote/modules.ts @@ -74,7 +74,7 @@ export class UpdateRemoteModulesCommand extends Command { // TODO Update remotes in parallel. Currently not possible since updating might // trigger a username and password prompt from git. for (const { name, repositoryUrl } of moduleSources) { - await garden.vcs.updateRemoteSource({ name, url: repositoryUrl, sourceType: "module", logEntry: garden.log }) + await garden.vcs.updateRemoteSource({ name, url: repositoryUrl, sourceType: "module", log: garden.log }) } await pruneRemoteSources({ projectRoot: garden.projectRoot, type: "module", sources: moduleSources }) diff --git a/garden-service/src/commands/update-remote/sources.ts b/garden-service/src/commands/update-remote/sources.ts index 247e9835078..c6d7120e817 100644 --- a/garden-service/src/commands/update-remote/sources.ts +++ b/garden-service/src/commands/update-remote/sources.ts @@ -69,7 +69,7 @@ export class UpdateRemoteSourcesCommand extends Command { // TODO Update remotes in parallel. Currently not possible since updating might // trigger a username and password prompt from git. for (const { name, repositoryUrl } of projectSources) { - await garden.vcs.updateRemoteSource({ name, url: repositoryUrl, sourceType: "project", logEntry: garden.log }) + await garden.vcs.updateRemoteSource({ name, url: repositoryUrl, sourceType: "project", log: garden.log }) } await pruneRemoteSources({ projectRoot: garden.projectRoot, type: "project", sources: projectSources }) diff --git a/garden-service/src/config/config-context.ts b/garden-service/src/config/config-context.ts index 0782e734dff..3f168524d5f 100644 --- a/garden-service/src/config/config-context.ts +++ b/garden-service/src/config/config-context.ts @@ -16,6 +16,7 @@ import { Service } from "../types/service" import { resolveTemplateString } from "../template-string" import * as Joi from "joi" import { Garden } from "../garden" +import { LogEntry } from "../logger/log-entry" export type ContextKey = string[] @@ -281,6 +282,7 @@ export class ModuleConfigContext extends ProjectConfigContext { constructor( garden: Garden, + log: LogEntry, environment: Environment, moduleConfigs: ModuleConfig[], ) { @@ -304,7 +306,7 @@ export class ModuleConfigContext extends ProjectConfigContext { const service = await garden.getService(name) const outputs = { ...service.config.outputs, - ...await garden.actions.getServiceOutputs({ service }), + ...await garden.actions.getServiceOutputs({ log, service }), } return new ServiceContext(_this, service, outputs) }], diff --git a/garden-service/src/garden.ts b/garden-service/src/garden.ts index df6c8f66749..5b98aa2e05c 100644 --- a/garden-service/src/garden.ts +++ b/garden-service/src/garden.ts @@ -410,7 +410,7 @@ export class Garden { plugin = await factory({ projectName: this.projectName, config, - logEntry: this.log, + log: this.log, }) } catch (error) { throw new PluginError(`Unexpected error when loading plugin "${pluginName}": ${error}`, { @@ -699,7 +699,7 @@ export class Garden { await this.detectCircularDependencies() const moduleConfigContext = new ModuleConfigContext( - this, this.environment, Object.values(this.moduleConfigs), + this, this.log.info(), this.environment, Object.values(this.moduleConfigs), ) this.moduleConfigs = await resolveTemplateStrings(this.moduleConfigs, moduleConfigContext) }) @@ -827,7 +827,7 @@ export class Garden { return linked.path } - const path = await this.vcs.ensureRemoteSource({ name, sourceType, url: repositoryUrl, logEntry: this.log }) + const path = await this.vcs.ensureRemoteSource({ name, sourceType, url: repositoryUrl, log: this.log }) return path } diff --git a/garden-service/src/logger/writers/fancy-terminal-writer.ts b/garden-service/src/logger/writers/fancy-terminal-writer.ts index f12203e26a8..cd036947d42 100644 --- a/garden-service/src/logger/writers/fancy-terminal-writer.ts +++ b/garden-service/src/logger/writers/fancy-terminal-writer.ts @@ -137,24 +137,24 @@ export class FancyTerminalWriter extends Writer { ) } - private handleGraphChange(logEntry: LogEntry, logger: Logger, didWrite: boolean = false) { + private handleGraphChange(log: LogEntry, logger: Logger, didWrite: boolean = false) { this.updatePending = false // Suspend processing and write immediately if a lot of data is being intercepted, e.g. when user is typing in input - if (logEntry.fromStdStream() && !didWrite) { + if (log.fromStdStream() && !didWrite) { const now = Date.now() const throttleProcessing = this.lastInterceptAt && (now - this.lastInterceptAt) < THROTTLE_MS this.lastInterceptAt = now if (throttleProcessing) { this.stopLoop() - this.stream.write(renderMsg(logEntry)) + this.stream.write(renderMsg(log)) this.updatePending = true // Resume processing if idle and original update is still pending setTimeout(() => { if (this.updatePending) { - this.handleGraphChange(logEntry, logger, true) + this.handleGraphChange(log, logger, true) } }, THROTTLE_MS) return @@ -162,7 +162,7 @@ export class FancyTerminalWriter extends Writer { } const terminalEntries = this.toTerminalEntries(logger) - const nextEntry = terminalEntries.find(e => e.key === logEntry.key) + const nextEntry = terminalEntries.find(e => e.key === log.key) // Nothing to do, e.g. because entry level is higher than writer level if (!nextEntry) { @@ -241,12 +241,12 @@ export class FancyTerminalWriter extends Writer { return terminalEntries.map(e => e.text).join("").split("\n") } - public onGraphChange(logEntry: LogEntry, logger: Logger): void { + public onGraphChange(log: LogEntry, logger: Logger): void { if (!this.stream) { this.stream = this.initStream(logger) } - this.handleGraphChange(logEntry, logger, false) + this.handleGraphChange(log, logger, false) } public stop(): void { diff --git a/garden-service/src/plugins/container.ts b/garden-service/src/plugins/container.ts index fba0781dee4..503181645b8 100644 --- a/garden-service/src/plugins/container.ts +++ b/garden-service/src/plugins/container.ts @@ -450,11 +450,11 @@ export const gardenPlugin = (): GardenPlugin => ({ container: { validate: validateContainerModule, - async getBuildStatus({ module, logEntry }: GetBuildStatusParams) { + async getBuildStatus({ module, log }: GetBuildStatusParams) { const identifier = await helpers.imageExistsLocally(module) if (identifier) { - logEntry && logEntry.debug({ + log.debug({ section: module.name, msg: `Image ${identifier} already exists`, symbol: "info", @@ -464,7 +464,7 @@ export const gardenPlugin = (): GardenPlugin => ({ return { ready: !!identifier } }, - async build({ module, logEntry }: BuildModuleParams) { + async build({ module, log }: BuildModuleParams) { const buildPath = module.buildPath const image = module.spec.image @@ -472,7 +472,7 @@ export const gardenPlugin = (): GardenPlugin => ({ if (await helpers.imageExistsLocally(module)) { return { fresh: false } } - logEntry && logEntry.setState(`Pulling image ${image}...`) + log.setState(`Pulling image ${image}...`) await helpers.pullImage(module) return { fetched: true } } @@ -480,7 +480,7 @@ export const gardenPlugin = (): GardenPlugin => ({ const identifier = await helpers.getLocalImageId(module) // build doesn't exist, so we create it - logEntry && logEntry.setState(`Building ${identifier}...`) + log.setState(`Building ${identifier}...`) const buildArgs = Object.entries(module.spec.buildArgs).map(([key, value]) => { // TODO: may need to escape this @@ -494,16 +494,16 @@ export const gardenPlugin = (): GardenPlugin => ({ return { fresh: true, details: { identifier } } }, - async publishModule({ module, logEntry }: PublishModuleParams) { + async publishModule({ module, log }: PublishModuleParams) { if (!(await helpers.hasDockerfile(module))) { - logEntry && logEntry.setState({ msg: `Nothing to publish` }) + log.setState({ msg: `Nothing to publish` }) return { published: false } } const localId = await helpers.getLocalImageId(module) const remoteId = await helpers.getPublicImageId(module) - logEntry && logEntry.setState({ msg: `Publishing image ${remoteId}...` }) + log.setState({ msg: `Publishing image ${remoteId}...` }) if (localId !== remoteId) { await helpers.dockerCli(module, `tag ${localId} ${remoteId}`) diff --git a/garden-service/src/plugins/google/common.ts b/garden-service/src/plugins/google/common.ts index df63ace5059..e49bbf1a2aa 100644 --- a/garden-service/src/plugins/google/common.ts +++ b/garden-service/src/plugins/google/common.ts @@ -61,7 +61,7 @@ export async function getEnvironmentStatus() { return output } -export async function prepareEnvironment({ status, logEntry }: PrepareEnvironmentParams) { +export async function prepareEnvironment({ status, log }: PrepareEnvironmentParams) { if (!status.detail.sdkInstalled) { throw new ConfigurationError( "Google Cloud SDK is not installed. " + @@ -71,7 +71,7 @@ export async function prepareEnvironment({ status, logEntry }: PrepareEnvironmen } if (!status.detail.betaComponentsInstalled) { - logEntry && logEntry.info({ + log.info({ section: "google-cloud-functions", msg: `Installing gcloud SDK beta components...`, }) @@ -80,7 +80,7 @@ export async function prepareEnvironment({ status, logEntry }: PrepareEnvironmen } if (!status.detail.sdkInitialized) { - logEntry && logEntry.info({ + log.info({ section: "google-cloud-functions", msg: `Initializing SDK...`, }) diff --git a/garden-service/src/plugins/google/google-app-engine.ts b/garden-service/src/plugins/google/google-app-engine.ts index 93b1b74d418..cd5d6fda5b2 100644 --- a/garden-service/src/plugins/google/google-app-engine.ts +++ b/garden-service/src/plugins/google/google-app-engine.ts @@ -55,8 +55,8 @@ export const gardenPlugin = (): GardenPlugin => ({ return {} }, - async deployService({ ctx, service, runtimeContext, logEntry }: DeployServiceParams) { - logEntry && logEntry.info({ + async deployService({ ctx, service, runtimeContext, log }: DeployServiceParams) { + log.info({ section: service.name, msg: `Deploying app...`, }) @@ -72,7 +72,7 @@ export const gardenPlugin = (): GardenPlugin => ({ if (config.healthCheck) { if (config.healthCheck.tcpPort || config.healthCheck.command) { - logEntry && logEntry.warn({ + log.warn({ section: service.name, msg: "GAE only supports httpGet health checks", }) @@ -94,7 +94,7 @@ export const gardenPlugin = (): GardenPlugin => ({ "app", "deploy", "--quiet", ], { cwd: service.module.path }) - logEntry && logEntry.info({ section: service.name, msg: `App deployed` }) + log.info({ section: service.name, msg: `App deployed` }) return {} }, diff --git a/garden-service/src/plugins/google/google-cloud-functions.ts b/garden-service/src/plugins/google/google-cloud-functions.ts index 06dfe3dcdec..a7d84188846 100644 --- a/garden-service/src/plugins/google/google-cloud-functions.ts +++ b/garden-service/src/plugins/google/google-cloud-functions.ts @@ -110,7 +110,7 @@ export const gardenPlugin = (): GardenPlugin => ({ validate: parseGcfModule, async deployService( - { ctx, module, service, runtimeContext, logEntry }: DeployServiceParams, + { ctx, module, service, runtimeContext, log }: DeployServiceParams, ) { // TODO: provide env vars somehow to function const project = getProject(service, ctx.provider) @@ -126,7 +126,7 @@ export const gardenPlugin = (): GardenPlugin => ({ "--trigger-http", ]) - return getServiceStatus({ ctx, module, service, runtimeContext, logEntry }) + return getServiceStatus({ ctx, module, service, runtimeContext, log }) }, async getServiceOutputs({ ctx, service }: GetServiceOutputsParams) { diff --git a/garden-service/src/plugins/kubernetes/actions.ts b/garden-service/src/plugins/kubernetes/actions.ts index cdaf748ef54..1e26a4814f8 100644 --- a/garden-service/src/plugins/kubernetes/actions.ts +++ b/garden-service/src/plugins/kubernetes/actions.ts @@ -61,12 +61,12 @@ export async function validate(params: ValidateModuleParams) { } export async function deleteService(params: DeleteServiceParams): Promise { - const { ctx, logEntry, service } = params + const { ctx, log, service } = params const namespace = await getAppNamespace(ctx, ctx.provider) const provider = ctx.provider await deleteContainerService( - { provider, namespace, serviceName: service.name, logEntry }) + { provider, namespace, serviceName: service.name, log }) return getContainerServiceStatus(params) } @@ -175,7 +175,7 @@ export async function runModule( } export async function runService( - { ctx, service, interactive, runtimeContext, silent, timeout, logEntry }: + { ctx, service, interactive, runtimeContext, silent, timeout, log }: RunServiceParams, ) { return runModule({ @@ -186,12 +186,12 @@ export async function runService( runtimeContext, silent, timeout, - logEntry, + log, }) } export async function testModule( - { ctx, interactive, module, runtimeContext, silent, testConfig, logEntry }: + { ctx, interactive, module, runtimeContext, silent, testConfig, log }: TestModuleParams, ): Promise { const testName = testConfig.name @@ -207,7 +207,7 @@ export async function testModule( runtimeContext, silent, timeout, - logEntry, + log, }) const api = new KubeApi(ctx.provider) diff --git a/garden-service/src/plugins/kubernetes/deployment.ts b/garden-service/src/plugins/kubernetes/deployment.ts index c082062863f..15611ceb06b 100644 --- a/garden-service/src/plugins/kubernetes/deployment.ts +++ b/garden-service/src/plugins/kubernetes/deployment.ts @@ -50,7 +50,7 @@ export async function getContainerServiceStatus( } export async function deployContainerService(params: DeployServiceParams): Promise { - const { ctx, service, runtimeContext, force, logEntry } = params + const { ctx, service, runtimeContext, force, log } = params const provider = ctx.provider const namespace = await getAppNamespace(ctx, provider) @@ -59,7 +59,7 @@ export async function deployContainerService(params: DeployServiceParams) { +export async function pushModule({ ctx, module, log }: PushModuleParams) { if (!(await helpers.hasDockerfile(module))) { - logEntry && logEntry.setState({ msg: `Nothing to push` }) + log.setState({ msg: `Nothing to push` }) return { pushed: false } } const localId = await helpers.getLocalImageId(module) const remoteId = await helpers.getDeploymentImageId(module, ctx.provider.config.deploymentRegistry) - logEntry && logEntry.setState({ msg: `Pushing image ${remoteId}...` }) + log.setState({ msg: `Pushing image ${remoteId}...` }) await helpers.dockerCli(module, `tag ${localId} ${remoteId}`) await helpers.dockerCli(module, `push ${remoteId}`) diff --git a/garden-service/src/plugins/kubernetes/helm.ts b/garden-service/src/plugins/kubernetes/helm.ts index 8cf62d9fd49..629d422f670 100644 --- a/garden-service/src/plugins/kubernetes/helm.ts +++ b/garden-service/src/plugins/kubernetes/helm.ts @@ -136,7 +136,7 @@ export const helmHandlers: Partial> = { getServiceStatus, async deployService( - { ctx, module, service, logEntry }: DeployServiceParams, + { ctx, module, service, log }: DeployServiceParams, ): Promise { const provider = ctx.provider const chartPath = await getChartPath(module) @@ -144,10 +144,10 @@ export const helmHandlers: Partial> = { const namespace = await getAppNamespace(ctx, ctx.provider) const releaseName = getReleaseName(namespace, service) - const releaseStatus = await getReleaseStatus(ctx.provider, releaseName, logEntry) + const releaseStatus = await getReleaseStatus(ctx.provider, releaseName, log) if (releaseStatus.state === "missing") { - await helm(provider, logEntry, + await helm(provider, log, "install", chartPath, "--name", releaseName, "--namespace", namespace, @@ -155,7 +155,7 @@ export const helmHandlers: Partial> = { "--wait", ) } else { - await helm(provider, logEntry, + await helm(provider, log, "upgrade", releaseName, chartPath, "--namespace", namespace, "--values", valuesPath, @@ -163,24 +163,24 @@ export const helmHandlers: Partial> = { ) } - const objects = await getChartObjects(ctx, service, logEntry) - await waitForObjects({ ctx, provider, service, objects, logEntry }) + const objects = await getChartObjects(ctx, service, log) + await waitForObjects({ ctx, provider, service, objects, log }) return {} }, async deleteService(params: DeleteServiceParams): Promise { - const { ctx, logEntry, service } = params + const { ctx, log, service } = params const namespace = await getAppNamespace(ctx, ctx.provider) const releaseName = getReleaseName(namespace, service) - await helm(ctx.provider, logEntry, "delete", "--purge", releaseName) - logEntry && logEntry.setSuccess("Service deleted") + await helm(ctx.provider, log, "delete", "--purge", releaseName) + log && log.setSuccess("Service deleted") return await getServiceStatus(params) }, } -async function build({ ctx, module, logEntry }: BuildModuleParams): Promise { +async function build({ ctx, module, log }: BuildModuleParams): Promise { const buildPath = module.buildPath const config = module @@ -196,14 +196,14 @@ async function build({ ctx, module, logEntry }: BuildModuleParams): if (config.spec.repo) { fetchArgs.push("--repo", config.spec.repo) } - logEntry && logEntry.setState("Fetching chart...") - await helm(ctx.provider, logEntry, ...fetchArgs) + await helm(ctx.provider, log, ...fetchArgs) + log.setState("Fetching chart...") const chartPath = await getChartPath(module) // create the values.yml file (merge the configured parameters into the default values) - logEntry && logEntry.setState("Preparing chart...") - const values = safeLoad(await helm(ctx.provider, logEntry, "inspect", "values", chartPath)) || {} + log && log.setState("Preparing chart...") + const values = safeLoad(await helm(ctx.provider, log, "inspect", "values", chartPath)) || {} Object.entries(flattenValues(config.spec.parameters)) .map(([k, v]) => set(values, k, v)) @@ -252,9 +252,9 @@ const helmCmd = new BinaryCmd({ }, }) -export function helm(provider: KubernetesProvider, logEntry: LogEntry | undefined, ...args: string[]) { +export function helm(provider: KubernetesProvider, log: LogEntry | undefined, ...args: string[]) { return helmCmd.stdout({ - logEntry, + log, args: [ "--kube-context", provider.config.context, ...args, @@ -272,13 +272,13 @@ function getValuesPath(chartPath: string) { return join(chartPath, "garden-values.yml") } -async function getChartObjects(ctx: PluginContext, service: Service, logEntry?: LogEntry) { +async function getChartObjects(ctx: PluginContext, service: Service, log?: LogEntry) { const chartPath = await getChartPath(service.module) const valuesPath = getValuesPath(chartPath) const namespace = await getAppNamespace(ctx, ctx.provider) const releaseName = getReleaseName(namespace, service) - const objects = safeLoadAll(await helm(ctx.provider, logEntry, + const objects = safeLoadAll(await helm(ctx.provider, log, "template", "--name", releaseName, "--namespace", namespace, @@ -295,16 +295,16 @@ async function getChartObjects(ctx: PluginContext, service: Service, logEntry?: } async function getServiceStatus( - { ctx, service, module, logEntry }: GetServiceStatusParams, + { ctx, service, module, log }: GetServiceStatusParams, ): Promise { // need to build to be able to check the status - const buildStatus = await getGenericModuleBuildStatus({ ctx, module, logEntry }) + const buildStatus = await getGenericModuleBuildStatus({ ctx, module, log }) if (!buildStatus.ready) { - await build({ ctx, module, logEntry }) + await build({ ctx, module, log }) } // first check if the installed objects on the cluster match the current code - const objects = await getChartObjects(ctx, service, logEntry) + const objects = await getChartObjects(ctx, service, log) const matched = await compareDeployedObjects(ctx, objects) if (!matched) { @@ -328,10 +328,10 @@ function getReleaseName(namespace: string, service: Service) { } async function getReleaseStatus( - provider: KubernetesProvider, releaseName: string, logEntry?: LogEntry, + provider: KubernetesProvider, releaseName: string, log?: LogEntry, ): Promise { try { - const res = JSON.parse(await helm(provider, logEntry, "status", releaseName, "--output", "json")) + const res = JSON.parse(await helm(provider, log, "status", releaseName, "--output", "json")) const statusCode = res.info.status.code return { state: helmStatusCodeMap[statusCode], diff --git a/garden-service/src/plugins/kubernetes/init.ts b/garden-service/src/plugins/kubernetes/init.ts index 32306691da2..69ca2a8ea01 100644 --- a/garden-service/src/plugins/kubernetes/init.ts +++ b/garden-service/src/plugins/kubernetes/init.ts @@ -65,8 +65,8 @@ async function prepareNamespaces({ ctx }: GetEnvironmentStatusParams) { ]) } -export async function getRemoteEnvironmentStatus({ ctx }: GetEnvironmentStatusParams) { - const loggedIn = await getLoginStatus({ ctx }) +export async function getRemoteEnvironmentStatus({ ctx, log }: GetEnvironmentStatusParams) { + const loggedIn = await getLoginStatus({ ctx, log }) if (!loggedIn) { return { @@ -75,7 +75,7 @@ export async function getRemoteEnvironmentStatus({ ctx }: GetEnvironmentStatusPa } } - await prepareNamespaces({ ctx }) + await prepareNamespaces({ ctx, log }) return { ready: true, @@ -83,11 +83,11 @@ export async function getRemoteEnvironmentStatus({ ctx }: GetEnvironmentStatusPa } } -export async function getLocalEnvironmentStatus({ ctx }: GetEnvironmentStatusParams) { +export async function getLocalEnvironmentStatus({ ctx, log }: GetEnvironmentStatusParams) { let ready = true let needUserInput = false - await prepareNamespaces({ ctx }) + await prepareNamespaces({ ctx, log }) // TODO: check if mkcert has been installed // TODO: check if all certs have been generated @@ -95,7 +95,7 @@ export async function getLocalEnvironmentStatus({ ctx }: GetEnvironmentStatusPar // check if system services are deployed if (!isSystemGarden(ctx.provider)) { const sysGarden = await getSystemGarden(ctx.provider) - const sysStatus = await sysGarden.actions.getStatus() + const sysStatus = await sysGarden.actions.getStatus({ log }) const systemReady = sysStatus.providers[ctx.provider.config.name].ready && every(values(sysStatus.services).map(s => s.state === "ready")) @@ -111,30 +111,30 @@ export async function getLocalEnvironmentStatus({ ctx }: GetEnvironmentStatusPar } } -export async function prepareRemoteEnvironment({ ctx, logEntry }: PrepareEnvironmentParams) { - const loggedIn = await getLoginStatus({ ctx, logEntry }) +export async function prepareRemoteEnvironment({ ctx, log }: PrepareEnvironmentParams) { + const loggedIn = await getLoginStatus({ ctx, log }) if (!loggedIn) { - await login({ ctx, logEntry }) + await login({ ctx, log }) } return {} } -export async function prepareLocalEnvironment({ ctx, force, logEntry }: PrepareEnvironmentParams) { +export async function prepareLocalEnvironment({ ctx, force, log }: PrepareEnvironmentParams) { // make sure system services are deployed if (!isSystemGarden(ctx.provider)) { - await configureSystemServices({ ctx, force, logEntry }) + await configureSystemServices({ ctx, force, log }) } // TODO: make sure all certs have been generated return {} } -export async function cleanupEnvironment({ ctx, logEntry }: CleanupEnvironmentParams) { +export async function cleanupEnvironment({ ctx, log }: CleanupEnvironmentParams) { const api = new KubeApi(ctx.provider) const namespace = await getAppNamespace(ctx, ctx.provider) - const entry = logEntry && logEntry.info({ + const entry = log.info({ section: "kubernetes", msg: `Deleting namespace ${namespace} (this may take a while)`, status: "active", @@ -150,7 +150,7 @@ export async function cleanupEnvironment({ ctx, logEntry }: CleanupEnvironmentPa throw new NotFoundError(err, { namespace, availableNamespaces }) } - await logout({ ctx, logEntry }) + await logout({ ctx, log }) // Wait until namespace has been deleted const startTime = new Date().getTime() @@ -183,8 +183,8 @@ async function getLoginStatus({ ctx }: PluginActionParamsBase) { return !!currentUsername } -async function login({ ctx, logEntry }: PluginActionParamsBase) { - const entry = logEntry && logEntry.info({ section: "kubernetes", msg: "Logging in..." }) +async function login({ ctx, log }: PluginActionParamsBase) { + const entry = log.info({ section: "kubernetes", msg: "Logging in..." }) const localConfig = await ctx.localConfigStore.get() let currentUsername @@ -251,8 +251,8 @@ async function login({ ctx, logEntry }: PluginActionParamsBase) { return { loggedIn: true } } -async function logout({ ctx, logEntry }: PluginActionParamsBase) { - const entry = logEntry && logEntry.info({ section: "kubernetes", msg: "Logging out..." }) +async function logout({ ctx, log }: PluginActionParamsBase) { + const entry = log.info({ section: "kubernetes", msg: "Logging out..." }) const localConfig = await ctx.localConfigStore.get() const k8sConfig = localConfig.kubernetes || {} @@ -265,15 +265,15 @@ async function logout({ ctx, logEntry }: PluginActionParamsBase) { } async function configureSystemServices( - { ctx, force, logEntry }: - { ctx: PluginContext, force: boolean, logEntry?: LogEntry }, + { ctx, force, log }: + { ctx: PluginContext, force: boolean, log: LogEntry }, ) { const provider = ctx.provider const sysGarden = await getSystemGarden(provider) const sysCtx = sysGarden.getPluginContext(provider.name) // TODO: need to add logic here to wait for tiller to be ready - await helm(sysCtx.provider, logEntry, + await helm(sysCtx.provider, log, "init", "--wait", "--service-account", "default", "--upgrade", @@ -281,19 +281,20 @@ async function configureSystemServices( const sysStatus = await getLocalEnvironmentStatus({ ctx: sysCtx, - logEntry, + log, }) await prepareLocalEnvironment({ ctx: sysCtx, force, status: sysStatus, - logEntry, + log, }) // only deploy services if configured to do so (minikube bundles the required services as addons) if (!provider.config._systemServices || provider.config._systemServices.length > 0) { const results = await sysGarden.actions.deployServices({ + log, serviceNames: provider.config._systemServices, }) diff --git a/garden-service/src/plugins/kubernetes/local.ts b/garden-service/src/plugins/kubernetes/local.ts index 97a2b054864..000c764e1b8 100644 --- a/garden-service/src/plugins/kubernetes/local.ts +++ b/garden-service/src/plugins/kubernetes/local.ts @@ -69,7 +69,7 @@ const configSchema = kubernetesConfigBase export const name = "local-kubernetes" -export async function gardenPlugin({ projectName, config, logEntry }): Promise { +export async function gardenPlugin({ projectName, config, log }): Promise { config = validate(config, configSchema, { context: "local-kubernetes provider config" }) let context = config.context @@ -84,14 +84,14 @@ export async function gardenPlugin({ projectName, config, logEntry }): Promise c.name) for (const supportedContext of supportedContexts) { if (availableContexts.includes(supportedContext)) { context = supportedContext - logEntry.debug({ section: name, msg: `Using detected context: ${context}` }) + log.debug({ section: name, msg: `Using detected context: ${context}` }) break } } @@ -100,7 +100,7 @@ export async function gardenPlugin({ projectName, config, logEntry }): Promise ({ getServiceStatus, async deployService( - { ctx, module, service, runtimeContext, logEntry }: DeployServiceParams, + { ctx, module, service, runtimeContext, log }: DeployServiceParams, ) { // TODO: split this method up and test const { versionString } = service.module.version - logEntry && logEntry.info({ section: service.name, msg: `Deploying version ${versionString}` }) + log.info({ section: service.name, msg: `Deploying version ${versionString}` }) const identifier = await helpers.getLocalImageId(module) const ports = service.spec.ports.map(p => { @@ -116,7 +116,7 @@ export const gardenPlugin = (): GardenPlugin => ({ } const docker = getDocker() - const serviceStatus = await getServiceStatus({ ctx, service, module, runtimeContext, logEntry }) + const serviceStatus = await getServiceStatus({ ctx, service, module, runtimeContext, log }) let swarmServiceStatus let serviceId @@ -124,14 +124,14 @@ export const gardenPlugin = (): GardenPlugin => ({ const swarmService = await docker.getService(serviceStatus.providerId) swarmServiceStatus = await swarmService.inspect() opts.version = parseInt(swarmServiceStatus.Version.Index, 10) - logEntry && logEntry.verbose({ + log.verbose({ section: service.name, msg: `Updating existing Swarm service (version ${opts.version})`, }) await swarmService.update(opts) serviceId = serviceStatus.providerId } else { - logEntry && logEntry.verbose({ + log.verbose({ section: service.name, msg: `Creating new Swarm service`, }) @@ -167,12 +167,12 @@ export const gardenPlugin = (): GardenPlugin => ({ } } - logEntry && logEntry.info({ + log.info({ section: service.name, msg: `Ready`, }) - return getServiceStatus({ ctx, module, service, runtimeContext, logEntry }) + return getServiceStatus({ ctx, module, service, runtimeContext, log }) }, async getServiceOutputs({ ctx, service }: GetServiceOutputsParams) { @@ -182,14 +182,14 @@ export const gardenPlugin = (): GardenPlugin => ({ }, async execInService( - { ctx, service, command, runtimeContext, logEntry }: ExecInServiceParams, + { ctx, service, command, runtimeContext, log }: ExecInServiceParams, ) { const status = await getServiceStatus({ ctx, service, module: service.module, runtimeContext, - logEntry, + log, }) if (!status.state || status.state !== "ready") { diff --git a/garden-service/src/plugins/openfaas/openfaas.ts b/garden-service/src/plugins/openfaas/openfaas.ts index 4444a05f0b2..4b55c96dbfd 100644 --- a/garden-service/src/plugins/openfaas/openfaas.ts +++ b/garden-service/src/plugins/openfaas/openfaas.ts @@ -110,9 +110,9 @@ export function gardenPlugin({ config }: { config: OpenFaasConfig }): GardenPlug return { modules: [join(STATIC_DIR, "openfaas", "builder")], actions: { - async getEnvironmentStatus({ ctx }: GetEnvironmentStatusParams) { + async getEnvironmentStatus({ ctx, log }: GetEnvironmentStatusParams) { const ofGarden = await getOpenFaasGarden(ctx) - const status = await ofGarden.actions.getStatus() + const status = await ofGarden.actions.getStatus({ log }) const envReady = every(values(status.providers).map(s => s.ready)) const servicesReady = every(values(status.services).map(s => s.state === "ready")) @@ -122,13 +122,13 @@ export function gardenPlugin({ config }: { config: OpenFaasConfig }): GardenPlug } }, - async prepareEnvironment({ ctx, force }: PrepareEnvironmentParams) { + async prepareEnvironment({ ctx, force, log }: PrepareEnvironmentParams) { // TODO: refactor to dedupe similar code in local-kubernetes const ofGarden = await getOpenFaasGarden(ctx) - await ofGarden.actions.prepareEnvironment({ force }) + await ofGarden.actions.prepareEnvironment({ force, log }) - const results = await ofGarden.actions.deployServices({}) + const results = await ofGarden.actions.deployServices({ log }) const failed = values(results.taskResults).filter(r => !!r.error).length if (failed) { @@ -140,10 +140,10 @@ export function gardenPlugin({ config }: { config: OpenFaasConfig }): GardenPlug return {} }, - async cleanupEnvironment({ ctx }) { + async cleanupEnvironment({ ctx, log }) { const ofGarden = await getOpenFaasGarden(ctx) - return ofGarden.actions.cleanupEnvironment({}) + return ofGarden.actions.cleanupEnvironment({ log }) }, }, moduleActions: { @@ -214,7 +214,7 @@ export function gardenPlugin({ config }: { config: OpenFaasConfig }): GardenPlug }, async deployService(params: DeployServiceParams): Promise { - const { ctx, module, service, logEntry, runtimeContext } = params + const { ctx, module, service, log, runtimeContext } = params // write the stack file again with environment variables await writeStackFile(ctx, module, runtimeContext.envVars) @@ -229,20 +229,21 @@ export function gardenPlugin({ config }: { config: OpenFaasConfig }): GardenPlug const deployment = (await api.apps.readNamespacedDeployment(service.name, namespace)).body - await waitForObjects({ ctx, provider: k8sProvider, service, logEntry, objects: [deployment] }) + await waitForObjects({ ctx, provider: k8sProvider, service, log, objects: [deployment] }) // TODO: avoid duplicate work here return getServiceStatus(params) }, async deleteService(params: DeleteServiceParams): Promise { - const { ctx, logEntry, service, runtimeContext } = params + const { ctx, log, service, runtimeContext } = params let status let found = true try { status = await getServiceStatus({ ctx, + log, service, runtimeContext, module: service.module, @@ -256,8 +257,8 @@ export function gardenPlugin({ config }: { config: OpenFaasConfig }): GardenPlug found = false } - if (logEntry) { - found ? logEntry.setSuccess("Service deleted") : logEntry.setWarn("Service not deployed") + if (log) { + found ? log.setSuccess("Service deleted") : log.setWarn("Service not deployed") } return status diff --git a/garden-service/src/tasks/base.ts b/garden-service/src/tasks/base.ts index 65ddf12dd82..22b4bed74ba 100644 --- a/garden-service/src/tasks/base.ts +++ b/garden-service/src/tasks/base.ts @@ -10,11 +10,13 @@ import { TaskResults } from "../task-graph" import { ModuleVersion } from "../vcs/base" import { v1 as uuidv1 } from "uuid" import { Garden } from "../garden" +import { LogEntry } from "../logger/log-entry" export class TaskDefinitionError extends Error { } export interface TaskParams { garden: Garden + log: LogEntry force?: boolean version: ModuleVersion } @@ -22,6 +24,7 @@ export interface TaskParams { export abstract class Task { abstract type: string garden: Garden + log: LogEntry id: string force: boolean version: ModuleVersion @@ -34,6 +37,7 @@ export abstract class Task { this.id = uuidv1() // uuidv1 is timestamp-based this.force = !!initArgs.force this.version = initArgs.version + this.log = initArgs.log } async getDependencies(): Promise { diff --git a/garden-service/src/tasks/build.ts b/garden-service/src/tasks/build.ts index a0f31eb45aa..e0d9d3f2431 100644 --- a/garden-service/src/tasks/build.ts +++ b/garden-service/src/tasks/build.ts @@ -12,9 +12,11 @@ import { Module } from "../types/module" import { BuildResult } from "../types/plugin/outputs" import { Task } from "../tasks/base" import { Garden } from "../garden" +import { LogEntry } from "../logger/log-entry" export interface BuildTaskParams { garden: Garden + log: LogEntry module: Module force: boolean } @@ -24,8 +26,8 @@ export class BuildTask extends Task { private module: Module - constructor({ garden, force, module }: BuildTaskParams) { - super({ garden, force, version: module.version }) + constructor({ garden, log, force, module }: BuildTaskParams) { + super({ garden, log, force, version: module.version }) this.module = module } @@ -34,6 +36,7 @@ export class BuildTask extends Task { return Bluebird.map(deps, async (m: Module) => { return new BuildTask({ garden: this.garden, + log: this.log, module: m, force: this.force, }) @@ -51,13 +54,13 @@ export class BuildTask extends Task { async process(): Promise { const module = this.module - if (!this.force && (await this.garden.actions.getBuildStatus({ module })).ready) { + if (!this.force && (await this.garden.actions.getBuildStatus({ log: this.log, module })).ready) { // this is necessary in case other modules depend on files from this one await this.garden.buildDir.syncDependencyProducts(this.module) return { fresh: false } } - const logEntry = this.garden.log.info({ + const log = this.log.info({ section: this.module.name, msg: "Building", status: "active", @@ -67,14 +70,14 @@ export class BuildTask extends Task { try { result = await this.garden.actions.build({ module, - logEntry, + log, }) } catch (err) { - logEntry.setError() + log.setError() throw err } - logEntry.setSuccess({ msg: chalk.green(`Done (took ${logEntry.getDuration(1)} sec)`), append: true }) + log.setSuccess({ msg: chalk.green(`Done (took ${log.getDuration(1)} sec)`), append: true }) return result } } diff --git a/garden-service/src/tasks/deploy.ts b/garden-service/src/tasks/deploy.ts index 176471df5a5..8f287941173 100644 --- a/garden-service/src/tasks/deploy.ts +++ b/garden-service/src/tasks/deploy.ts @@ -27,7 +27,7 @@ export interface DeployTaskParams { service: Service force: boolean forceBuild: boolean - logEntry?: LogEntry + log: LogEntry } export class DeployTask extends Task { @@ -35,13 +35,12 @@ export class DeployTask extends Task { private service: Service private forceBuild: boolean - private logEntry?: LogEntry - constructor({ garden, service, force, forceBuild, logEntry }: DeployTaskParams) { - super({ garden, force, version: service.module.version }) + constructor({ garden, service, force, forceBuild, log }: DeployTaskParams) { + super({ garden, log, force, version: service.module.version }) this.service = service this.forceBuild = forceBuild - this.logEntry = logEntry + this.log = log } async getDependencies() { @@ -51,6 +50,7 @@ export class DeployTask extends Task { const deps: Task[] = await Bluebird.map(services, async (service) => { return new DeployTask({ garden: this.garden, + log: this.log, service, force: false, forceBuild: this.forceBuild, @@ -59,6 +59,7 @@ export class DeployTask extends Task { deps.push(new PushTask({ garden: this.garden, + log: this.log, module: this.service.module, forceBuild: this.forceBuild, })) @@ -75,7 +76,7 @@ export class DeployTask extends Task { } async process(): Promise { - const logEntry = (this.logEntry || this.garden.log).info({ + const log = this.log.info({ section: this.service.name, msg: "Checking status", status: "active", @@ -83,7 +84,7 @@ export class DeployTask extends Task { // TODO: get version from build task results const { versionString } = await this.service.module.version - const status = await this.garden.actions.getServiceStatus({ service: this.service, logEntry }) + const status = await this.garden.actions.getServiceStatus({ service: this.service, log }) if ( !this.force && @@ -91,14 +92,14 @@ export class DeployTask extends Task { status.state === "ready" ) { // already deployed and ready - logEntry.setSuccess({ + log.setSuccess({ msg: `Version ${versionString} already deployed`, append: true, }) return status } - logEntry.setState("Deploying") + log.setState("Deploying") const dependencies = await this.garden.getServices(this.service.config.dependencies) @@ -107,23 +108,23 @@ export class DeployTask extends Task { result = await this.garden.actions.deployService({ service: this.service, runtimeContext: await prepareRuntimeContext(this.garden, this.service.module, dependencies), - logEntry, + log, force: this.force, }) } catch (err) { - logEntry.setError() + log.setError() throw err } - logEntry.setSuccess({ msg: chalk.green(`Ready`), append: true }) + log.setSuccess({ msg: chalk.green(`Ready`), append: true }) return result } } export async function getDeployTasks( - { garden, module, serviceNames, force = false, forceBuild = false, includeDependants = false }: + { garden, log, module, serviceNames, force = false, forceBuild = false, includeDependants = false }: { - garden: Garden, module: Module, serviceNames?: string[] | null, + garden: Garden, log: LogEntry, module: Module, serviceNames?: string[] | null, force?: boolean, forceBuild?: boolean, includeDependants?: boolean, }, ) { @@ -140,5 +141,5 @@ export async function getDeployTasks( ? moduleServices.filter(s => serviceNames.includes(s.name)) : moduleServices - return servicesToProcess.map(service => new DeployTask({ garden, service, force, forceBuild })) + return servicesToProcess.map(service => new DeployTask({ garden, log, service, force, forceBuild })) } diff --git a/garden-service/src/tasks/publish.ts b/garden-service/src/tasks/publish.ts index 87652546e5c..a873d3c409c 100644 --- a/garden-service/src/tasks/publish.ts +++ b/garden-service/src/tasks/publish.ts @@ -12,9 +12,11 @@ import { Module } from "../types/module" import { PublishResult } from "../types/plugin/outputs" import { Task } from "../tasks/base" import { Garden } from "../garden" +import { LogEntry } from "../logger/log-entry" export interface PublishTaskParams { garden: Garden + log: LogEntry module: Module forceBuild: boolean } @@ -25,8 +27,8 @@ export class PublishTask extends Task { private module: Module private forceBuild: boolean - constructor({ garden, module, forceBuild }: PublishTaskParams) { - super({ garden, version: module.version }) + constructor({ garden, log, module, forceBuild }: PublishTaskParams) { + super({ garden, log, version: module.version }) this.module = module this.forceBuild = forceBuild } @@ -37,6 +39,7 @@ export class PublishTask extends Task { } return [new BuildTask({ garden: this.garden, + log: this.log, module: this.module, force: this.forceBuild, })] @@ -52,7 +55,7 @@ export class PublishTask extends Task { async process(): Promise { if (!this.module.allowPublish) { - this.garden.log.info({ + this.log.info({ section: this.module.name, msg: "Publishing disabled", status: "active", @@ -60,7 +63,7 @@ export class PublishTask extends Task { return { published: false } } - const logEntry = this.garden.log.info({ + const log = this.log.info({ section: this.module.name, msg: "Publishing", status: "active", @@ -68,16 +71,16 @@ export class PublishTask extends Task { let result: PublishResult try { - result = await this.garden.actions.publishModule({ module: this.module, logEntry }) + result = await this.garden.actions.publishModule({ module: this.module, log }) } catch (err) { - logEntry.setError() + log.setError() throw err } if (result.published) { - logEntry.setSuccess({ msg: chalk.green(result.message || `Ready`), append: true }) + log.setSuccess({ msg: chalk.green(result.message || `Ready`), append: true }) } else { - logEntry.setWarn({ msg: result.message, append: true }) + log.setWarn({ msg: result.message, append: true }) } return result diff --git a/garden-service/src/tasks/push.ts b/garden-service/src/tasks/push.ts index a96c0d2fb82..86f99ef234c 100644 --- a/garden-service/src/tasks/push.ts +++ b/garden-service/src/tasks/push.ts @@ -12,9 +12,11 @@ import { Module } from "../types/module" import { PushResult } from "../types/plugin/outputs" import { Task } from "../tasks/base" import { Garden } from "../garden" +import { LogEntry } from "../logger/log-entry" export interface PushTaskParams { garden: Garden + log: LogEntry module: Module forceBuild: boolean } @@ -25,8 +27,8 @@ export class PushTask extends Task { private module: Module private forceBuild: boolean - constructor({ garden, module, forceBuild }: PushTaskParams) { - super({ garden, version: module.version }) + constructor({ garden, log, module, forceBuild }: PushTaskParams) { + super({ garden, log, version: module.version }) this.module = module this.forceBuild = forceBuild } @@ -34,6 +36,7 @@ export class PushTask extends Task { async getDependencies() { return [new BuildTask({ garden: this.garden, + log: this.log, module: this.module, force: this.forceBuild, })] @@ -60,7 +63,7 @@ export class PushTask extends Task { return { pushed: false } } - const logEntry = this.garden.log.info({ + const log = this.log.info({ section: this.module.name, msg: "Pushing", status: "active", @@ -68,16 +71,16 @@ export class PushTask extends Task { let result: PushResult try { - result = await this.garden.actions.pushModule({ module: this.module, logEntry }) + result = await this.garden.actions.pushModule({ module: this.module, log }) } catch (err) { - logEntry.setError() + log.setError() throw err } if (result.pushed) { - logEntry.setSuccess({ msg: chalk.green(result.message || `Ready`), append: true }) + log.setSuccess({ msg: chalk.green(result.message || `Ready`), append: true }) } else if (result.message) { - logEntry.setWarn({ msg: result.message, append: true }) + log.setWarn({ msg: result.message, append: true }) } return result diff --git a/garden-service/src/tasks/test.ts b/garden-service/src/tasks/test.ts index 8a587c89690..4a5cab16ec8 100644 --- a/garden-service/src/tasks/test.ts +++ b/garden-service/src/tasks/test.ts @@ -17,6 +17,7 @@ import { TestResult } from "../types/plugin/outputs" import { Task, TaskParams } from "../tasks/base" import { prepareRuntimeContext } from "../types/service" import { Garden } from "../garden" +import { LogEntry } from "../logger/log-entry" class TestError extends Error { toString() { @@ -26,6 +27,7 @@ class TestError extends Error { export interface TestTaskParams { garden: Garden + log: LogEntry module: Module testConfig: TestConfig force: boolean @@ -39,8 +41,8 @@ export class TestTask extends Task { private testConfig: TestConfig private forceBuild: boolean - constructor({ garden, module, testConfig, force, forceBuild, version }: TestTaskParams & TaskParams) { - super({ garden, force, version }) + constructor({ garden, log, module, testConfig, force, forceBuild, version }: TestTaskParams & TaskParams) { + super({ garden, log, force, version }) this.module = module this.testConfig = testConfig this.force = force @@ -64,6 +66,7 @@ export class TestTask extends Task { const deps: Task[] = [new BuildTask({ garden: this.garden, + log: this.log, module: this.module, force: this.forceBuild, })] @@ -71,6 +74,7 @@ export class TestTask extends Task { for (const service of services) { deps.push(new DeployTask({ garden: this.garden, + log: this.log, service, force: false, forceBuild: this.forceBuild, @@ -93,7 +97,7 @@ export class TestTask extends Task { const testResult = await this.getTestResult() if (testResult && testResult.success) { - const passedEntry = this.garden.log.info({ + const passedEntry = this.log.info({ section: this.module.name, msg: `${this.testConfig.name} tests`, }) @@ -101,7 +105,7 @@ export class TestTask extends Task { return testResult } - const entry = this.garden.log.info({ + const log = this.log.info({ section: this.module.name, msg: `Running ${this.testConfig.name} tests`, status: "active", @@ -113,6 +117,7 @@ export class TestTask extends Task { let result: TestResult try { result = await this.garden.actions.testModule({ + log, interactive: false, module: this.module, runtimeContext, @@ -120,13 +125,13 @@ export class TestTask extends Task { testConfig: this.testConfig, }) } catch (err) { - entry.setError() + log.setError() throw err } if (result.success) { - entry.setSuccess({ msg: chalk.green(`Success`), append: true }) + log.setSuccess({ msg: chalk.green(`Success`), append: true }) } else { - entry.setError({ msg: chalk.red(`Failed!`), append: true }) + log.setError({ msg: chalk.red(`Failed!`), append: true }) throw new TestError(result.output) } @@ -139,6 +144,7 @@ export class TestTask extends Task { } return this.garden.actions.getTestResult({ + log: this.log, module: this.module, testName: this.testConfig.name, version: this.version, @@ -147,25 +153,19 @@ export class TestTask extends Task { } export async function getTestTasks( - { garden, module, name, force = false, forceBuild = false }: - { garden: Garden, module: Module, name?: string, force?: boolean, forceBuild?: boolean }, + { garden, log, module, name, force = false, forceBuild = false }: + { garden: Garden, log: LogEntry, module: Module, name?: string, force?: boolean, forceBuild?: boolean }, ) { - const tasks: Promise[] = [] - - for (const test of module.testConfigs) { - if (name && test.name !== name) { - continue - } - tasks.push(TestTask.factory({ - garden, - force, - forceBuild, - testConfig: test, - module, - })) - } - - return Bluebird.all(tasks) + const configs = module.testConfigs.filter(test => !name || test.name === name) + + return Bluebird.map(configs, test => TestTask.factory({ + garden, + log, + force, + forceBuild, + testConfig: test, + module, + })) } async function getTestDependencies(garden: Garden, testConfig: TestConfig) { diff --git a/garden-service/src/types/plugin/params.ts b/garden-service/src/types/plugin/params.ts index 3173da69058..9fc030ddbf3 100644 --- a/garden-service/src/types/plugin/params.ts +++ b/garden-service/src/types/plugin/params.ts @@ -23,7 +23,7 @@ export interface PluginActionContextParams { } export interface PluginActionParamsBase extends PluginActionContextParams { - logEntry?: LogEntry + log: LogEntry } // Note: not specifying this further because we will later remove it from the API @@ -34,7 +34,7 @@ const actionParamsSchema = Joi.object() .keys({ ctx: pluginContextSchema .required(), - logEntry: logEntrySchema, + log: logEntrySchema, }) export interface PluginModuleActionParamsBase extends PluginActionParamsBase { @@ -65,14 +65,14 @@ export const describeModuleTypeParamsSchema = Joi.object() export interface ValidateModuleParams { ctx: PluginContext - logEntry?: LogEntry + log?: LogEntry moduleConfig: T["_ConfigType"] } export const validateModuleParamsSchema = Joi.object() .keys({ ctx: pluginContextSchema .required(), - logEntry: logEntrySchema, + log: logEntrySchema, moduleConfig: moduleConfigSchema .required(), }) diff --git a/garden-service/src/types/plugin/plugin.ts b/garden-service/src/types/plugin/plugin.ts index 8b3c6deeb01..1b3608af358 100644 --- a/garden-service/src/types/plugin/plugin.ts +++ b/garden-service/src/types/plugin/plugin.ts @@ -377,7 +377,7 @@ export interface GardenPlugin { export interface PluginFactoryParams { config: T["config"], - logEntry: LogNode, + log: LogNode, projectName: string, } diff --git a/garden-service/src/types/service.ts b/garden-service/src/types/service.ts index 5205d4caad9..1e377a7e6b9 100644 --- a/garden-service/src/types/service.ts +++ b/garden-service/src/types/service.ts @@ -209,7 +209,13 @@ export async function prepareRuntimeContext( } const depContext = deps[dep.name] - const outputs = { ...await garden.actions.getServiceOutputs({ service: dep }), ...dep.config.outputs } + const outputs = { + ...await garden.actions.getServiceOutputs({ + log: garden.log.info(), + service: dep, + }), + ...dep.config.outputs, + } const serviceEnvName = getEnvVarName(dep.name) validate(outputs, serviceOutputsSchema, { context: `outputs for service ${dep.name}` }) diff --git a/garden-service/src/util/ext-tools.ts b/garden-service/src/util/ext-tools.ts index b612ae68856..93bcb1286b6 100644 --- a/garden-service/src/util/ext-tools.ts +++ b/garden-service/src/util/ext-tools.ts @@ -24,7 +24,7 @@ const toolsPath = join(globalGardenPath, "tools") interface ExecParams { cwd?: string - logEntry?: LogEntry + log?: LogEntry args?: string[] } @@ -95,13 +95,13 @@ export class BinaryCmd extends Cmd { this.executablePath = join(this.downloadPath, ...executableSubpath) } - private async download(logEntry?: LogEntry) { + private async download(log?: LogEntry) { if (await pathExists(this.executablePath)) { return } - logEntry && logEntry.setState(`Fetching ${this.name}...`) - const debug = logEntry && logEntry.debug(`Downloading ${this.spec.url}...`) + log && log.setState(`Fetching ${this.name}...`) + const debug = log && log.debug(`Downloading ${this.spec.url}...`) const response = await Axios({ method: "GET", @@ -121,7 +121,7 @@ export class BinaryCmd extends Cmd { // return a promise and resolve when download finishes return new Promise((resolve, reject) => { response.data.on("error", (err) => { - logEntry && logEntry.setError(`Failed fetching ${this.spec.url}`) + log && log.setError(`Failed fetching ${this.spec.url}`) reject(err) }) @@ -146,7 +146,7 @@ export class BinaryCmd extends Cmd { response.data.pipe(extractor) extractor.on("error", (err) => { - logEntry && logEntry.setError(`Failed extracting ${format} archive ${this.spec.url}`) + log && log.setError(`Failed extracting ${format} archive ${this.spec.url}`) reject(err) }) } @@ -175,15 +175,15 @@ export class BinaryCmd extends Cmd { } debug && debug.setSuccess("Done") - logEntry && logEntry.setSuccess(`Fetched ${this.name}`) + log && log.setSuccess(`Fetched ${this.name}`) resolve() }) }) }) } - async exec({ cwd, args, logEntry }: ExecParams) { - await this.download(logEntry) + async exec({ cwd, args, log }: ExecParams) { + await this.download(log) return execa(this.executablePath, args || [], { cwd }) } diff --git a/garden-service/src/vcs/base.ts b/garden-service/src/vcs/base.ts index bab9bbe1090..3478ff0dfc4 100644 --- a/garden-service/src/vcs/base.ts +++ b/garden-service/src/vcs/base.ts @@ -75,7 +75,7 @@ export interface RemoteSourceParams { url: string, name: string, sourceType: ExternalSourceType, - logEntry: LogNode, + log: LogNode, } export abstract class VcsHandler { diff --git a/garden-service/src/vcs/git.ts b/garden-service/src/vcs/git.ts index 574ecf4fefa..f21e75f49cb 100644 --- a/garden-service/src/vcs/git.ts +++ b/garden-service/src/vcs/git.ts @@ -93,7 +93,7 @@ export class GitHandler extends VcsHandler { } // TODO Better auth handling - async ensureRemoteSource({ url, name, logEntry, sourceType }: RemoteSourceParams): Promise { + async ensureRemoteSource({ url, name, log, sourceType }: RemoteSourceParams): Promise { const remoteSourcesPath = join(this.projectRoot, this.getRemoteSourcesDirname(sourceType)) await ensureDir(remoteSourcesPath) const git = helpers.gitCli(remoteSourcesPath) @@ -102,7 +102,7 @@ export class GitHandler extends VcsHandler { const isCloned = await pathExists(absPath) if (!isCloned) { - const entry = logEntry.info({ section: name, msg: `Fetching from ${url}`, status: "active" }) + const entry = log.info({ section: name, msg: `Fetching from ${url}`, status: "active" }) const { repositoryUrl, hash } = parseGitUrl(url) await git("clone", ["--depth=1", `--branch=${hash}`, repositoryUrl, absPath]) @@ -113,14 +113,14 @@ export class GitHandler extends VcsHandler { return absPath } - async updateRemoteSource({ url, name, sourceType, logEntry }: RemoteSourceParams) { + async updateRemoteSource({ url, name, sourceType, log }: RemoteSourceParams) { const absPath = join(this.projectRoot, this.getRemoteSourcePath(name, url, sourceType)) const git = helpers.gitCli(absPath) const { repositoryUrl, hash } = parseGitUrl(url) - await this.ensureRemoteSource({ url, name, sourceType, logEntry }) + await this.ensureRemoteSource({ url, name, sourceType, log }) - const entry = logEntry.info({ section: name, msg: "Getting remote state", status: "active" }) + const entry = log.info({ section: name, msg: "Getting remote state", status: "active" }) await git("remote", ["update"]) const remoteCommitId = getCommitIdFromRefList(await git("ls-remote", [repositoryUrl, hash])) diff --git a/garden-service/test/helpers.ts b/garden-service/test/helpers.ts index d1a9f107743..b644e83d247 100644 --- a/garden-service/test/helpers.ts +++ b/garden-service/test/helpers.ts @@ -138,9 +138,10 @@ export const testPlugin: PluginFactory = (): GardenPlugin => { build: buildGenericModule, runModule, - async runService({ ctx, service, interactive, runtimeContext, silent, timeout }: RunServiceParams) { + async runService({ ctx, log, service, interactive, runtimeContext, silent, timeout }: RunServiceParams) { return runModule({ ctx, + log, module: service.module, command: [service.name], interactive, diff --git a/garden-service/test/src/actions.ts b/garden-service/test/src/actions.ts index 26b51cfd26b..68808cd54cc 100644 --- a/garden-service/test/src/actions.ts +++ b/garden-service/test/src/actions.ts @@ -9,6 +9,7 @@ import { Module } from "../../src/types/module" import { Service } from "../../src/types/service" import Stream from "ts-stream" import { ServiceLogEntry } from "../../src/types/plugin/outputs" +import { LogEntry } from "../../src/logger/log-entry" import { describeModuleTypeParamsSchema, validateModuleParamsSchema, @@ -38,6 +39,7 @@ const now = new Date() describe("ActionHelper", () => { let garden: Garden + let log: LogEntry let actions: ActionHelper let module: Module let service: Service @@ -45,6 +47,7 @@ describe("ActionHelper", () => { before(async () => { const plugins = { "test-plugin": testPlugin, "test-plugin-b": testPluginB } garden = await makeTestGardenA(plugins) + log = garden.log.info() actions = garden.actions module = await garden.getModule("module-a") service = await garden.getService("service-a") @@ -54,7 +57,7 @@ describe("ActionHelper", () => { describe("environment actions", () => { describe("getEnvironmentStatus", () => { it("should return a map of statuses for providers that have a getEnvironmentStatus handler", async () => { - const result = await actions.getEnvironmentStatus({}) + const result = await actions.getEnvironmentStatus({ log }) expect(result).to.eql({ "test-plugin": { ready: false }, "test-plugin-b": { ready: false }, @@ -62,7 +65,7 @@ describe("ActionHelper", () => { }) it("should optionally filter to single plugin", async () => { - const result = await actions.getEnvironmentStatus({ pluginName: "test-plugin" }) + const result = await actions.getEnvironmentStatus({ log, pluginName: "test-plugin" }) expect(result).to.eql({ "test-plugin": { ready: false }, }) @@ -71,7 +74,7 @@ describe("ActionHelper", () => { describe("prepareEnvironment", () => { it("should prepare the environment for each configured provider", async () => { - const result = await actions.prepareEnvironment({}) + const result = await actions.prepareEnvironment({ log }) expect(result).to.eql({ "test-plugin": true, "test-plugin-b": true, @@ -79,7 +82,7 @@ describe("ActionHelper", () => { }) it("should optionally filter to single plugin", async () => { - const result = await actions.prepareEnvironment({ pluginName: "test-plugin" }) + const result = await actions.prepareEnvironment({ log, pluginName: "test-plugin" }) expect(result).to.eql({ "test-plugin": true, }) @@ -88,7 +91,7 @@ describe("ActionHelper", () => { describe("cleanupEnvironment", () => { it("should clean up environment for each configured provider", async () => { - const result = await actions.cleanupEnvironment({}) + const result = await actions.cleanupEnvironment({ log }) expect(result).to.eql({ "test-plugin": { ready: false }, "test-plugin-b": { ready: false }, @@ -96,7 +99,7 @@ describe("ActionHelper", () => { }) it("should optionally filter to single plugin", async () => { - const result = await actions.cleanupEnvironment({ pluginName: "test-plugin" }) + const result = await actions.cleanupEnvironment({ log, pluginName: "test-plugin" }) expect(result).to.eql({ "test-plugin": { ready: false }, }) @@ -105,21 +108,21 @@ describe("ActionHelper", () => { describe("getSecret", () => { it("should retrieve a secret from the specified provider", async () => { - const result = await actions.getSecret({ pluginName: "test-plugin", key: "foo" }) + const result = await actions.getSecret({ log, pluginName: "test-plugin", key: "foo" }) expect(result).to.eql({ value: "foo" }) }) }) describe("setSecret", () => { it("should set a secret via the specified provider", async () => { - const result = await actions.setSecret({ pluginName: "test-plugin", key: "foo", value: "boo" }) + const result = await actions.setSecret({ log, pluginName: "test-plugin", key: "foo", value: "boo" }) expect(result).to.eql({}) }) }) describe("deleteSecret", () => { it("should delete a secret from the specified provider", async () => { - const result = await actions.deleteSecret({ pluginName: "test-plugin", key: "foo" }) + const result = await actions.deleteSecret({ log, pluginName: "test-plugin", key: "foo" }) expect(result).to.eql({ found: true }) }) }) @@ -128,7 +131,7 @@ describe("ActionHelper", () => { describe("module actions", () => { describe("getBuildStatus", () => { it("should correctly call the corresponding plugin handler", async () => { - const result = await actions.getBuildStatus({ module }) + const result = await actions.getBuildStatus({ log, module }) expect(result).to.eql({ ready: true, }) @@ -137,14 +140,14 @@ describe("ActionHelper", () => { describe("build", () => { it("should correctly call the corresponding plugin handler", async () => { - const result = await actions.build({ module }) + const result = await actions.build({ log, module }) expect(result).to.eql({}) }) }) describe("pushModule", () => { it("should correctly call the corresponding plugin handler", async () => { - const result = await actions.pushModule({ module }) + const result = await actions.pushModule({ log, module }) expect(result).to.eql({ pushed: true, }) @@ -155,6 +158,7 @@ describe("ActionHelper", () => { it("should correctly call the corresponding plugin handler", async () => { const command = ["npm", "run"] const result = await actions.runModule({ + log, module, command, interactive: true, @@ -179,6 +183,7 @@ describe("ActionHelper", () => { describe("testModule", () => { it("should correctly call the corresponding plugin handler", async () => { const result = await actions.testModule({ + log, module, interactive: true, runtimeContext: { @@ -209,6 +214,7 @@ describe("ActionHelper", () => { describe("getTestResult", () => { it("should correctly call the corresponding plugin handler", async () => { const result = await actions.getTestResult({ + log, module, testName: "test", version: module.version, @@ -230,35 +236,35 @@ describe("ActionHelper", () => { describe("service actions", () => { describe("getServiceStatus", () => { it("should correctly call the corresponding plugin handler", async () => { - const result = await actions.getServiceStatus({ service }) + const result = await actions.getServiceStatus({ log, service }) expect(result).to.eql({ state: "ready" }) }) }) describe("deployService", () => { it("should correctly call the corresponding plugin handler", async () => { - const result = await actions.deployService({ service, force: true }) + const result = await actions.deployService({ log, service, force: true }) expect(result).to.eql({ state: "ready" }) }) }) describe("deleteService", () => { it("should correctly call the corresponding plugin handler", async () => { - const result = await actions.deleteService({ service }) + const result = await actions.deleteService({ log, service }) expect(result).to.eql({ state: "ready" }) }) }) describe("getServiceOutputs", () => { it("should correctly call the corresponding plugin handler", async () => { - const result = await actions.getServiceOutputs({ service }) + const result = await actions.getServiceOutputs({ log, service }) expect(result).to.eql({ foo: "bar" }) }) }) describe("execInService", () => { it("should correctly call the corresponding plugin handler", async () => { - const result = await actions.execInService({ service, command: ["foo"] }) + const result = await actions.execInService({ log, service, command: ["foo"] }) expect(result).to.eql({ code: 0, output: "bla bla" }) }) }) @@ -266,7 +272,7 @@ describe("ActionHelper", () => { describe("getServiceLogs", () => { it("should correctly call the corresponding plugin handler", async () => { const stream = new Stream() - const result = await actions.getServiceLogs({ service, stream, tail: false }) + const result = await actions.getServiceLogs({ log, service, stream, tail: false }) expect(result).to.eql({}) }) }) @@ -274,6 +280,7 @@ describe("ActionHelper", () => { describe("runService", () => { it("should correctly call the corresponding plugin handler", async () => { const result = await actions.runService({ + log, service, interactive: true, runtimeContext: { diff --git a/garden-service/test/src/build-dir.ts b/garden-service/test/src/build-dir.ts index 9f8fbaae3c6..11ac999fd19 100644 --- a/garden-service/test/src/build-dir.ts +++ b/garden-service/test/src/build-dir.ts @@ -65,6 +65,8 @@ describe("BuildDir", () => { it("should sync dependency products to their specified destinations", async () => { const garden = await makeGarden() + const log = garden.log.info() + try { await garden.clearBuilds() const modules = await garden.getModules() @@ -72,6 +74,7 @@ describe("BuildDir", () => { await Bluebird.map(modules, async (module) => { return garden.addTask(new BuildTask({ garden, + log, module, force: true, })) diff --git a/garden-service/test/src/commands/build.ts b/garden-service/test/src/commands/build.ts index 789b0c93bc1..7fe9bd7fbb0 100644 --- a/garden-service/test/src/commands/build.ts +++ b/garden-service/test/src/commands/build.ts @@ -6,10 +6,12 @@ import { taskResultOutputs } from "../../helpers" describe("commands.build", () => { it("should build all modules in a project", async () => { const garden = await makeTestGardenA() + const log = garden.log.info() const command = new BuildCommand() const { result } = await command.action({ garden, + log, args: { module: undefined }, opts: { watch: false, force: true }, }) @@ -23,10 +25,12 @@ describe("commands.build", () => { it("should optionally build single module and its dependencies", async () => { const garden = await makeTestGardenA() + const log = garden.log.info() const command = new BuildCommand() const { result } = await command.action({ garden, + log, args: { module: ["module-b"] }, opts: { watch: false, force: true }, }) diff --git a/garden-service/test/src/commands/call.ts b/garden-service/test/src/commands/call.ts index 891271c557e..b53f809e455 100644 --- a/garden-service/test/src/commands/call.ts +++ b/garden-service/test/src/commands/call.ts @@ -59,13 +59,19 @@ describe("commands.call", () => { it("should find the ingress for a service and call it with the specified path", async () => { const garden = await Garden.factory(projectRootB, { plugins }) + const log = garden.log.info() const command = new CallCommand() nock("http://service-a.test-project-b.local.app.garden:32000") .get("/path-a") .reply(200, "bla") - const { result } = await command.action({ garden, args: { serviceAndPath: "service-a/path-a" }, opts: {} }) + const { result } = await command.action({ + garden, + log, + args: { serviceAndPath: "service-a/path-a" }, + opts: {}, + }) expect(result.url).to.equal("http://service-a.test-project-b.local.app.garden:32000/path-a") expect(result.serviceName).to.equal("service-a") @@ -77,13 +83,19 @@ describe("commands.call", () => { it("should default to the path '/' if that is exposed if no path is requested", async () => { const garden = await Garden.factory(projectRootB, { plugins }) + const log = garden.log.info() const command = new CallCommand() nock("http://service-a.test-project-b.local.app.garden:32000") .get("/path-a") .reply(200, "bla") - const { result } = await command.action({ garden, args: { serviceAndPath: "service-a" }, opts: {} }) + const { result } = await command.action({ + garden, + log, + args: { serviceAndPath: "service-a" }, + opts: {}, + }) expect(result.url).to.equal("http://service-a.test-project-b.local.app.garden:32000/path-a") expect(result.serviceName).to.equal("service-a") @@ -94,13 +106,19 @@ describe("commands.call", () => { it("should otherwise use the first defined ingress if no path is requested", async () => { const garden = await Garden.factory(projectRootB, { plugins }) + const log = garden.log.info() const command = new CallCommand() nock("http://service-b.test-project-b.local.app.garden:32000") .get("/") .reply(200, "bla") - const { result } = await command.action({ garden, args: { serviceAndPath: "service-b" }, opts: {} }) + const { result } = await command.action({ + garden, + log, + args: { serviceAndPath: "service-b" }, + opts: {}, + }) expect(result.url).to.equal("http://service-b.test-project-b.local.app.garden:32000/") expect(result.serviceName).to.equal("service-b") @@ -111,10 +129,16 @@ describe("commands.call", () => { it("should error if service isn't running", async () => { const garden = await Garden.factory(projectRootB, { plugins }) + const log = garden.log.info() const command = new CallCommand() try { - await command.action({ garden, args: { serviceAndPath: "service-d/path-d" }, opts: {} }) + await command.action({ + garden, + log, + args: { serviceAndPath: "service-d/path-d" }, + opts: {}, + }) } catch (err) { expect(err.type).to.equal("runtime") return @@ -125,10 +149,16 @@ describe("commands.call", () => { it("should error if service has no ingresses", async () => { const garden = await Garden.factory(projectRootB, { plugins }) + const log = garden.log.info() const command = new CallCommand() try { - await command.action({ garden, args: { serviceAndPath: "service-c/path-c" }, opts: {} }) + await command.action({ + garden, + log, + args: { serviceAndPath: "service-c/path-c" }, + opts: {}, + }) } catch (err) { expect(err.type).to.equal("parameter") return @@ -139,10 +169,16 @@ describe("commands.call", () => { it("should error if service has no matching ingresses", async () => { const garden = await Garden.factory(projectRootB, { plugins }) + const log = garden.log.info() const command = new CallCommand() try { - await command.action({ garden, args: { serviceAndPath: "service-a/bla" }, opts: {} }) + await command.action({ + garden, + log, + args: { serviceAndPath: "service-a/bla" }, + opts: {}, + }) } catch (err) { expect(err.type).to.equal("parameter") return diff --git a/garden-service/test/src/commands/create/module.ts b/garden-service/test/src/commands/create/module.ts index 5fa50f2c361..4b204cc6bdd 100644 --- a/garden-service/test/src/commands/create/module.ts +++ b/garden-service/test/src/commands/create/module.ts @@ -35,7 +35,15 @@ describe("CreateModuleCommand", () => { it("should add a module config to the current directory", async () => { replaceAddConfigForModule() const garden = await makeTestGarden(projectRoot) - const { result } = await cmd.action({ garden, args: { "module-dir": "" }, opts: { name: "", type: "" } }) + const log = garden.log.info() + + const { result } = await cmd.action({ + garden, + log, + args: { "module-dir": "" }, + opts: { name: "", type: "" }, + }) + expect(pick(result.module, ["name", "type", "path"])).to.eql({ name: "test-project-create-command", type: "container", @@ -46,8 +54,11 @@ describe("CreateModuleCommand", () => { it("should add a module config to new-module directory", async () => { replaceAddConfigForModule() const garden = await makeTestGarden(projectRoot) + const log = garden.log.info() + const { result } = await cmd.action({ garden, + log, args: { "module-dir": "new-module" }, opts: { name: "", type: "" }, }) @@ -61,8 +72,11 @@ describe("CreateModuleCommand", () => { it("should optionally name the module my-module", async () => { replaceAddConfigForModule() const garden = await makeTestGarden(projectRoot) + const log = garden.log.info() + const { result } = await cmd.action({ garden, + log, args: { "module-dir": "" }, opts: { name: "my-module", type: "" }, }) @@ -75,8 +89,11 @@ describe("CreateModuleCommand", () => { // garden create module --type=google-cloud-function it("should optionally create a module of a specific type (without prompting)", async () => { const garden = await makeTestGarden(projectRoot) + const log = garden.log.info() + const { result } = await cmd.action({ garden, + log, args: { "module-dir": "" }, opts: { name: "", type: "google-cloud-function" }, }) @@ -90,8 +107,15 @@ describe("CreateModuleCommand", () => { it("should throw if module name is invalid when inherited from current directory", async () => { replaceAddConfigForModule() const garden = await makeTestGarden(projectRoot) + const log = garden.log.info() + await expectError( - async () => await cmd.action({ garden, args: { "module-dir": "___" }, opts: { name: "", type: "" } }), + async () => await cmd.action({ + garden, + log, + args: { "module-dir": "___" }, + opts: { name: "", type: "" }, + }), "configuration", ) }) @@ -99,8 +123,15 @@ describe("CreateModuleCommand", () => { it("should throw if module name is invalid when explicitly specified", async () => { replaceAddConfigForModule() const garden = await makeTestGarden(projectRoot) + const log = garden.log.info() + await expectError( - async () => await cmd.action({ garden, args: { "module-dir": "" }, opts: { name: "___", type: "" } }), + async () => await cmd.action({ + garden, + log, + args: { "module-dir": "" }, + opts: { name: "___", type: "" }, + }), "configuration", ) }) @@ -108,8 +139,15 @@ describe("CreateModuleCommand", () => { it("should throw if invalid type provided", async () => { replaceAddConfigForModule() const garden = await makeTestGarden(projectRoot) + const log = garden.log.info() + await expectError( - async () => await cmd.action({ garden, args: { "module-dir": "" }, opts: { name: "", type: "banana" } }), + async () => await cmd.action({ + garden, + log, + args: { "module-dir": "" }, + opts: { name: "", type: "banana" }, + }), "parameter", ) }) diff --git a/garden-service/test/src/commands/create/project.ts b/garden-service/test/src/commands/create/project.ts index f340ca99782..4712df776e2 100644 --- a/garden-service/test/src/commands/create/project.ts +++ b/garden-service/test/src/commands/create/project.ts @@ -6,6 +6,8 @@ import { join } from "path" import * as td from "testdouble" import { CreateProjectCommand } from "../../../../src/commands/create/project" +import { LogEntry } from "../../../../src/logger/log-entry" +import { Garden } from "../../../../src/garden" import { prompts, ModuleTypeAndName, @@ -41,6 +43,14 @@ describe("CreateProjectCommand", () => { const projectRoot = join(__dirname, "../../..", "data", "test-project-create-command") const cmd = new CreateProjectCommand() + let garden: Garden + let log: LogEntry + + beforeEach(async () => { + garden = await makeTestGarden(projectRoot) + log = garden.log.info() + }) + afterEach(async () => { await remove(join(projectRoot, "new-project")) }) @@ -48,9 +58,9 @@ describe("CreateProjectCommand", () => { // garden create project it("should create a project in the current directory", async () => { replaceRepeatAddModule() - const garden = await makeTestGarden(projectRoot) const { result } = await cmd.action({ garden, + log, args: { "project-dir": "" }, opts: { name: "", "module-dirs": [] }, }) @@ -71,9 +81,9 @@ describe("CreateProjectCommand", () => { // garden create project new-project it("should create a project in directory new-project", async () => { replaceRepeatAddModule() - const garden = await makeTestGarden(projectRoot) const { result } = await cmd.action({ garden, + log, args: { "project-dir": "new-project" }, opts: { name: "", "module-dirs": [] }, }) @@ -85,9 +95,9 @@ describe("CreateProjectCommand", () => { // garden create project --name=my-project it("should optionally create a project named my-project", async () => { replaceRepeatAddModule() - const garden = await makeTestGarden(projectRoot) const { result } = await cmd.action({ garden, + log, args: { "project-dir": "" }, opts: { name: "my-project", "module-dirs": [] }, }) @@ -99,9 +109,9 @@ describe("CreateProjectCommand", () => { // garden create project --module-dirs=. it("should optionally create module configs for modules in current directory", async () => { replaceAddConfigForModule() - const garden = await makeTestGarden(projectRoot) const { result } = await cmd.action({ garden, + log, args: { "project-dir": "" }, opts: { name: "", "module-dirs": ["."] }, }) @@ -113,9 +123,9 @@ describe("CreateProjectCommand", () => { // garden create project --module-dirs=module-a,module-b it("should optionally create module configs for modules in specified directories", async () => { replaceAddConfigForModule() - const garden = await makeTestGarden(projectRoot) const { result } = await cmd.action({ garden, + log, args: { "project-dir": "" }, opts: { name: "", "module-dirs": ["module-a", "module-b"] }, }) @@ -127,10 +137,10 @@ describe("CreateProjectCommand", () => { // garden create project ___ it("should throw if project name is invalid when inherited from current directory", async () => { replaceRepeatAddModule() - const garden = await makeTestGarden(projectRoot) await expectError( async () => await cmd.action({ garden, + log, args: { "project-dir": "___" }, opts: { name: "", "module-dirs": [] }, }), @@ -140,10 +150,10 @@ describe("CreateProjectCommand", () => { // garden create project --name=____ it("should throw if project name is invalid when explicitly specified", async () => { replaceRepeatAddModule() - const garden = await makeTestGarden(projectRoot) await expectError( async () => await cmd.action({ garden, + log, args: { "project-dir": "" }, opts: { name: "___", "module-dirs": [] }, }), diff --git a/garden-service/test/src/commands/delete.ts b/garden-service/test/src/commands/delete.ts index 5e3f47f09b5..5f375b91921 100644 --- a/garden-service/test/src/commands/delete.ts +++ b/garden-service/test/src/commands/delete.ts @@ -17,24 +17,26 @@ describe("DeleteSecretCommand", () => { it("should delete a secret", async () => { const garden = await makeTestGardenA() + const log = garden.log.info() const command = new DeleteSecretCommand() const key = "mykey" const value = "myvalue" - await garden.actions.setSecret({ key, value, pluginName }) + await garden.actions.setSecret({ log, key, value, pluginName }) - await command.action({ garden, args: { provider, key }, opts: {} }) + await command.action({ garden, log, args: { provider, key }, opts: {} }) - expect(await garden.actions.getSecret({ pluginName, key })).to.eql({ value: null }) + expect(await garden.actions.getSecret({ log, pluginName, key })).to.eql({ value: null }) }) it("should throw on missing key", async () => { const garden = await makeTestGardenA() + const log = garden.log.info() const command = new DeleteSecretCommand() await expectError( - async () => await command.action({ garden, args: { provider, key: "foo" }, opts: {} }), + async () => await command.action({ garden, log, args: { provider, key: "foo" }, opts: {} }), "not-found", ) }) @@ -69,8 +71,9 @@ describe("DeleteEnvironmentCommand", () => { it("should destroy environment", async () => { const garden = await Garden.factory(projectRootB, { plugins }) + const log = garden.log.info() - const { result } = await command.action({ garden, args: {}, opts: {} }) + const { result } = await command.action({ garden, log, args: {}, opts: {} }) expect(result!["test-plugin"]["ready"]).to.be.false }) @@ -109,8 +112,9 @@ describe("DeleteServiceCommand", () => { it("should return the status of the deleted service", async () => { const garden = await Garden.factory(projectRootB, { plugins }) + const log = garden.log.info() - const { result } = await command.action({ garden, args: { service: ["service-a"] }, opts: {} }) + const { result } = await command.action({ garden, log, args: { service: ["service-a"] }, opts: {} }) expect(result).to.eql({ "service-a": { state: "unknown", ingresses: [] }, }) @@ -118,8 +122,14 @@ describe("DeleteServiceCommand", () => { it("should return the status of the deleted services", async () => { const garden = await Garden.factory(projectRootB, { plugins }) + const log = garden.log.info() - const { result } = await command.action({ garden, args: { service: ["service-a", "service-b"] }, opts: {} }) + const { result } = await command.action({ + garden, + log, + args: { service: ["service-a", "service-b"] }, + opts: {}, + }) expect(result).to.eql({ "service-a": { state: "unknown", ingresses: [] }, "service-b": { state: "unknown", ingresses: [] }, diff --git a/garden-service/test/src/commands/deploy.ts b/garden-service/test/src/commands/deploy.ts index fd3375afb86..cd9ca4ce650 100644 --- a/garden-service/test/src/commands/deploy.ts +++ b/garden-service/test/src/commands/deploy.ts @@ -66,10 +66,12 @@ describe("DeployCommand", () => { it("should build and deploy all modules in a project", async () => { const garden = await Garden.factory(projectRootB, { plugins }) + const log = garden.log.info() const command = new DeployCommand() const { result } = await command.action({ garden, + log, args: { service: undefined, }, @@ -96,10 +98,12 @@ describe("DeployCommand", () => { it("should optionally build and deploy single service and its dependencies", async () => { const garden = await Garden.factory(projectRootB, { plugins }) + const log = garden.log.info() const command = new DeployCommand() const { result } = await command.action({ garden, + log, args: { service: ["service-b"], }, diff --git a/garden-service/test/src/commands/get.ts b/garden-service/test/src/commands/get.ts index 8ef644621e4..652c8d2059d 100644 --- a/garden-service/test/src/commands/get.ts +++ b/garden-service/test/src/commands/get.ts @@ -8,21 +8,38 @@ describe("GetSecretCommand", () => { it("should get a config variable", async () => { const garden = await makeTestGardenA() + const log = garden.log.info() const command = new GetSecretCommand() - await garden.actions.setSecret({ pluginName, key: "project.mykey", value: "myvalue" }) + await garden.actions.setSecret({ + log, + pluginName, + key: "project.mykey", + value: "myvalue", + }) - const res = await command.action({ garden, args: { provider, key: "project.mykey" }, opts: {} }) + const res = await command.action({ + garden, + log, + args: { provider, key: "project.mykey" }, + opts: {}, + }) expect(res).to.eql({ "project.mykey": "myvalue" }) }) it("should throw on missing key", async () => { const garden = await makeTestGardenA() + const log = garden.log.info() const command = new GetSecretCommand() await expectError( - async () => await command.action({ garden, args: { provider, key: "project.mykey" }, opts: {} }), + async () => await command.action({ + garden, + log, + args: { provider, key: "project.mykey" }, + opts: {}, + }), "not-found", ) }) diff --git a/garden-service/test/src/commands/link.ts b/garden-service/test/src/commands/link.ts index 13bbe48571c..cf8af775804 100644 --- a/garden-service/test/src/commands/link.ts +++ b/garden-service/test/src/commands/link.ts @@ -11,9 +11,11 @@ import { } from "../../helpers" import { LinkSourceCommand } from "../../../src/commands/link/source" import { Garden } from "../../../src/garden" +import { LogEntry } from "../../../src/logger/log-entry" describe("LinkCommand", () => { let garden: Garden + let log: LogEntry describe("LinkModuleCommand", () => { const cmd = new LinkModuleCommand() @@ -21,6 +23,7 @@ describe("LinkCommand", () => { beforeEach(async () => { garden = await makeTestGarden(projectRoot) + log = garden.log.info() stubExtSources(garden) }) @@ -31,6 +34,7 @@ describe("LinkCommand", () => { it("should link external modules", async () => { await cmd.action({ garden, + log, args: { module: "module-a", path: join(projectRoot, "mock-local-path", "module-a"), @@ -48,6 +52,7 @@ describe("LinkCommand", () => { it("should handle relative paths", async () => { await cmd.action({ garden, + log, args: { module: "module-a", path: join("mock-local-path", "module-a"), @@ -67,6 +72,7 @@ describe("LinkCommand", () => { async () => ( await cmd.action({ garden, + log, args: { module: "banana", path: "", @@ -85,6 +91,7 @@ describe("LinkCommand", () => { beforeEach(async () => { garden = await makeTestGarden(projectRoot) + log = garden.log.info() stubExtSources(garden) }) @@ -95,6 +102,7 @@ describe("LinkCommand", () => { it("should link external sources", async () => { await cmd.action({ garden, + log, args: { source: "source-a", path: join(projectRoot, "mock-local-path", "source-a"), @@ -112,6 +120,7 @@ describe("LinkCommand", () => { it("should handle relative paths", async () => { await cmd.action({ garden, + log, args: { source: "source-a", path: join("mock-local-path", "source-a"), diff --git a/garden-service/test/src/commands/publish.ts b/garden-service/test/src/commands/publish.ts index d3f6c3b5c82..c5186e29fc8 100644 --- a/garden-service/test/src/commands/publish.ts +++ b/garden-service/test/src/commands/publish.ts @@ -10,6 +10,7 @@ import { PublishCommand } from "../../../src/commands/publish" import { makeTestGardenA } from "../../helpers" import { expectError, taskResultOutputs } from "../../helpers" import { ModuleVersion } from "../../../src/vcs/base" +import { LogEntry } from "../../../src/logger/log-entry" const projectRootB = join(__dirname, "..", "..", "data", "test-project-b") @@ -50,10 +51,12 @@ describe("PublishCommand", () => { it("should build and publish modules in a project", async () => { const garden = await getTestGarden() + const log = garden.log.info() const command = new PublishCommand() const { result } = await command.action({ garden, + log, args: { module: undefined, }, @@ -74,10 +77,12 @@ describe("PublishCommand", () => { it("should optionally force new build", async () => { const garden = await getTestGarden() + const log = garden.log.info() const command = new PublishCommand() const { result } = await command.action({ garden, + log, args: { module: undefined, }, @@ -98,10 +103,12 @@ describe("PublishCommand", () => { it("should optionally build selected module", async () => { const garden = await getTestGarden() + const log = garden.log.info() const command = new PublishCommand() const { result } = await command.action({ garden, + log, args: { module: ["module-a"], }, @@ -119,10 +126,12 @@ describe("PublishCommand", () => { it("should respect allowPublish flag", async () => { const garden = await getTestGarden() + const log = garden.log.info() const command = new PublishCommand() const { result } = await command.action({ garden, + log, args: { module: ["module-c"], }, @@ -139,12 +148,14 @@ describe("PublishCommand", () => { it("should fail gracefully if module does not have a provider for publish", async () => { const garden = await makeTestGardenA() + const log = garden.log.info() await garden.clearBuilds() const command = new PublishCommand() const { result } = await command.action({ garden, + log, args: { module: ["module-a"], }, @@ -168,6 +179,7 @@ describe("PublishCommand", () => { context("module is dirty", () => { let garden + let log: LogEntry beforeEach(async () => { td.replace(Garden.prototype, "resolveVersion", async (): Promise => { @@ -178,6 +190,7 @@ describe("PublishCommand", () => { } }) garden = await getTestGarden() + log = garden.log.info() }) it("should throw if module is dirty", async () => { @@ -185,6 +198,7 @@ describe("PublishCommand", () => { await expectError(() => command.action({ garden, + log, args: { module: ["module-a"], }, @@ -200,6 +214,7 @@ describe("PublishCommand", () => { const { result } = await command.action({ garden, + log, args: { module: ["module-a"], }, diff --git a/garden-service/test/src/commands/run/module.ts b/garden-service/test/src/commands/run/module.ts index eccbc17cd08..386c5059361 100644 --- a/garden-service/test/src/commands/run/module.ts +++ b/garden-service/test/src/commands/run/module.ts @@ -13,10 +13,12 @@ import * as td from "testdouble" describe("RunModuleCommand", () => { // TODO: test optional flags let garden + let log beforeEach(async () => { td.replace(Garden.prototype, "resolveVersion", async () => testModuleVersion) garden = await makeTestGardenA() + log = garden.log.info() }) it("should run a module without a command param", async () => { @@ -28,6 +30,7 @@ describe("RunModuleCommand", () => { const cmd = new RunModuleCommand() const { result } = await cmd.action({ garden, + log, args: { module: "run-test", command: [] }, opts: { interactive: false, "force-build": false }, }) @@ -54,6 +57,7 @@ describe("RunModuleCommand", () => { const cmd = new RunModuleCommand() const { result } = await cmd.action({ garden, + log, args: { module: "run-test", command: ["my", "command"] }, opts: { interactive: false, "force-build": false }, }) diff --git a/garden-service/test/src/commands/run/service.ts b/garden-service/test/src/commands/run/service.ts index f8d6a4ade39..5bd876ada6e 100644 --- a/garden-service/test/src/commands/run/service.ts +++ b/garden-service/test/src/commands/run/service.ts @@ -9,14 +9,17 @@ import { import { expect } from "chai" import { Garden } from "../../../../src/garden" import * as td from "testdouble" +import { LogEntry } from "../../../../src/logger/log-entry" describe("RunServiceCommand", () => { // TODO: test optional flags let garden + let log: LogEntry beforeEach(async () => { td.replace(Garden.prototype, "resolveVersion", async () => testModuleVersion) garden = await makeTestGardenA() + log = garden.log.info() }) it("should run a service", async () => { @@ -28,6 +31,7 @@ describe("RunServiceCommand", () => { const cmd = new RunServiceCommand() const { result } = await cmd.action({ garden, + log, args: { service: "test-service" }, opts: { "force-build": false }, }) diff --git a/garden-service/test/src/commands/scan.ts b/garden-service/test/src/commands/scan.ts index 6e667ae5699..abe4fc030fa 100644 --- a/garden-service/test/src/commands/scan.ts +++ b/garden-service/test/src/commands/scan.ts @@ -6,9 +6,15 @@ describe("ScanCommand", () => { for (const [name, path] of Object.entries(getExampleProjects())) { it(`should successfully scan the ${name} project`, async () => { const garden = await Garden.factory(path) + const log = garden.log.info() const command = new ScanCommand() - await command.action({ garden, args: {}, opts: {} }) + await command.action({ + garden, + log, + args: {}, + opts: {}, + }) }) } }) diff --git a/garden-service/test/src/commands/set.ts b/garden-service/test/src/commands/set.ts index e9c17d4045d..11961902af9 100644 --- a/garden-service/test/src/commands/set.ts +++ b/garden-service/test/src/commands/set.ts @@ -8,10 +8,16 @@ describe("SetSecretCommand", () => { it("should set a config variable", async () => { const garden = await makeTestGardenA() + const log = garden.log.info() const command = new SetSecretCommand() - await command.action({ garden, args: { provider, key: "mykey", value: "myvalue" }, opts: {} }) + await command.action({ + garden, + log, + args: { provider, key: "mykey", value: "myvalue" }, + opts: {}, + }) - expect(await garden.actions.getSecret({ pluginName, key: "mykey" })).to.eql({ value: "myvalue" }) + expect(await garden.actions.getSecret({ log, pluginName, key: "mykey" })).to.eql({ value: "myvalue" }) }) }) diff --git a/garden-service/test/src/commands/test.ts b/garden-service/test/src/commands/test.ts index e222cc15608..8715f4fc6cc 100644 --- a/garden-service/test/src/commands/test.ts +++ b/garden-service/test/src/commands/test.ts @@ -6,10 +6,12 @@ import { makeTestGardenA, taskResultOutputs } from "../../helpers" describe("commands.test", () => { it("should run all tests in a simple project", async () => { const garden = await makeTestGardenA() + const log = garden.log.info() const command = new TestCommand() const { result } = await command.action({ garden, + log, args: { module: undefined }, opts: { name: undefined, force: true, "force-build": true, watch: false }, }) @@ -41,10 +43,12 @@ describe("commands.test", () => { it("should optionally test single module", async () => { const garden = await makeTestGardenA() + const log = garden.log.info() const command = new TestCommand() const { result } = await command.action({ garden, + log, args: { module: ["module-a"] }, opts: { name: undefined, force: true, "force-build": true, watch: false }, }) diff --git a/garden-service/test/src/commands/unlink.ts b/garden-service/test/src/commands/unlink.ts index 3fd8789f053..9345a6c36aa 100644 --- a/garden-service/test/src/commands/unlink.ts +++ b/garden-service/test/src/commands/unlink.ts @@ -12,9 +12,11 @@ import { import { LinkSourceCommand } from "../../../src/commands/link/source" import { UnlinkSourceCommand } from "../../../src/commands/unlink/source" import { Garden } from "../../../src/garden" +import { LogEntry } from "../../../src/logger/log-entry" describe("UnlinkCommand", () => { let garden: Garden + let log: LogEntry describe("UnlinkModuleCommand", () => { const projectRoot = getDataDir("test-project-ext-module-sources") @@ -23,10 +25,12 @@ describe("UnlinkCommand", () => { beforeEach(async () => { garden = await makeTestGarden(projectRoot) + log = garden.log.info() stubExtSources(garden) await linkCmd.action({ garden, + log, args: { module: "module-a", path: join(projectRoot, "mock-local-path", "module-a"), @@ -35,6 +39,7 @@ describe("UnlinkCommand", () => { }) await linkCmd.action({ garden, + log, args: { module: "module-b", path: join(projectRoot, "mock-local-path", "module-b"), @@ -43,6 +48,7 @@ describe("UnlinkCommand", () => { }) await linkCmd.action({ garden, + log, args: { module: "module-c", path: join(projectRoot, "mock-local-path", "module-c"), @@ -58,6 +64,7 @@ describe("UnlinkCommand", () => { it("should unlink the provided modules", async () => { await unlinkCmd.action({ garden, + log, args: { module: ["module-a", "module-b"] }, opts: { all: false }, }) @@ -70,6 +77,7 @@ describe("UnlinkCommand", () => { it("should unlink all modules", async () => { await unlinkCmd.action({ garden, + log, args: { module: undefined }, opts: { all: true }, }) @@ -85,10 +93,13 @@ describe("UnlinkCommand", () => { beforeEach(async () => { garden = await makeTestGarden(projectRoot) + log = garden.log.info() + stubExtSources(garden) await linkCmd.action({ garden, + log, args: { source: "source-a", path: join(projectRoot, "mock-local-path", "source-a"), @@ -97,6 +108,7 @@ describe("UnlinkCommand", () => { }) await linkCmd.action({ garden, + log, args: { source: "source-b", path: join(projectRoot, "mock-local-path", "source-b"), @@ -105,6 +117,7 @@ describe("UnlinkCommand", () => { }) await linkCmd.action({ garden, + log, args: { source: "source-c", path: join(projectRoot, "mock-local-path", "source-c"), @@ -120,6 +133,7 @@ describe("UnlinkCommand", () => { it("should unlink the provided sources", async () => { await unlinkCmd.action({ garden, + log, args: { source: ["source-a", "source-b"] }, opts: { all: false }, }) @@ -132,6 +146,7 @@ describe("UnlinkCommand", () => { it("should unlink all sources", async () => { await unlinkCmd.action({ garden, + log, args: { source: undefined }, opts: { all: true }, }) diff --git a/garden-service/test/src/commands/update-remote.ts b/garden-service/test/src/commands/update-remote.ts index c27f16705e2..674a44c25c6 100644 --- a/garden-service/test/src/commands/update-remote.ts +++ b/garden-service/test/src/commands/update-remote.ts @@ -14,13 +14,16 @@ import { getDataDir, expectError, stubExtSources, stubGitCli, makeTestGarden } f import { UpdateRemoteSourcesCommand } from "../../../src/commands/update-remote/sources" import { UpdateRemoteModulesCommand } from "../../../src/commands/update-remote/modules" import { Garden } from "../../../src/garden" +import { LogEntry } from "../../../src/logger/log-entry" describe("UpdateRemoteCommand", () => { describe("UpdateRemoteSourcesCommand", () => { let garden: Garden + let log: LogEntry beforeEach(async () => { garden = await makeTestGarden(projectRoot) + log = garden.log.info() stubGitCli() }) @@ -28,26 +31,46 @@ describe("UpdateRemoteCommand", () => { const cmd = new UpdateRemoteSourcesCommand() it("should update all project sources", async () => { - const { result } = await cmd.action({ garden, args: { source: undefined }, opts: {} }) + const { result } = await cmd.action({ + garden, + log, + args: { source: undefined }, + opts: {}, + }) expect(result!.map(s => s.name).sort()).to.eql(["source-a", "source-b", "source-c"]) }) it("should update the specified project sources", async () => { - const { result } = await cmd.action({ garden, args: { source: ["source-a"] }, opts: {} }) + const { result } = await cmd.action({ + garden, + log, + args: { source: ["source-a"] }, + opts: {}, + }) expect(result!.map(s => s.name).sort()).to.eql(["source-a"]) }) it("should remove stale remote project sources", async () => { const stalePath = join(projectRoot, ".garden", "sources", "project", "stale-source") await mkdirp(stalePath) - await cmd.action({ garden, args: { source: undefined }, opts: {} }) + await cmd.action({ + garden, + log, + args: { source: undefined }, + opts: {}, + }) expect(await pathExists(stalePath)).to.be.false }) it("should throw if project source is not found", async () => { await expectError( async () => ( - await cmd.action({ garden, args: { source: ["banana"] }, opts: {} }) + await cmd.action({ + garden, + log, + args: { source: ["banana"] }, + opts: {}, + }) ), "parameter", ) @@ -56,9 +79,11 @@ describe("UpdateRemoteCommand", () => { describe("UpdateRemoteModulesCommand", () => { let garden: Garden + let log: LogEntry beforeEach(async () => { garden = await makeTestGarden(projectRoot) + log = garden.log.info() stubExtSources(garden) }) @@ -66,26 +91,46 @@ describe("UpdateRemoteCommand", () => { const cmd = new UpdateRemoteModulesCommand() it("should update all modules sources", async () => { - const { result } = await cmd.action({ garden, args: { module: undefined }, opts: {} }) + const { result } = await cmd.action({ + garden, + log, + args: { module: undefined }, + opts: {}, + }) expect(result!.map(s => s.name).sort()).to.eql(["module-a", "module-b", "module-c"]) }) it("should update the specified module sources", async () => { - const { result } = await cmd.action({ garden, args: { module: ["module-a"] }, opts: {} }) + const { result } = await cmd.action({ + garden, + log, + args: { module: ["module-a"] }, + opts: {}, + }) expect(result!.map(s => s.name).sort()).to.eql(["module-a"]) }) it("should remove stale remote module sources", async () => { const stalePath = join(projectRoot, ".garden", "sources", "module", "stale-source") await mkdirp(stalePath) - await cmd.action({ garden, args: { module: undefined }, opts: {} }) + await cmd.action({ + garden, + log, + args: { module: undefined }, + opts: {}, + }) expect(await pathExists(stalePath)).to.be.false }) it("should throw if project source is not found", async () => { await expectError( async () => ( - await cmd.action({ garden, args: { module: ["banana"] }, opts: {} }) + await cmd.action({ + garden, + log, + args: { module: ["banana"] }, + opts: {}, + }) ), "parameter", ) diff --git a/garden-service/test/src/commands/validate.ts b/garden-service/test/src/commands/validate.ts index cdbcb4a07a1..40d7c33ddc7 100644 --- a/garden-service/test/src/commands/validate.ts +++ b/garden-service/test/src/commands/validate.ts @@ -8,9 +8,15 @@ describe("commands.validate", () => { for (const [name, path] of Object.entries(getExampleProjects())) { it(`should successfully validate the ${name} project`, async () => { const garden = await Garden.factory(path) + const log = garden.log.info() const command = new ValidateCommand() - await command.action({ garden, args: {}, opts: {} }) + await command.action({ + garden, + log, + args: {}, + opts: {}, + }) }) } @@ -23,8 +29,14 @@ describe("commands.validate", () => { it("should fail validating the bad-module project", async () => { const root = join(__dirname, "data", "validate", "bad-module") const garden = await Garden.factory(root) + const log = garden.log.info() const command = new ValidateCommand() - await expectError(async () => await command.action({ garden, args: {}, opts: {} }), "configuration") + await expectError(async () => await command.action({ + garden, + log, + args: {}, + opts: {}, + }), "configuration") }) }) diff --git a/garden-service/test/src/config/config-context.ts b/garden-service/test/src/config/config-context.ts index 67623a50f8a..9f68d59a7a9 100644 --- a/garden-service/test/src/config/config-context.ts +++ b/garden-service/test/src/config/config-context.ts @@ -233,6 +233,7 @@ describe("ModuleConfigContext", () => { await garden.scanModules() c = new ModuleConfigContext( garden, + garden.log.info(), garden.environment, Object.values((garden).moduleConfigs), ) diff --git a/garden-service/test/src/plugins/container.ts b/garden-service/test/src/plugins/container.ts index 7f489cf9662..b5a2be94faa 100644 --- a/garden-service/test/src/plugins/container.ts +++ b/garden-service/test/src/plugins/container.ts @@ -14,6 +14,7 @@ import { makeTestGarden, } from "../../helpers" import { moduleFromConfig } from "../../../src/types/module" +import { LogEntry } from "../../../src/logger/log-entry" describe("plugins.container", () => { const projectRoot = resolve(dataDir, "test-project-container") @@ -27,9 +28,11 @@ describe("plugins.container", () => { let garden: Garden let ctx: PluginContext + let log: LogEntry beforeEach(async () => { garden = await makeTestGarden(projectRoot, { container: gardenPlugin }) + log = garden.log.info() ctx = garden.getPluginContext("container") td.replace(garden.buildDir, "syncDependencyProducts", () => null) @@ -486,7 +489,7 @@ describe("plugins.container", () => { td.replace(helpers, "imageExistsLocally", async () => true) - const result = await getBuildStatus({ ctx, module }) + const result = await getBuildStatus({ ctx, log, module }) expect(result).to.eql({ ready: true }) }) @@ -514,7 +517,7 @@ describe("plugins.container", () => { td.replace(helpers, "imageExistsLocally", async () => false) - const result = await getBuildStatus({ ctx, module }) + const result = await getBuildStatus({ ctx, log, module }) expect(result).to.eql({ ready: false }) }) }) @@ -547,7 +550,7 @@ describe("plugins.container", () => { td.replace(helpers, "pullImage", async () => null) td.replace(helpers, "imageExistsLocally", async () => false) - const result = await build({ ctx, module }) + const result = await build({ ctx, log, module }) expect(result).to.eql({ fetched: true }) }) @@ -581,7 +584,7 @@ describe("plugins.container", () => { const dockerCli = td.replace(helpers, "dockerCli") - const result = await build({ ctx, module }) + const result = await build({ ctx, log, module }) expect(result).to.eql({ fresh: true, @@ -618,7 +621,7 @@ describe("plugins.container", () => { td.replace(helpers, "hasDockerfile", async () => false) - const result = await publishModule({ ctx, module }) + const result = await publishModule({ ctx, log, module }) expect(result).to.eql({ published: false }) }) @@ -651,7 +654,7 @@ describe("plugins.container", () => { const dockerCli = td.replace(helpers, "dockerCli") - const result = await publishModule({ ctx, module }) + const result = await publishModule({ ctx, log, module }) expect(result).to.eql({ message: "Published some/image:12345", published: true }) td.verify(dockerCli(module, "tag some/image:12345 some/image:12345"), { times: 0 }) @@ -687,7 +690,7 @@ describe("plugins.container", () => { const dockerCli = td.replace(helpers, "dockerCli") - const result = await publishModule({ ctx, module }) + const result = await publishModule({ ctx, log, module }) expect(result).to.eql({ message: "Published some/image:1.1", published: true }) td.verify(dockerCli(module, "tag some/image:12345 some/image:1.1")) diff --git a/garden-service/test/src/plugins/generic.ts b/garden-service/test/src/plugins/generic.ts index 72b498b403d..38111272aa9 100644 --- a/garden-service/test/src/plugins/generic.ts +++ b/garden-service/test/src/plugins/generic.ts @@ -6,6 +6,7 @@ import { import { Garden } from "../../../src/garden" import { gardenPlugin } from "../../../src/plugins/generic" import { GARDEN_BUILD_VERSION_FILENAME } from "../../../src/constants" +import { LogEntry } from "../../../src/logger/log-entry" import { writeModuleVersionFile, readModuleVersionFile, @@ -20,9 +21,11 @@ describe("generic plugin", () => { const moduleName = "module-a" let garden: Garden + let log: LogEntry beforeEach(async () => { garden = await makeTestGarden(projectRoot, { generic: gardenPlugin }) + log = garden.log.info() await garden.clearBuilds() }) @@ -35,7 +38,7 @@ describe("generic plugin", () => { await writeModuleVersionFile(versionFilePath, version) - const result = await garden.actions.getBuildStatus({ module }) + const result = await garden.actions.getBuildStatus({ log, module }) expect(result.ready).to.be.true }) @@ -48,7 +51,7 @@ describe("generic plugin", () => { const buildPath = module.buildPath const versionFilePath = join(buildPath, GARDEN_BUILD_VERSION_FILENAME) - await garden.actions.build({ module }) + await garden.actions.build({ log, module }) const versionFileContents = await readModuleVersionFile(versionFilePath) diff --git a/garden-service/test/src/task-graph.ts b/garden-service/test/src/task-graph.ts index 2f0d16b312b..1b848bfc3ed 100644 --- a/garden-service/test/src/task-graph.ts +++ b/garden-service/test/src/task-graph.ts @@ -34,6 +34,7 @@ class TestTask extends Task { ) { super({ garden, + log: garden.log.info(), version: { versionString: "12345-6789", dirtyTimestamp: 6789, diff --git a/garden-service/test/src/tasks/test.ts b/garden-service/test/src/tasks/test.ts index 6196e4223ad..f7573833781 100644 --- a/garden-service/test/src/tasks/test.ts +++ b/garden-service/test/src/tasks/test.ts @@ -4,12 +4,15 @@ import { TestTask } from "../../../src/tasks/test" import * as td from "testdouble" import { Garden } from "../../../src/garden" import { dataDir, makeTestGarden } from "../../helpers" +import { LogEntry } from "../../../src/logger/log-entry" describe("TestTask", () => { let garden: Garden + let log: LogEntry beforeEach(async () => { garden = await makeTestGarden(resolve(dataDir, "test-project-test-deps")) + log = garden.log.info() }) it("should correctly resolve version for tests with dependencies", async () => { @@ -37,6 +40,7 @@ describe("TestTask", () => { const task = await TestTask.factory({ garden, + log, module: moduleA, testConfig, force: true,