From ba7597f5570aa5ecdb00e19bc6aecf5efc43ff29 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 | 61 ++++++++++--------- garden-service/src/cli/cli.ts | 3 + garden-service/src/commands/base.ts | 9 ++- garden-service/src/commands/build.ts | 14 +++-- garden-service/src/commands/call.ts | 12 ++-- garden-service/src/commands/create/module.ts | 14 ++--- garden-service/src/commands/create/project.ts | 19 +++--- garden-service/src/commands/delete.ts | 26 ++++---- garden-service/src/commands/deploy.ts | 21 ++++--- garden-service/src/commands/dev.ts | 28 ++++++--- garden-service/src/commands/exec.ts | 8 ++- garden-service/src/commands/get.ts | 16 +++-- garden-service/src/commands/helpers.ts | 24 +++++--- garden-service/src/commands/init.ts | 11 ++-- garden-service/src/commands/link/module.ts | 11 ++-- garden-service/src/commands/link/source.ts | 7 ++- garden-service/src/commands/logs.ts | 8 +-- garden-service/src/commands/publish.ts | 13 ++-- garden-service/src/commands/run/module.ts | 17 +++--- garden-service/src/commands/run/run.ts | 16 ++--- garden-service/src/commands/run/service.ts | 21 ++++--- garden-service/src/commands/run/test.ts | 15 +++-- garden-service/src/commands/scan.ts | 4 +- garden-service/src/commands/set.ts | 11 +++- garden-service/src/commands/test.ts | 15 +++-- garden-service/src/commands/unlink/module.ts | 9 +-- garden-service/src/commands/unlink/source.ts | 9 +-- .../src/commands/update-remote/all.ts | 20 ++++-- .../src/commands/update-remote/modules.ts | 9 ++- .../src/commands/update-remote/sources.ts | 7 ++- garden-service/src/commands/validate.ts | 5 +- garden-service/src/config/config-context.ts | 4 +- garden-service/src/garden.ts | 8 +-- garden-service/src/logger/log-entry.ts | 8 +-- garden-service/src/logger/logger.ts | 15 +---- garden-service/src/logger/renderers.ts | 2 +- garden-service/src/logger/util.ts | 23 ++++++- .../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 | 16 ++--- .../src/plugins/kubernetes/deployment.ts | 20 +++--- garden-service/src/plugins/kubernetes/helm.ts | 48 +++++++-------- garden-service/src/plugins/kubernetes/init.ts | 51 ++++++++-------- .../src/plugins/kubernetes/local.ts | 8 +-- .../src/plugins/kubernetes/status.ts | 14 ++--- .../src/plugins/local/local-docker-swarm.ts | 18 +++--- .../src/plugins/openfaas/openfaas.ts | 30 +++++---- garden-service/src/process.ts | 15 +++-- garden-service/src/task-graph.ts | 13 ++-- garden-service/src/tasks/base.ts | 4 ++ garden-service/src/tasks/build.ts | 17 +++--- garden-service/src/tasks/deploy.ts | 26 ++++---- garden-service/src/tasks/helpers.ts | 15 ++--- garden-service/src/tasks/publish.ts | 19 +++--- garden-service/src/tasks/push.ts | 17 +++--- garden-service/src/tasks/test.ts | 52 ++++++++-------- garden-service/src/types/plugin/params.ts | 8 +-- garden-service/src/types/plugin/plugin.ts | 2 +- garden-service/src/types/service.ts | 11 +++- garden-service/src/util/ext-tools.ts | 22 +++---- 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 | 44 +++++++------ 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/logger.ts | 8 +-- garden-service/test/src/plugins/container.ts | 19 +++--- garden-service/test/src/plugins/generic.ts | 7 ++- garden-service/test/src/task-graph.ts | 9 +-- garden-service/test/src/tasks/test.ts | 4 ++ 91 files changed, 898 insertions(+), 528 deletions(-) diff --git a/garden-service/src/actions.ts b/garden-service/src/actions.ts index d1d37951a2e..9e208e87dd4 100644 --- a/garden-service/src/actions.ts +++ b/garden-service/src/actions.ts @@ -83,7 +83,8 @@ export interface ContextStatus { } export interface DeployServicesParams { - serviceNames?: string[], + log: LogEntry + serviceNames?: string[] force?: boolean forceBuild?: boolean } @@ -108,10 +109,10 @@ export class ActionHelper implements TypeGuard { //=========================================================================== async getEnvironmentStatus( - { pluginName }: ActionHelperParams, + { pluginName, log }: ActionHelperParams, ): Promise { const handlers = this.garden.getActionHandlers("getEnvironmentStatus", pluginName) - return Bluebird.props(mapValues(handlers, h => h({ ...this.commonParams(h) }))) + return Bluebird.props(mapValues(handlers, h => h({ ...this.commonParams(h, log) }))) } /** @@ -121,11 +122,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 })) @@ -153,13 +154,13 @@ export class ActionHelper implements TypeGuard { continue } - const envLogEntry = (logEntry || this.garden.log).info({ + const envLogEntry = log.info({ status: "active", section: name, msg: "Preparing environment...", }) - await handler({ ...this.commonParams(handler), force, status, logEntry: envLogEntry }) + await handler({ ...this.commonParams(handler, log), force, status, log: envLogEntry }) envLogEntry.setSuccess("Configured") @@ -170,11 +171,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 }) + await Bluebird.each(values(handlers), h => h({ ...this.commonParams(h, log) })) + return this.getEnvironmentStatus({ pluginName, log }) } async getSecret(params: RequirePluginName>): Promise { @@ -263,13 +264,13 @@ export class ActionHelper implements TypeGuard { } async deleteService(params: ServiceActionHelperParams): Promise { - const logEntry = this.garden.log.info({ + const log = params.log.info({ section: params.service.name, msg: "Deleting...", status: "active", }) return this.callServiceHandler({ - params: { ...params, logEntry }, + params: { ...params, log }, actionType: "deleteService", defaultHandler: dummyDeleteServiceHandler, }) @@ -306,14 +307,14 @@ export class ActionHelper implements TypeGuard { return keyBy(dependencies, "name") } - 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 serviceDependencies = await this.garden.getServices(service.config.dependencies) - const runtimeContext = await prepareRuntimeContext(this.garden, service.module, serviceDependencies) - return this.getServiceStatus({ service, runtimeContext }) + const runtimeContext = await prepareRuntimeContext(this.garden, log, service.module, serviceDependencies) + return this.getServiceStatus({ log, service, runtimeContext }) })) return { @@ -323,16 +324,18 @@ 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) return processServices({ services, garden: this.garden, + log, watch: false, handler: async (module) => getDeployTasks({ garden: this.garden, + log, module, serviceNames, hotReloadServiceNames: [], @@ -345,11 +348,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, } } @@ -368,7 +371,7 @@ export class ActionHelper implements TypeGuard { defaultHandler, }) const handlerParams: PluginActionParams[T] = { - ...this.commonParams(handler), + ...this.commonParams(handler, params.log), ...params, } return (handler)(handlerParams) @@ -390,7 +393,7 @@ export class ActionHelper implements TypeGuard { const buildDependencies = await this.getBuildDependencies(module) const handlerParams: any = { - ...this.commonParams(handler), + ...this.commonParams(handler, params.log), ...params, module: omit(module, ["_ConfigType"]), buildDependencies, @@ -403,7 +406,7 @@ export class ActionHelper implements TypeGuard { { params, actionType, defaultHandler }: { params: ServiceActionHelperParams, actionType: T, defaultHandler?: ServiceActions[T] }, ): Promise { - const { service } = params + const { log, service } = params const module = service.module const handler = await this.garden.getModuleActionHandler({ @@ -416,10 +419,10 @@ export class ActionHelper implements TypeGuard { // TODO: figure out why this doesn't compile without the casts const buildDependencies = await this.getBuildDependencies(module) const deps = await this.garden.getServices(service.config.dependencies) - const runtimeContext = ((params).runtimeContext || await prepareRuntimeContext(this.garden, module, deps)) + const runtimeContext = ((params).runtimeContext || await prepareRuntimeContext(this.garden, log, module, deps)) const handlerParams: any = { - ...this.commonParams(handler), + ...this.commonParams(handler, log), ...params, module, runtimeContext, @@ -430,8 +433,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}`), }) @@ -449,8 +452,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..958656a984a 100644 --- a/garden-service/src/cli/cli.ts +++ b/garden-service/src/cli/cli.ts @@ -238,9 +238,12 @@ export class GardenCli { contextOpts.config = MOCK_CONFIG } garden = await Garden.factory(root, contextOpts) + // Indent -1 so that the children of this entry get printed with indent 0 + const log = garden.log.info({ indent: -1 }) // 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..8a07df60607 100644 --- a/garden-service/src/commands/base.ts +++ b/garden-service/src/commands/base.ts @@ -14,6 +14,8 @@ import { TaskResults } from "../task-graph" import { LoggerType } from "../logger/logger" import { ProcessResults } from "../process" import { Garden } from "../garden" +import { LogEntry } from "../logger/log-entry" +import { logHeader } from "../logger/util" export class ValidationError extends Error { } @@ -188,6 +190,7 @@ export interface CommandParams opts: ParameterValues garden: Garden + log: LogEntry } export abstract class Command { @@ -232,7 +235,7 @@ export abstract class Command> { const failed = Object.values(results.taskResults).filter(r => !!r.error).length @@ -243,9 +246,9 @@ export async function handleTaskResults( return { errors: [error] } } - garden.log.info("") + log.info("") if (!results.restartRequired) { - garden.log.header({ emoji: "heavy_check_mark", command: `Done!` }) + logHeader({ log, emoji: "heavy_check_mark", command: `Done!` }) } return { result: results.taskResults, diff --git a/garden-service/src/commands/build.ts b/garden-service/src/commands/build.ts index 2fa53e97898..d8de31b5739 100644 --- a/garden-service/src/commands/build.ts +++ b/garden-service/src/commands/build.ts @@ -21,6 +21,7 @@ import { processModules } from "../process" import { computeAutoReloadDependants, withDependants } from "../watch" import { Module } from "../types/module" import { hotReloadAndLog } from "./helpers" +import { logHeader } from "../logger/util" const buildArguments = { module: new StringsParameter({ @@ -56,7 +57,7 @@ export class BuildCommand extends Command { options = buildOptions async action( - { args, opts, garden }: CommandParams, + { args, opts, garden, log }: CommandParams, ): Promise> { await garden.clearBuilds() @@ -65,25 +66,26 @@ export class BuildCommand extends Command { const modules = await garden.getModules(args.module) const moduleNames = modules.map(m => m.name) - garden.log.header({ emoji: "hammer", command: "Build" }) + logHeader({ log, emoji: "hammer", command: "Build" }) const results = await processModules({ garden, + log, 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) => { if (module.spec.hotReload) { - await hotReloadAndLog(garden, module) + await hotReloadAndLog(garden, log, 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 })) }, }) - return handleTaskResults(garden, "build", results) + return handleTaskResults(log, "build", results) } } diff --git a/garden-service/src/commands/call.ts b/garden-service/src/commands/call.ts index ed63d620521..708cc2b7b29 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 (!includes(["ready", "outdated"], status.state)) { throw new RuntimeError(`Service ${service.name} is not running`, { @@ -119,7 +119,7 @@ export class CallCommand extends Command { // TODO: support POST requests with request body const method = "get" - const entry = garden.log.info({ + const entry = log.info({ msg: chalk.cyan(`Sending ${matchedIngress.protocol.toUpperCase()} GET request to `) + url + "\n", status: "active", }) @@ -141,18 +141,18 @@ export class CallCommand extends Command { try { res = await req entry.setSuccess() - garden.log.info(chalk.green(`${res.status} ${res.statusText}\n`)) + log.info(chalk.green(`${res.status} ${res.statusText}\n`)) } catch (err) { res = err.response entry.setError() const error = res ? `${res.status} ${res.statusText}` : err.message - garden.log.info(chalk.red(error + "\n")) + log.info(chalk.red(error + "\n")) return {} } const resStr = isObject(res.data) ? JSON.stringify(res.data, null, 2) : res.data - res.data && garden.log.info(chalk.white(resStr) + "\n") + res.data && log.info(chalk.white(resStr) + "\n") return { result: { diff --git a/garden-service/src/commands/create/module.ts b/garden-service/src/commands/create/module.ts index 8e3246b7ae1..73258353193 100644 --- a/garden-service/src/commands/create/module.ts +++ b/garden-service/src/commands/create/module.ts @@ -55,6 +55,7 @@ export class CreateModuleCommand extends Command { name = "module" alias = "m" help = "Creates a new Garden module." + header = { emoji: "house_with_garden", command: "create" } description = dedent` Creates a new Garden module of the given type @@ -71,7 +72,7 @@ export class CreateModuleCommand extends Command { arguments = createModuleArguments options = createModuleOptions - async action({ garden, args, opts }: CommandParams): Promise { + async action({ garden, args, opts, log }: CommandParams): Promise { let errors: GardenBaseError[] = [] const moduleRoot = join(garden.projectRoot, (args["module-dir"] || "").trim()) @@ -83,8 +84,7 @@ export class CreateModuleCommand extends Command { await ensureDir(moduleRoot) - garden.log.header({ emoji: "house_with_garden", command: "create" }) - garden.log.info(`Initializing new module ${moduleName}`) + log.info(`Initializing new module ${moduleName}`) let type: ModuleType @@ -96,10 +96,10 @@ export class CreateModuleCommand extends Command { } } else { // Prompt for type - garden.log.info("---------") - garden.log.stop() + log.info("---------") + log.stop() type = (await prompts.addConfigForModule(moduleName)).type - garden.log.info("---------") + log.info("---------") if (!type) { return { result: {} } } @@ -107,7 +107,7 @@ export class CreateModuleCommand extends Command { const module = prepareNewModuleConfig(moduleName, type, moduleRoot) try { - await dumpConfig(module, moduleSchema, garden.log) + await dumpConfig(module, moduleSchema, log) } catch (err) { errors.push(err) } diff --git a/garden-service/src/commands/create/project.ts b/garden-service/src/commands/create/project.ts index 8a514714529..6c3e03cda95 100644 --- a/garden-service/src/commands/create/project.ts +++ b/garden-service/src/commands/create/project.ts @@ -86,7 +86,7 @@ export class CreateProjectCommand extends Command { arguments = createProjectArguments options = createProjectOptions - async action({ garden, args, opts }: CommandParams): Promise { + async action({ garden, args, opts, log }: CommandParams): Promise { let moduleConfigs: ModuleConfigOpts[] = [] let errors: GardenBaseError[] = [] @@ -100,11 +100,10 @@ export class CreateProjectCommand extends Command { await ensureDir(projectRoot) - garden.log.header({ emoji: "house_with_garden", command: "create" }) - garden.log.info(`Initializing new Garden project ${projectName}`) - garden.log.info("---------") + log.info(`Initializing new Garden project ${projectName}`) + log.info("---------") // Stop logger while prompting - garden.log.stop() + log.stop() if (moduleParentDirs.length > 0) { // If module-dirs option provided we scan for modules in the parent dir(s) and add them one by one @@ -127,13 +126,13 @@ export class CreateProjectCommand extends Command { .map(({ name, type }) => prepareNewModuleConfig(name, type, join(projectRoot, name))) } - garden.log.info("---------") - const taskLog = garden.log.info({ msg: "Setting up project", status: "active" }) + log.info("---------") + const taskLog = log.info({ msg: "Setting up project", status: "active" }) for (const module of moduleConfigs) { await ensureDir(module.path) try { - await dumpConfig(module, moduleSchema, garden.log) + await dumpConfig(module, moduleSchema, log) } catch (err) { errors.push(err) } @@ -146,7 +145,7 @@ export class CreateProjectCommand extends Command { } try { - await dumpConfig(projectConfig, projectSchema, garden.log) + await dumpConfig(projectConfig, projectSchema, log) } catch (err) { errors.push(err) } @@ -158,7 +157,7 @@ export class CreateProjectCommand extends Command { } const docs = terminalLink("docs", "https://docs.garden.io") - garden.log.info(`Project created! Be sure to check out our ${docs} for how to get sarted!`) + log.info(`Project created! Be sure to check out our ${docs} for how to get sarted!`) return { result: { diff --git a/garden-service/src/commands/delete.ts b/garden-service/src/commands/delete.ts index c9d367b381e..a22401d418e 100644 --- a/garden-service/src/commands/delete.ts +++ b/garden-service/src/commands/delete.ts @@ -21,6 +21,7 @@ import { import { NotFoundError } from "../exceptions" import dedent = require("dedent") import { ServiceStatus } from "../types/service" +import { logHeader } from "../logger/util" export class DeleteCommand extends Command { name = "delete" @@ -64,12 +65,14 @@ 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}`) + log.info(`Deleted config key ${args.key}`) } else { throw new NotFoundError(`Could not find config key ${args.key}`, { key }) } @@ -91,13 +94,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` }) + logHeader({ log, emoji: "skull_and_crossbones", command: `Deleting ${name} environment` }) - const result = await garden.actions.cleanupEnvironment({}) - - garden.log.finish() + const result = await garden.actions.cleanupEnvironment({ log }) return { result } } @@ -126,23 +127,22 @@ 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) { - garden.log.warn({ msg: "No services found. Aborting." }) + log.warn({ msg: "No services found. Aborting." }) return { result: {} } } - garden.log.header({ emoji: "skull_and_crossbones", command: `Delete service` }) + logHeader({ log, emoji: "skull_and_crossbones", command: `Delete service` }) 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() return { result } } } diff --git a/garden-service/src/commands/deploy.ts b/garden-service/src/commands/deploy.ts index 68a065bbfc2..ee10b7e8226 100644 --- a/garden-service/src/commands/deploy.ts +++ b/garden-service/src/commands/deploy.ts @@ -20,6 +20,7 @@ import { getDeployTasks, getTasksForHotReload, getHotReloadModuleNames } from ". import { TaskResults } from "../task-graph" import { processServices } from "../process" import { getNames } from "../util/util" +import { logHeader } from "../logger/util" const deployArgs = { service: new StringsParameter({ @@ -67,12 +68,12 @@ 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) if (services.length === 0) { - garden.log.error({ msg: "No services found. Aborting." }) + log.error({ msg: "No services found. Aborting." }) return { result: {} } } @@ -81,7 +82,7 @@ export class DeployCommand extends Command { const hotReloadModuleNames = await getHotReloadModuleNames(garden, hotReloadServiceNames) if (opts["hot-reload"]) { - if (!validateHotReloadOpt(garden, hotReloadServiceNames)) { + if (!validateHotReloadOpt(garden, log, hotReloadServiceNames)) { return { result: {} } } watch = true @@ -89,17 +90,19 @@ export class DeployCommand extends Command { watch = opts.watch } - garden.log.header({ emoji: "rocket", command: "Deploy" }) + logHeader({ log, emoji: "rocket", command: "Deploy" }) // TODO: make this a task - await garden.actions.prepareEnvironment({}) + await garden.actions.prepareEnvironment({ log }) const results = await processServices({ garden, + log, services, watch, handler: async (module) => getDeployTasks({ garden, + log, module, serviceNames, watch, @@ -109,16 +112,16 @@ export class DeployCommand extends Command { }), changeHandler: async (module) => { if (hotReloadModuleNames.has(module.name)) { - await hotReloadAndLog(garden, module) - return getTasksForHotReload({ garden, module, hotReloadServiceNames, serviceNames }) + await hotReloadAndLog(garden, log, module) + return getTasksForHotReload({ garden, log, module, hotReloadServiceNames, serviceNames }) } else { return getDeployTasks({ - garden, module, serviceNames, hotReloadServiceNames, force: true, forceBuild: true, watch: true, + garden, log, module, serviceNames, hotReloadServiceNames, force: true, forceBuild: true, watch: true, }) } }, }) - return handleTaskResults(garden, "deploy", results) + return handleTaskResults(log, "deploy", results) } } diff --git a/garden-service/src/commands/dev.ts b/garden-service/src/commands/dev.ts index 43b5b140dcf..275f7cbb200 100644 --- a/garden-service/src/commands/dev.ts +++ b/garden-service/src/commands/dev.ts @@ -63,28 +63,28 @@ export class DevCommand extends Command { options = devOpts - async action({ garden, opts }: CommandParams): Promise { + async action({ garden, log, opts }: 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`)) + 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() if (modules.length === 0) { - garden.log.info({ msg: "No modules found in project." }) - garden.log.info({ msg: "Aborting..." }) + log.info({ msg: "No modules found in project." }) + log.info({ msg: "Aborting..." }) return {} } const hotReloadServiceNames = opts["hot-reload"] || [] const hotReloadModuleNames = await getHotReloadModuleNames(garden, hotReloadServiceNames) - if (opts["hot-reload"] && !validateHotReloadOpt(garden, hotReloadServiceNames)) { + if (opts["hot-reload"] && !validateHotReloadOpt(garden, log, hotReloadServiceNames)) { return {} } @@ -97,7 +97,7 @@ export class DevCommand extends Command { const hotReload = hotReloadModuleNames.has(module.name) if (watch && hotReload) { - await hotReloadAndLog(garden, module) + await hotReloadAndLog(garden, log, module) } const testModules: Module[] = watch @@ -105,14 +105,21 @@ 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 }))) let tasks if (watch && hotReload) { - tasks = testTasks.concat(await getTasksForHotReload({ garden, module, hotReloadServiceNames, serviceNames })) + tasks = testTasks.concat(await getTasksForHotReload({ + garden, + log, + module, + hotReloadServiceNames, + serviceNames, + })) } else { tasks = testTasks.concat(await getDeployTasks({ garden, + log, module, watch, serviceNames, @@ -124,7 +131,7 @@ export class DevCommand extends Command { } if (tasks.length === 0) { - return [new BuildTask({ garden, module, force: watch })] + return [new BuildTask({ garden, log, module, force: watch })] } else { return tasks } @@ -134,6 +141,7 @@ export class DevCommand extends Command { await processModules({ garden, + log, modules, watch: true, handler: tasksForModule(false), diff --git a/garden-service/src/commands/exec.ts b/garden-service/src/commands/exec.ts index 801be5e1193..9f2a198af49 100644 --- a/garden-service/src/commands/exec.ts +++ b/garden-service/src/commands/exec.ts @@ -9,6 +9,7 @@ import chalk from "chalk" import { LoggerType } from "../logger/logger" import { ExecInServiceResult } from "../types/plugin/outputs" +import { logHeader } from "../logger/util" import { Command, CommandResult, @@ -58,17 +59,18 @@ 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 || [] - garden.log.header({ + logHeader({ + log, emoji: "runner", command: `Running command ${chalk.cyan(command.join(" "))} in service ${chalk.cyan(serviceName)}`, }) const service = await garden.getService(serviceName) - const result = await garden.actions.execInService({ service, command, interactive: true }) + const result = await garden.actions.execInService({ log, service, command, interactive: true }) return { result } } diff --git a/garden-service/src/commands/get.ts b/garden-service/src/commands/get.ts index c888952a2cd..cd176d1d692 100644 --- a/garden-service/src/commands/get.ts +++ b/garden-service/src/commands/get.ts @@ -60,15 +60,19 @@ export class GetSecretCommand extends Command { arguments = getSecretArgs - async action({ garden, args }: CommandParams): Promise { + async action({ garden, log, 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, + }) if (value === null || value === undefined) { throw new NotFoundError(`Could not find config key ${key}`, { key }) } - garden.log.info(value) + log.info(value) return { [key]: value } } @@ -78,12 +82,12 @@ export class GetStatusCommand extends Command { name = "status" help = "Outputs the status of your environment." - async action({ garden }: CommandParams): Promise> { - const status = await garden.actions.getStatus() + async action({ garden, log }: CommandParams): Promise> { + const status = await garden.actions.getStatus({ log }) 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 - garden.log.info(highlightYaml(yamlStatus)) + log.info(highlightYaml(yamlStatus)) return { result: status } } diff --git a/garden-service/src/commands/helpers.ts b/garden-service/src/commands/helpers.ts index 2ca3b8e7e7b..c0d269abdc2 100644 --- a/garden-service/src/commands/helpers.ts +++ b/garden-service/src/commands/helpers.ts @@ -12,9 +12,12 @@ import { uniq, flatten } from "lodash" import { Garden } from "../garden" import { Module } from "../types/module" import { prepareRuntimeContext, Service } from "../types/service" +import { LogEntry } from "../logger/log-entry" // Returns true if validation succeeded, false otherwise. -export async function validateHotReloadOpt(garden: Garden, hotReloadServiceNames: string[]): Promise { +export async function validateHotReloadOpt( + garden: Garden, log: LogEntry, hotReloadServiceNames: string[], +): Promise { const incompatibleServices: Service[] = [] for (const hotReloadService of await garden.getServices(hotReloadServiceNames)) { @@ -39,32 +42,33 @@ export async function validateHotReloadOpt(garden: Garden, hotReloadServiceNames Aborting. ` - garden.log.error({ msg: errMsg }) + log.error({ msg: errMsg }) return false } } -export async function hotReloadAndLog(garden: Garden, module: Module) { - - const logEntry = garden.log.info({ +export async function hotReloadAndLog(garden: Garden, log: LogEntry, module: Module) { + log.info({ section: module.name, msg: "Hot reloading", status: "active", }) const serviceDependencyNames = uniq(flatten(module.services.map(s => s.config.dependencies))) - const runtimeContext = await prepareRuntimeContext(garden, module, await garden.getServices(serviceDependencyNames)) + const runtimeContext = await prepareRuntimeContext( + garden, log, module, await garden.getServices(serviceDependencyNames), + ) try { - await garden.actions.hotReload({ module, runtimeContext }) + await garden.actions.hotReload({ log, module, runtimeContext }) } catch (err) { - logEntry.setError() + log.setError() throw err } - const msec = logEntry.getDuration(5) * 1000 - logEntry.setSuccess({ + const msec = log.getDuration(5) * 1000 + log.setSuccess({ msg: chalk.green(`Done (took ${msec} ms)`), append: true, }) diff --git a/garden-service/src/commands/init.ts b/garden-service/src/commands/init.ts index c93a0730fe4..46e2c5dedad 100644 --- a/garden-service/src/commands/init.ts +++ b/garden-service/src/commands/init.ts @@ -12,6 +12,7 @@ import { CommandResult, CommandParams, } from "./base" +import { logHeader } from "../logger/util" import dedent = require("dedent") const initOpts = { @@ -36,14 +37,14 @@ 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` }) + logHeader({ log, 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!` }) + log.info("") + logHeader({ log, emoji: "heavy_check_mark", command: `Done!` }) return { result: {} } } diff --git a/garden-service/src/commands/link/module.ts b/garden-service/src/commands/link/module.ts index a576c3d113e..6b6b64a4299 100644 --- a/garden-service/src/commands/link/module.ts +++ b/garden-service/src/commands/link/module.ts @@ -18,9 +18,8 @@ import { PathParameter, CommandParams, } from "../base" -import { - LinkedSource, -} from "../../config-store" +import { LinkedSource } from "../../config-store" +import { logHeader } from "../../logger/util" import { addLinkedSources, hasRemoteSource, @@ -54,8 +53,8 @@ export class LinkModuleCommand extends Command { garden link module my-module path/to/my-module # links my-module to its local version at the given path ` - async action({ garden, args }: CommandParams): Promise> { - garden.log.header({ emoji: "link", command: "link module" }) + async action({ garden, log, args }: CommandParams): Promise> { + logHeader({ log, emoji: "link", command: "link module" }) const sourceType = "module" @@ -83,7 +82,7 @@ export class LinkModuleCommand extends Command { sources: [{ name: moduleName, path: absPath }], }) - garden.log.info(`Linked module ${moduleName}`) + log.info(`Linked module ${moduleName}`) return { result: linkedModuleSources } diff --git a/garden-service/src/commands/link/source.ts b/garden-service/src/commands/link/source.ts index da31980f0de..0efefa34e3e 100644 --- a/garden-service/src/commands/link/source.ts +++ b/garden-service/src/commands/link/source.ts @@ -20,6 +20,7 @@ import { import { addLinkedSources } from "../../util/ext-source-util" import { LinkedSource } from "../../config-store" import { CommandParams } from "../base" +import { logHeader } from "../../logger/util" const linkSourceArguments = { source: new StringParameter({ @@ -49,8 +50,8 @@ export class LinkSourceCommand extends Command { garden link source my-source path/to/my-source # links my-source to its local version at the given path ` - async action({ garden, args }: CommandParams): Promise> { - garden.log.header({ emoji: "link", command: "link source" }) + async action({ garden, log, args }: CommandParams): Promise> { + logHeader({ log, emoji: "link", command: "link source" }) const sourceType = "project" @@ -78,7 +79,7 @@ export class LinkSourceCommand extends Command { sources: [{ name: sourceName, path: absPath }], }) - garden.log.info(`Linked source ${sourceName}`) + log.info(`Linked source ${sourceName}`) return { result: linkedProjectSources } } diff --git a/garden-service/src/commands/logs.ts b/garden-service/src/commands/logs.ts index 1b38758cff9..26cdeb465ab 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) @@ -74,7 +74,7 @@ export class LogsCommand extends Command { } catch { } } - garden.log.info({ + log.info({ section: entry.serviceName, msg: [timestamp, chalk.white(entry.msg)], }) @@ -85,9 +85,9 @@ export class LogsCommand extends Command { }) await Bluebird.map(services, async (service: Service) => { - const status = await garden.actions.getServiceStatus({ service }) + const status = await garden.actions.getServiceStatus({ log, service }) if (status.state === "ready" || status.state === "outdated") { - await garden.actions.getServiceLogs({ service, stream, tail }) + await garden.actions.getServiceLogs({ log, service, stream, tail }) } else { await stream.write({ serviceName: service.name, diff --git a/garden-service/src/commands/publish.ts b/garden-service/src/commands/publish.ts index d3e6ed56571..e3ff6664e1e 100644 --- a/garden-service/src/commands/publish.ts +++ b/garden-service/src/commands/publish.ts @@ -19,6 +19,8 @@ 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 { logHeader } from "../logger/util" import dedent = require("dedent") const publishArgs = { @@ -59,19 +61,20 @@ export class PublishCommand extends Command { arguments = publishArgs options = publishOpts - async action({ garden, args, opts }: CommandParams): Promise> { - garden.log.header({ emoji: "rocket", command: "Publish modules" }) + async action({ garden, log, args, opts }: CommandParams): Promise> { + logHeader({ log, 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 }) + return handleTaskResults(log, "publish", { taskResults: results }) } } export async function publishModules( garden: Garden, + log: LogEntry, modules: Module[], forceBuild: boolean, allowDirty: boolean, @@ -87,7 +90,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 ddb761d5011..fb8c6364373 100644 --- a/garden-service/src/commands/run/module.ts +++ b/garden-service/src/commands/run/module.ts @@ -24,6 +24,7 @@ import { import { printRuntimeContext } from "./run" import dedent = require("dedent") import { prepareRuntimeContext } from "../../types/service" +import { logHeader } from "../../logger/util" const runArgs = { module: new StringParameter({ @@ -67,7 +68,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) @@ -75,14 +76,15 @@ export class RunModuleCommand extends Command { ? `Running command ${chalk.white(args.command.join(" "))} in module ${chalk.white(moduleName)}` : `Running module ${chalk.white(moduleName)}` - garden.log.header({ + logHeader({ + log, emoji: "runner", 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() @@ -92,13 +94,14 @@ export class RunModuleCommand extends Command { const depNames = uniq(flatten(module.serviceConfigs.map(s => s.dependencies))) const deps = await garden.getServices(depNames) - const runtimeContext = await prepareRuntimeContext(garden, module, deps) + const runtimeContext = await prepareRuntimeContext(garden, log, module, deps) - printRuntimeContext(garden, runtimeContext) + printRuntimeContext(log, runtimeContext) - garden.log.info("") + log.info("") const result = await garden.actions.runModule({ + log, module, command, runtimeContext, diff --git a/garden-service/src/commands/run/run.ts b/garden-service/src/commands/run/run.ts index 506b474c7dc..2adc626ea50 100644 --- a/garden-service/src/commands/run/run.ts +++ b/garden-service/src/commands/run/run.ts @@ -13,7 +13,7 @@ import { Command } from "../base" import { RunModuleCommand } from "./module" import { RunServiceCommand } from "./service" import { RunTestCommand } from "./test" -import { Garden } from "../../garden" +import { LogEntry } from "../../logger/log-entry" export class RunCommand extends Command { name = "run" @@ -29,11 +29,11 @@ export class RunCommand extends Command { async action() { return {} } } -export function printRuntimeContext(garden: Garden, runtimeContext: RuntimeContext) { - garden.log.verbose("-----------------------------------\n") - garden.log.verbose("Environment variables:") - garden.log.verbose(highlightYaml(safeDump(runtimeContext.envVars))) - garden.log.verbose("Dependencies:") - garden.log.verbose(highlightYaml(safeDump(runtimeContext.dependencies))) - garden.log.verbose("-----------------------------------\n") +export function printRuntimeContext(log: LogEntry, runtimeContext: RuntimeContext) { + log.verbose("-----------------------------------\n") + log.verbose("Environment variables:") + log.verbose(highlightYaml(safeDump(runtimeContext.envVars))) + log.verbose("Dependencies:") + log.verbose(highlightYaml(safeDump(runtimeContext.dependencies))) + log.verbose("-----------------------------------\n") } diff --git a/garden-service/src/commands/run/service.ts b/garden-service/src/commands/run/service.ts index 8612752a147..69983751719 100644 --- a/garden-service/src/commands/run/service.ts +++ b/garden-service/src/commands/run/service.ts @@ -19,6 +19,7 @@ import { import { printRuntimeContext } from "./run" import dedent = require("dedent") import { prepareRuntimeContext } from "../../types/service" +import { logHeader } from "../../logger/util" const runArgs = { service: new StringParameter({ @@ -50,28 +51,34 @@ 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 - garden.log.header({ + logHeader({ + log, emoji: "runner", 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() const dependencies = await garden.getServices(module.serviceDependencyNames) - const runtimeContext = await prepareRuntimeContext(garden, module, dependencies) + const runtimeContext = await prepareRuntimeContext(garden, log, module, dependencies) - printRuntimeContext(garden, runtimeContext) + printRuntimeContext(log, runtimeContext) - const result = await garden.actions.runService({ service, runtimeContext, interactive: true }) + const result = await garden.actions.runService({ + log, + service, + runtimeContext, + interactive: true, + }) return { result } } diff --git a/garden-service/src/commands/run/test.ts b/garden-service/src/commands/run/test.ts index c2506c77038..f525e244f6d 100644 --- a/garden-service/src/commands/run/test.ts +++ b/garden-service/src/commands/run/test.ts @@ -24,6 +24,7 @@ import { import { printRuntimeContext } from "./run" import dedent = require("dedent") import { prepareRuntimeContext } from "../../types/service" +import { logHeader } from "../../logger/util" const runArgs = { module: new StringParameter({ @@ -64,7 +65,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) @@ -79,24 +80,26 @@ export class RunTestCommand extends Command { }) } - garden.log.header({ + logHeader({ + log, emoji: "runner", 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() const interactive = opts.interactive const deps = await garden.getServices(testConfig.dependencies) - const runtimeContext = await prepareRuntimeContext(garden, module, deps) + const runtimeContext = await prepareRuntimeContext(garden, log, module, deps) - printRuntimeContext(garden, runtimeContext) + printRuntimeContext(log, runtimeContext) const result = await garden.actions.testModule({ + log, module, interactive, runtimeContext, diff --git a/garden-service/src/commands/scan.ts b/garden-service/src/commands/scan.ts index 14f8c591bc8..91c96606e25 100644 --- a/garden-service/src/commands/scan.ts +++ b/garden-service/src/commands/scan.ts @@ -20,7 +20,7 @@ export class ScanCommand extends Command { name = "scan" help = "Scans your project and outputs an overview of all modules." - async action({ garden }: CommandParams): Promise> { + async action({ garden, log }: CommandParams): Promise> { const modules = (await garden.getModules()) .map(m => { m.services.forEach(s => delete s.module) @@ -36,7 +36,7 @@ export class ScanCommand extends Command { }), } - garden.log.info(highlightYaml(safeDump(shortOutput, { noRefs: true, skipInvalid: true, sortKeys: true }))) + log.info(highlightYaml(safeDump(shortOutput, { noRefs: true, skipInvalid: true, sortKeys: true }))) return { result: output } } diff --git a/garden-service/src/commands/set.ts b/garden-service/src/commands/set.ts index 8397f8b791a..a18183e23b3 100644 --- a/garden-service/src/commands/set.ts +++ b/garden-service/src/commands/set.ts @@ -64,10 +64,15 @@ 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 }) - garden.log.info(`Set config key ${args.key}`) + const result = await garden.actions.setSecret({ + pluginName: args.provider, + key, + value: args.value, + log, + }) + 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..ccea18b07e9 100644 --- a/garden-service/src/commands/test.ts +++ b/garden-service/src/commands/test.ts @@ -22,6 +22,7 @@ import { processModules } from "../process" import { Module } from "../types/module" import { getTestTasks } from "../tasks/test" import { computeAutoReloadDependants, withDependants } from "../watch" +import { logHeader } from "../logger/util" const testArgs = { module: new StringsParameter({ @@ -66,7 +67,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) { @@ -76,12 +77,13 @@ export class TestCommand extends Command { modules = await garden.getModules() } - garden.log.header({ + logHeader({ + log, emoji: "thermometer", command: `Running tests`, }) - await garden.actions.prepareEnvironment({}) + await garden.actions.prepareEnvironment({ log }) const name = opts.name const force = opts.force @@ -89,17 +91,18 @@ export class TestCommand extends Command { const results = await processModules({ garden, + log, 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 }))) }, }) - return handleTaskResults(garden, "test", results) + return handleTaskResults(log, "test", results) } } diff --git a/garden-service/src/commands/unlink/module.ts b/garden-service/src/commands/unlink/module.ts index 929f04b4acc..c430bfdd34d 100644 --- a/garden-service/src/commands/unlink/module.ts +++ b/garden-service/src/commands/unlink/module.ts @@ -16,6 +16,7 @@ import { CommandParams, } from "../base" import { removeLinkedSources } from "../../util/ext-source-util" +import { logHeader } from "../../logger/util" import { localConfigKeys, LinkedSource, @@ -53,8 +54,8 @@ export class UnlinkModuleCommand extends Command { garden unlink module --all # unlink all modules ` - async action({ garden, args, opts }: CommandParams): Promise> { - garden.log.header({ emoji: "chains", command: "unlink module" }) + async action({ garden, log, args, opts }: CommandParams): Promise> { + logHeader({ log, emoji: "chains", command: "unlink module" }) const sourceType = "module" @@ -62,13 +63,13 @@ export class UnlinkModuleCommand extends Command { if (opts.all) { await garden.localConfigStore.set([localConfigKeys.linkedModuleSources], []) - garden.log.info("Unlinked all modules") + log.info("Unlinked all modules") return { result: [] } } const linkedModuleSources = await removeLinkedSources({ garden, sourceType, names: module }) - garden.log.info(`Unlinked module(s) ${module}`) + log.info(`Unlinked module(s) ${module}`) return { result: linkedModuleSources } } diff --git a/garden-service/src/commands/unlink/source.ts b/garden-service/src/commands/unlink/source.ts index 8b68bf434d7..6c28a21c129 100644 --- a/garden-service/src/commands/unlink/source.ts +++ b/garden-service/src/commands/unlink/source.ts @@ -16,6 +16,7 @@ import { CommandParams, } from "../base" import { removeLinkedSources } from "../../util/ext-source-util" +import { logHeader } from "../../logger/util" import { localConfigKeys, LinkedSource, @@ -53,8 +54,8 @@ export class UnlinkSourceCommand extends Command { garden unlink source --all # unlinks all sources ` - async action({ garden, args, opts }: CommandParams): Promise> { - garden.log.header({ emoji: "chains", command: "unlink source" }) + async action({ garden, log, args, opts }: CommandParams): Promise> { + logHeader({ log, emoji: "chains", command: "unlink source" }) const sourceType = "project" @@ -62,13 +63,13 @@ export class UnlinkSourceCommand extends Command { if (opts.all) { await garden.localConfigStore.set([localConfigKeys.linkedProjectSources], []) - garden.log.info("Unlinked all sources") + log.info("Unlinked all sources") return { result: [] } } const linkedProjectSources = await removeLinkedSources({ garden, sourceType, names: source }) - garden.log.info(`Unlinked source(s) ${source}`) + log.info(`Unlinked source(s) ${source}`) return { result: linkedProjectSources } } diff --git a/garden-service/src/commands/update-remote/all.ts b/garden-service/src/commands/update-remote/all.ts index 90ced17490d..acded199971 100644 --- a/garden-service/src/commands/update-remote/all.ts +++ b/garden-service/src/commands/update-remote/all.ts @@ -16,6 +16,7 @@ import { import { UpdateRemoteSourcesCommand } from "./sources" import { UpdateRemoteModulesCommand } from "./modules" import { SourceConfig } from "../../config/project" +import { logHeader } from "../../logger/util" export interface UpdateRemoteAllResult { projectSources: SourceConfig[], @@ -32,15 +33,24 @@ export class UpdateRemoteAllCommand extends Command { garden update-remote all # update all remote sources and modules in the project ` - async action({ garden }: CommandParams): Promise> { - - garden.log.header({ emoji: "hammer_and_wrench", command: "update-remote all" }) + async action({ garden, log }: CommandParams): Promise> { + logHeader({ log, 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..50e29d03e9a 100644 --- a/garden-service/src/commands/update-remote/modules.ts +++ b/garden-service/src/commands/update-remote/modules.ts @@ -20,6 +20,7 @@ import { SourceConfig } from "../../config/project" import { ParameterError } from "../../exceptions" import { pruneRemoteSources } from "./helpers" import { hasRemoteSource } from "../../util/ext-source-util" +import { logHeader } from "../../logger/util" const updateRemoteModulesArguments = { module: new StringsParameter({ @@ -44,10 +45,8 @@ export class UpdateRemoteModulesCommand extends Command { garden update-remote modules my-module # update remote module my-module ` - async action( - { garden, args }: CommandParams, - ): Promise> { - garden.log.header({ emoji: "hammer_and_wrench", command: "update-remote modules" }) + async action({ garden, log, args }: CommandParams): Promise> { + logHeader({ log, emoji: "hammer_and_wrench", command: "update-remote modules" }) const { module } = args const modules = await garden.getModules(module) @@ -74,7 +73,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 }) } 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..8b1c79cad0d 100644 --- a/garden-service/src/commands/update-remote/sources.ts +++ b/garden-service/src/commands/update-remote/sources.ts @@ -19,6 +19,7 @@ import { import { ParameterError } from "../../exceptions" import { pruneRemoteSources } from "./helpers" import { SourceConfig } from "../../config/project" +import { logHeader } from "../../logger/util" const updateRemoteSourcesArguments = { source: new StringsParameter({ @@ -43,9 +44,9 @@ export class UpdateRemoteSourcesCommand extends Command { ` async action( - { garden, args }: CommandParams, + { garden, log, args }: CommandParams, ): Promise> { - garden.log.header({ emoji: "hammer_and_wrench", command: "update-remote sources" }) + logHeader({ log, emoji: "hammer_and_wrench", command: "update-remote sources" }) const { source } = args @@ -69,7 +70,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 }) } await pruneRemoteSources({ projectRoot: garden.projectRoot, type: "project", sources: projectSources }) diff --git a/garden-service/src/commands/validate.ts b/garden-service/src/commands/validate.ts index 2594bf312ba..91a4c48787c 100644 --- a/garden-service/src/commands/validate.ts +++ b/garden-service/src/commands/validate.ts @@ -11,6 +11,7 @@ import { CommandParams, CommandResult, } from "./base" +import { logHeader } from "../logger/util" import dedent = require("dedent") export class ValidateCommand extends Command { @@ -21,8 +22,8 @@ export class ValidateCommand extends Command { Throws an error and exits with code 1 if something's not right in your garden.yml files. ` - async action({ garden }: CommandParams): Promise { - garden.log.header({ emoji: "heavy_check_mark", command: "validate" }) + async action({ garden, log }: CommandParams): Promise { + logHeader({ log, emoji: "heavy_check_mark", command: "validate" }) await garden.getModules() diff --git a/garden-service/src/config/config-context.ts b/garden-service/src/config/config-context.ts index b4bef78de27..d29d1407883 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[] @@ -280,6 +281,7 @@ export class ModuleConfigContext extends ProjectConfigContext { constructor( garden: Garden, + log: LogEntry, environment: Environment, moduleConfigs: ModuleConfig[], ) { @@ -303,7 +305,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 d86d4ad441b..94d7e7b659d 100644 --- a/garden-service/src/garden.ts +++ b/garden-service/src/garden.ts @@ -193,7 +193,7 @@ export class Garden { this.actionHandlers = fromPairs(pluginActionNames.map(n => [n, {}])) this.moduleActionHandlers = fromPairs(moduleActionNames.map(n => [n, {}])) - this.taskGraph = new TaskGraph(this) + this.taskGraph = new TaskGraph(this.log.info()) this.actions = new ActionHelper(this) this.hotReloadScheduler = new HotReloadScheduler() } @@ -417,7 +417,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}`, { @@ -706,7 +706,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) }) @@ -834,7 +834,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/log-entry.ts b/garden-service/src/logger/log-entry.ts index 974c012c1c0..1d89d7dcff8 100644 --- a/garden-service/src/logger/log-entry.ts +++ b/garden-service/src/logger/log-entry.ts @@ -30,7 +30,7 @@ export interface UpdateOpts { showDuration?: boolean error?: GardenError status?: EntryStatus - indentationLevel?: number + indent?: number } export interface CreateOpts extends UpdateOpts { @@ -103,12 +103,12 @@ export class LogEntry extends LogNode { createNode(level: LogLevel, parent: LogNode, param?: CreateParam) { // Empty entries inherit their parent's indentation level - let { indentationLevel } = this.opts + let indent = this.opts.indent || 0 if (param) { - indentationLevel = (indentationLevel || 0) + 1 + indent += 1 } const opts = { - indentationLevel, + indent, ...resolveParam(param), } return new LogEntry({ level, opts, parent }) diff --git a/garden-service/src/logger/logger.ts b/garden-service/src/logger/logger.ts index c013babf653..34c9c2701bf 100644 --- a/garden-service/src/logger/logger.ts +++ b/garden-service/src/logger/logger.ts @@ -9,7 +9,7 @@ import chalk from "chalk" import { RootLogNode, LogNode } from "./log-node" -import { LogEntry, CreateOpts, resolveParam, EmojiName } from "./log-entry" +import { LogEntry, CreateOpts, resolveParam } from "./log-entry" import { getChildEntries } from "./util" import { Writer } from "./writers/base" import { InternalError, ParameterError } from "../exceptions" @@ -110,18 +110,7 @@ export class Logger extends RootLogNode { return getChildEntries(this).filter(entry => entry.opts.section === section) } - header( - { command, emoji, level = LogLevel.info }: { command: string, emoji?: EmojiName, level?: LogLevel }, - ): LogEntry { - const msg = combine([ - [chalk.bold.magenta(command)], - [emoji && this.useEmoji ? " " + printEmoji(emoji) : ""], - ["\n"], - ]) - const lvlStr = LogLevel[level] - return this[lvlStr](msg) - } - + // FIXME: This isn't currently used anywhere, we should find this another place and purpose. finish( { showDuration = true, level = LogLevel.info }: { showDuration?: boolean, level?: LogLevel } = {}, ): LogEntry { diff --git a/garden-service/src/logger/renderers.ts b/garden-service/src/logger/renderers.ts index 51768896c02..0d23b55a3e6 100644 --- a/garden-service/src/logger/renderers.ts +++ b/garden-service/src/logger/renderers.ts @@ -72,7 +72,7 @@ export function printEmoji(emoji: EmojiName) { /*** RENDERERS ***/ export function leftPad(entry: LogEntry): string { - return padStart("", (entry.opts.indentationLevel || 0) * 3) + return padStart("", (entry.opts.indent || 0) * 3) } export function renderEmoji(entry: LogEntry): string { diff --git a/garden-service/src/logger/util.ts b/garden-service/src/logger/util.ts index 45fd599e249..955a3482d78 100644 --- a/garden-service/src/logger/util.ts +++ b/garden-service/src/logger/util.ts @@ -6,8 +6,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { LogNode } from "./log-node" -import { LogEntry, CreateOpts } from "./log-entry" +import { LogNode, LogLevel } from "./log-node" +import { LogEntry, CreateOpts, EmojiName } from "./log-entry" +import { combine, printEmoji } from "./renderers" +import chalk from "chalk" export interface Node { children: any[] @@ -105,3 +107,20 @@ export function getTerminalWidth(stream: NodeJS.WriteStream = process.stdout) { return columns } + +interface LogHeaderOptions { + log: LogEntry + command: string + emoji?: EmojiName + level?: LogLevel +} + +export function logHeader({ log, command, emoji, level = LogLevel.info }: LogHeaderOptions): LogEntry { + const msg = combine([ + [chalk.bold.magenta(command)], + [emoji && log.root.useEmoji ? " " + printEmoji(emoji) : ""], + ["\n"], + ]) + const lvlStr = LogLevel[level] + return log[lvlStr](msg) +} 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 977a844848f..66eef687f63 100644 --- a/garden-service/src/plugins/container.ts +++ b/garden-service/src/plugins/container.ts @@ -552,11 +552,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", @@ -566,7 +566,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 @@ -574,7 +574,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 } } @@ -582,7 +582,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 cmdOpts = ["build", "-t", identifier] const buildArgs = Object.entries(module.spec.buildArgs).map(([key, value]) => { @@ -605,16 +605,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 76775eb7912..1c266bd284f 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 c0ae3451ab8..1ed6623089f 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, buildDependencies }: DeployServiceParams, + { ctx, module, service, runtimeContext, log, buildDependencies }: 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, buildDependencies }) + return getServiceStatus({ ctx, module, service, runtimeContext, log, buildDependencies }) }, async getServiceOutputs({ ctx, service }: GetServiceOutputsParams) { diff --git a/garden-service/src/plugins/kubernetes/actions.ts b/garden-service/src/plugins/kubernetes/actions.ts index bd38f3df562..0fcf144b98a 100644 --- a/garden-service/src/plugins/kubernetes/actions.ts +++ b/garden-service/src/plugins/kubernetes/actions.ts @@ -73,12 +73,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) } @@ -134,13 +134,13 @@ export async function execInService(params: ExecInServiceParams } export async function hotReload( - { ctx, runtimeContext, module, buildDependencies }: HotReloadParams, + { ctx, log, runtimeContext, module, buildDependencies }: HotReloadParams, ): Promise { const hotReloadConfig = module.spec.hotReload! const services = module.services - if (!await waitForServices(ctx, runtimeContext, services, buildDependencies)) { + if (!await waitForServices(ctx, log, runtimeContext, services, buildDependencies)) { // Service deployment timed out, skip hot reload return {} } @@ -219,7 +219,7 @@ export async function runModule( } export async function runService( - { ctx, service, interactive, runtimeContext, timeout, logEntry, buildDependencies }: + { ctx, service, interactive, runtimeContext, timeout, log, buildDependencies }: RunServiceParams, ) { return runModule({ @@ -229,13 +229,13 @@ export async function runService( interactive, runtimeContext, timeout, - logEntry, + log, buildDependencies, }) } export async function testModule( - { ctx, interactive, module, runtimeContext, testConfig, logEntry, buildDependencies }: + { ctx, interactive, module, runtimeContext, testConfig, log, buildDependencies }: TestModuleParams, ): Promise { const testName = testConfig.name @@ -250,7 +250,7 @@ export async function testModule( interactive, runtimeContext, timeout, - logEntry, + log, buildDependencies, }) diff --git a/garden-service/src/plugins/kubernetes/deployment.ts b/garden-service/src/plugins/kubernetes/deployment.ts index b8e589d0f4d..e7564cb27cd 100644 --- a/garden-service/src/plugins/kubernetes/deployment.ts +++ b/garden-service/src/plugins/kubernetes/deployment.ts @@ -87,7 +87,7 @@ export async function getContainerServiceStatus( } export async function deployContainerService(params: DeployServiceParams): Promise { - const { ctx, service, runtimeContext, force, logEntry, hotReload } = params + const { ctx, service, runtimeContext, force, log, hotReload } = params const namespace = await getAppNamespace(ctx, ctx.provider) const enableHotReload = !!hotReload && ctx.provider.name === "local-kubernetes" @@ -97,7 +97,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 9670af6096f..45767a581a6 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, force }: DeployServiceParams, + { ctx, module, service, log, force }: DeployServiceParams, ): Promise { const provider = ctx.provider const chartPath = await getChartPath(module) @@ -144,7 +144,7 @@ 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") { const installArgs = [ @@ -157,7 +157,7 @@ export const helmHandlers: Partial> = { if (force) { installArgs.push("--replace") } - await helm(provider, logEntry, ...installArgs) + await helm(provider, log, ...installArgs) } else { const upgradeArgs = [ "upgrade", releaseName, chartPath, @@ -169,27 +169,27 @@ export const helmHandlers: Partial> = { if (force) { upgradeArgs.push("--force") } - await helm(provider, logEntry, ...upgradeArgs) + await helm(provider, log, ...upgradeArgs) } - 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.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 @@ -205,14 +205,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.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)) @@ -261,9 +261,9 @@ const helmCmd = new BinaryCmd({ }, }) -export function helm(provider: KubernetesProvider, logEntry: LogEntry | undefined, ...args: string[]) { +export function helm(provider: KubernetesProvider, log: LogEntry, ...args: string[]) { return helmCmd.stdout({ - logEntry, + log, args: [ "--kube-context", provider.config.context, ...args, @@ -281,13 +281,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, @@ -304,16 +304,16 @@ async function getChartObjects(ctx: PluginContext, service: Service, logEntry?: } async function getServiceStatus( - { ctx, service, module, logEntry, buildDependencies }: GetServiceStatusParams, + { ctx, service, module, log, buildDependencies }: GetServiceStatusParams, ): Promise { // need to build to be able to check the status - const buildStatus = await getGenericModuleBuildStatus({ ctx, module, logEntry, buildDependencies }) + const buildStatus = await getGenericModuleBuildStatus({ ctx, module, log, buildDependencies }) if (!buildStatus.ready) { - await build({ ctx, module, logEntry, buildDependencies }) + await build({ ctx, module, log, buildDependencies }) } // 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) let state = await compareDeployedObjects(ctx, objects) if (state !== "ready") { @@ -337,10 +337,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 da0a4ae3e13..8aa31ce07bd 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, logEntry }: GetEnvironmentStatusParams) { - const loggedIn = await getLoginStatus({ ctx }) +export async function getRemoteEnvironmentStatus({ ctx, log }: GetEnvironmentStatusParams) { + const loggedIn = await getLoginStatus({ ctx, log }) if (!loggedIn) { return { @@ -75,8 +75,8 @@ export async function getRemoteEnvironmentStatus({ ctx, logEntry }: GetEnvironme } } - await prepareNamespaces({ ctx }) - await helm(ctx.provider, logEntry, "init", "--client-only") + await prepareNamespaces({ ctx, log }) + await helm(ctx.provider, log, "init", "--client-only") return { ready: true, @@ -84,12 +84,12 @@ export async function getRemoteEnvironmentStatus({ ctx, logEntry }: GetEnvironme } } -export async function getLocalEnvironmentStatus({ ctx, logEntry }: GetEnvironmentStatusParams) { +export async function getLocalEnvironmentStatus({ ctx, log }: GetEnvironmentStatusParams) { let ready = true let needUserInput = false - await prepareNamespaces({ ctx }) - await helm(ctx.provider, logEntry, "init", "--client-only") + await prepareNamespaces({ ctx, log }) + await helm(ctx.provider, log, "init", "--client-only") // TODO: check if mkcert has been installed // TODO: check if all certs have been generated @@ -97,7 +97,7 @@ export async function getLocalEnvironmentStatus({ ctx, logEntry }: GetEnvironmen // 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")) @@ -113,30 +113,30 @@ export async function getLocalEnvironmentStatus({ ctx, logEntry }: GetEnvironmen } } -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", @@ -152,7 +152,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() @@ -185,8 +185,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 @@ -253,8 +253,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 || {} @@ -267,15 +267,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", @@ -283,19 +283,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 { let ready const startTime = new Date().getTime() @@ -406,7 +406,7 @@ export async function waitForServices( ready = (await Bluebird.map(services, async (service) => { const state = (await getContainerServiceStatus({ - ctx, buildDependencies, service, runtimeContext, module: service.module, + ctx, log, buildDependencies, service, runtimeContext, module: service.module, })).state return state === "ready" || state === "outdated" })).every(serviceReady => serviceReady) diff --git a/garden-service/src/plugins/local/local-docker-swarm.ts b/garden-service/src/plugins/local/local-docker-swarm.ts index 05f24fe96d7..6307921457a 100644 --- a/garden-service/src/plugins/local/local-docker-swarm.ts +++ b/garden-service/src/plugins/local/local-docker-swarm.ts @@ -45,12 +45,12 @@ export const gardenPlugin = (): GardenPlugin => ({ getServiceStatus, async deployService( - { ctx, module, service, runtimeContext, logEntry, buildDependencies }: DeployServiceParams, + { ctx, module, service, runtimeContext, log, buildDependencies }: 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 => { @@ -121,7 +121,7 @@ export const gardenPlugin = (): GardenPlugin => ({ service, module, runtimeContext, - logEntry, + log, buildDependencies, }) let swarmServiceStatus @@ -131,14 +131,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`, }) @@ -174,12 +174,12 @@ export const gardenPlugin = (): GardenPlugin => ({ } } - logEntry && logEntry.info({ + log.info({ section: service.name, msg: `Ready`, }) - return getServiceStatus({ ctx, module, service, runtimeContext, logEntry, buildDependencies }) + return getServiceStatus({ ctx, module, service, runtimeContext, log, buildDependencies }) }, async getServiceOutputs({ ctx, service }: GetServiceOutputsParams) { @@ -189,14 +189,14 @@ export const gardenPlugin = (): GardenPlugin => ({ }, async execInService( - { ctx, service, command, runtimeContext, logEntry, buildDependencies }: ExecInServiceParams, + { ctx, service, command, runtimeContext, log, buildDependencies }: ExecInServiceParams, ) { const status = await getServiceStatus({ ctx, service, module: service.module, runtimeContext, - logEntry, + log, buildDependencies, }) diff --git a/garden-service/src/plugins/openfaas/openfaas.ts b/garden-service/src/plugins/openfaas/openfaas.ts index b46293ce091..2d5bda90f42 100644 --- a/garden-service/src/plugins/openfaas/openfaas.ts +++ b/garden-service/src/plugins/openfaas/openfaas.ts @@ -109,9 +109,9 @@ export function gardenPlugin({ config }: { config: OpenFaasConfig }): GardenPlug return { modules: [join(STATIC_DIR, "openfaas", "templates")], 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")) @@ -121,13 +121,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({ force }) + const results = await ofGarden.actions.deployServices({ log, force }) const failed = values(results.taskResults).filter(r => !!r.error).length if (failed) { @@ -139,9 +139,9 @@ export function gardenPlugin({ config }: { config: OpenFaasConfig }): GardenPlug return {} }, - async cleanupEnvironment({ ctx }: CleanupEnvironmentParams) { + async cleanupEnvironment({ ctx, log }: CleanupEnvironmentParams) { const ofGarden = await getOpenFaasGarden(ctx) - await ofGarden.actions.cleanupEnvironment({}) + await ofGarden.actions.cleanupEnvironment({ log }) return {} }, }, @@ -186,10 +186,11 @@ export function gardenPlugin({ config }: { config: OpenFaasConfig }): GardenPlug getBuildStatus: getGenericModuleBuildStatus, - async build({ ctx, module }: BuildModuleParams) { + async build({ ctx, log, module }: BuildModuleParams) { await writeStackFile(ctx, module, {}) const buildLog = await faasCli.stdout({ + log, cwd: module.buildPath, args: ["build", "-f", stackFilename], }) @@ -209,13 +210,14 @@ 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) // use faas-cli to do the deployment await faasCli.stdout({ + log, cwd: module.buildPath, args: ["deploy", "-f", stackFilename], }) @@ -227,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, buildDependencies } = params + const { ctx, log, service, runtimeContext, buildDependencies } = params let status let found = true try { status = await getServiceStatus({ ctx, + log, service, runtimeContext, buildDependencies, @@ -250,6 +253,7 @@ export function gardenPlugin({ config }: { config: OpenFaasConfig }): GardenPlug found = !!status.state await faasCli.stdout({ + log, cwd: service.module.buildPath, args: ["remove", "-f", stackFilename], }) @@ -258,8 +262,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/process.ts b/garden-service/src/process.ts index 1bd52adf48f..7a6e3680d45 100644 --- a/garden-service/src/process.ts +++ b/garden-service/src/process.ts @@ -16,11 +16,13 @@ import { FSWatcher } from "./watch" import { registerCleanupFunction } from "./util/util" import { isModuleLinked } from "./util/ext-source-util" import { Garden } from "./garden" +import { LogEntry } from "./logger/log-entry" export type ProcessHandler = (module: Module) => Promise interface ProcessParams { - garden: Garden, + garden: Garden + log: LogEntry watch: boolean handler: ProcessHandler // use this if the behavior should be different on watcher changes than on initial processing @@ -41,7 +43,7 @@ export interface ProcessResults { } export async function processServices( - { garden, services, watch, handler, changeHandler }: ProcessServicesParams, + { garden, log, services, watch, handler, changeHandler }: ProcessServicesParams, ): Promise { const modules = Array.from(new Set(services.map(s => s.module))) @@ -49,6 +51,7 @@ export async function processServices( return processModules({ modules, garden, + log, watch, handler, changeHandler, @@ -56,12 +59,12 @@ export async function processServices( } export async function processModules( - { garden, modules, watch, handler, changeHandler }: ProcessModulesParams, + { garden, log, modules, watch, handler, changeHandler }: ProcessModulesParams, ): Promise { for (const module of modules) { const tasks = await handler(module) if (isModuleLinked(module, garden)) { - garden.log.info( + log.info( chalk.gray(`Reading module ${chalk.cyan(module.name)} from linked local path ${chalk.white(module.path)}`), ) } @@ -87,13 +90,13 @@ export async function processModules( await watcher.watchModules(modules, async (changedModule: Module | null, configChanged: boolean) => { if (configChanged) { - garden.log.debug({ msg: `Config changed, reloading.` }) + log.debug({ msg: `Config changed, reloading.` }) resolve() return } if (changedModule) { - garden.log.debug({ msg: `Files changed for module ${changedModule.name}` }) + log.debug({ msg: `Files changed for module ${changedModule.name}` }) await Bluebird.map(changeHandler!(changedModule), (task) => garden.addTask(task)) } diff --git a/garden-service/src/task-graph.ts b/garden-service/src/task-graph.ts index a272033985c..38753e1597a 100644 --- a/garden-service/src/task-graph.ts +++ b/garden-service/src/task-graph.ts @@ -14,7 +14,6 @@ import { Task, TaskDefinitionError } from "./tasks/base" import { LogEntry } from "./logger/log-entry" import { toGardenError } from "./exceptions" -import { Garden } from "./garden" class TaskGraphError extends Error { } @@ -46,7 +45,7 @@ export class TaskGraph { private resultCache: ResultCache private opQueue: PQueue - constructor(private garden: Garden, private concurrency: number = DEFAULT_CONCURRENCY) { + constructor(private log: LogEntry, private concurrency: number = DEFAULT_CONCURRENCY) { this.roots = new TaskNodeMap() this.index = new TaskNodeMap() this.inProgress = new TaskNodeMap() @@ -251,7 +250,7 @@ export class TaskGraph { // Logging private logTask(node: TaskNode) { - const entry = this.garden.log.debug({ + const entry = this.log.debug({ section: "tasks", msg: `Processing task ${taskStyle(node.getKey())}`, status: "active", @@ -269,12 +268,12 @@ export class TaskGraph { private initLogging() { if (!Object.keys(this.logEntryMap).length) { - const header = this.garden.log.debug("Processing tasks...") - const counter = this.garden.log.debug({ + const header = this.log.debug("Processing tasks...") + const counter = this.log.debug({ msg: remainingTasksToStr(this.index.length), status: "active", }) - const inProgress = this.garden.log.debug(inProgressToStr(this.inProgress.getNodes())) + const inProgress = this.log.debug(inProgressToStr(this.inProgress.getNodes())) this.logEntryMap = { ...this.logEntryMap, header, @@ -288,7 +287,7 @@ export class TaskGraph { const divider = padEnd("", 80, "—") const error = toGardenError(err) const msg = `\nFailed ${node.getDescription()}. Here is the output:\n${divider}\n${error.message}\n${divider}\n` - this.garden.log.error({ msg, error }) + this.log.error({ msg, error }) } } 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 9f5126e9f42..03864fdba58 100644 --- a/garden-service/src/tasks/deploy.ts +++ b/garden-service/src/tasks/deploy.ts @@ -24,7 +24,7 @@ export interface DeployTaskParams { service: Service force: boolean forceBuild: boolean - logEntry?: LogEntry + log: LogEntry //TODO: Move watch and hotReloadServiceNames to a new commandContext object? watch?: boolean hotReloadServiceNames?: string[] @@ -35,15 +35,13 @@ export class DeployTask extends Task { private service: Service private forceBuild: boolean - private logEntry?: LogEntry private watch: boolean private hotReloadServiceNames?: string[] - constructor({ garden, service, force, forceBuild, logEntry, watch, hotReloadServiceNames }: DeployTaskParams) { - super({ garden, force, version: service.module.version }) + constructor({ garden, log, service, force, forceBuild, watch, hotReloadServiceNames }: DeployTaskParams) { + super({ garden, log, force, version: service.module.version }) this.service = service this.forceBuild = forceBuild - this.logEntry = logEntry this.watch = !!watch this.hotReloadServiceNames = hotReloadServiceNames } @@ -55,6 +53,7 @@ export class DeployTask extends Task { const deps: Task[] = await Bluebird.map(servicesToDeploy, async (service) => { return new DeployTask({ garden: this.garden, + log: this.log, service, force: false, forceBuild: this.forceBuild, @@ -65,6 +64,7 @@ export class DeployTask extends Task { deps.push(new PushTask({ garden: this.garden, + log: this.log, module: this.service.module, forceBuild: this.forceBuild, })) @@ -81,7 +81,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", @@ -93,7 +93,7 @@ export class DeployTask extends Task { const status = await this.garden.actions.getServiceStatus({ service: this.service, verifyHotReloadStatus: hotReloadEnabled ? "enabled" : "disabled", - logEntry, + log, }) if ( @@ -102,14 +102,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) @@ -117,17 +117,17 @@ export class DeployTask extends Task { try { result = await this.garden.actions.deployService({ service: this.service, - runtimeContext: await prepareRuntimeContext(this.garden, this.service.module, dependencies), - logEntry, + runtimeContext: await prepareRuntimeContext(this.garden, log, this.service.module, dependencies), + log, force: this.force, hotReload: hotReloadEnabled, }) } 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 } } diff --git a/garden-service/src/tasks/helpers.ts b/garden-service/src/tasks/helpers.ts index 4b7861569de..866305f8a64 100644 --- a/garden-service/src/tasks/helpers.ts +++ b/garden-service/src/tasks/helpers.ts @@ -14,13 +14,14 @@ import { BuildTask } from "./build" import { getNames } from "../util/util" import { Garden } from "../garden" import { Module } from "../types/module" +import { LogEntry } from "../logger/log-entry" /** * @param hotReloadServiceNames - names of services with hot reloading enabled (should not be redeployed) */ export async function getTasksForHotReload( - { garden, module, hotReloadServiceNames, serviceNames }: - { garden: Garden, module: Module, hotReloadServiceNames: string[], serviceNames: string[] }, + { garden, log, module, hotReloadServiceNames, serviceNames }: + { garden: Garden, log: LogEntry, module: Module, hotReloadServiceNames: string[], serviceNames: string[] }, ) { const hotReloadModuleNames = await getHotReloadModuleNames(garden, hotReloadServiceNames) @@ -29,11 +30,11 @@ export async function getTasksForHotReload( await computeAutoReloadDependants(garden))) .filter(m => !hotReloadModuleNames.has(m.name)) - const buildTask = new BuildTask({ garden, module, force: true }) + const buildTask = new BuildTask({ garden, log, module, force: true }) const deployTasks = (await servicesForModules(garden, modulesForDeployment, serviceNames)) .map(service => new DeployTask({ - garden, service, force: true, forceBuild: true, watch: true, hotReloadServiceNames, + garden, log, service, force: true, forceBuild: true, watch: true, hotReloadServiceNames, })) return [buildTask, ...deployTasks] @@ -46,10 +47,10 @@ export async function getHotReloadModuleNames(garden: Garden, hotReloadServiceNa } export async function getDeployTasks( - { garden, module, serviceNames, hotReloadServiceNames, force = false, forceBuild = false, + { garden, log, module, serviceNames, hotReloadServiceNames, force = false, forceBuild = false, watch = false, includeDependants = false }: { - garden: Garden, module: Module, serviceNames?: string[], hotReloadServiceNames: string[], + garden: Garden, log: LogEntry, module: Module, serviceNames?: string[], hotReloadServiceNames: string[], force?: boolean, forceBuild?: boolean, watch?: boolean, includeDependants?: boolean, }, ) { @@ -59,7 +60,7 @@ export async function getDeployTasks( : [module] return (await servicesForModules(garden, modulesForDeployment, serviceNames)) - .map(service => new DeployTask({ garden, service, force, forceBuild, watch, hotReloadServiceNames })) + .map(service => new DeployTask({ garden, log, service, force, forceBuild, watch, hotReloadServiceNames })) } 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..8a40b9e4004 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,18 +105,19 @@ 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", }) const dependencies = await getTestDependencies(this.garden, this.testConfig) - const runtimeContext = await prepareRuntimeContext(this.garden, this.module, dependencies) + const runtimeContext = await prepareRuntimeContext(this.garden, log, this.module, dependencies) 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 9b1f8c30531..d6efab8f12d 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 { @@ -68,14 +68,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 cc1efb38553..424a0d0c9bf 100644 --- a/garden-service/src/types/plugin/plugin.ts +++ b/garden-service/src/types/plugin/plugin.ts @@ -387,7 +387,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..501f8e6c632 100644 --- a/garden-service/src/types/service.ts +++ b/garden-service/src/types/service.ts @@ -16,6 +16,7 @@ import dedent = require("dedent") import { format } from "url" import { moduleVersionSchema } from "../vcs/base" import { Garden } from "../garden" +import { LogEntry } from "../logger/log-entry" import normalizeUrl = require("normalize-url") export interface Service { @@ -177,7 +178,7 @@ export const runtimeContextSchema = Joi.object() }) export async function prepareRuntimeContext( - garden: Garden, module: Module, serviceDependencies: Service[], + garden: Garden, log: LogEntry, module: Module, serviceDependencies: Service[], ): Promise { const buildDepKeys = module.build.dependencies.map(dep => getModuleKey(dep.name, dep.plugin)) const buildDependencies: Module[] = await garden.getModules(buildDepKeys) @@ -209,7 +210,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, + 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 3505be4f7a8..7114acdfef9 100644 --- a/garden-service/src/util/ext-tools.ts +++ b/garden-service/src/util/ext-tools.ts @@ -25,7 +25,7 @@ const toolsPath = join(globalGardenPath, "tools") interface ExecParams { cwd?: string - logEntry?: LogEntry + log: LogEntry args?: string[] } @@ -99,7 +99,7 @@ export class BinaryCmd extends Cmd { this.defaultCwd = dirname(this.executablePath) } - private async download(logEntry?: LogEntry) { + private async download(log: LogEntry) { // TODO: use lockfile to avoid multiple downloads of the same thing // (we avoid a race condition by downloading to a temporary path, so it's more about efficiency) @@ -110,13 +110,13 @@ export class BinaryCmd extends Cmd { const tmpPath = join(this.toolPath, this.versionDirname + "." + uuid.v4().substr(0, 8)) const tmpExecutable = join(tmpPath, ...this.executableSubpath) - logEntry && logEntry.setState(`Fetching ${this.name}...`) - const debug = logEntry && logEntry.debug(`Downloading ${this.spec.url}...`) + log.setState(`Fetching ${this.name}...`) + const debug = log.debug(`Downloading ${this.spec.url}...`) await ensureDir(tmpPath) try { - await this.fetch(tmpPath, logEntry) + await this.fetch(tmpPath, log) if (!(await pathExists(tmpExecutable))) { throw new ConfigurationError( @@ -136,11 +136,11 @@ export class BinaryCmd extends Cmd { } debug && debug.setSuccess("Done") - logEntry && logEntry.setSuccess(`Fetched ${this.name}`) + log.setSuccess(`Fetched ${this.name}`) } - 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: cwd || this.defaultCwd }) } @@ -149,7 +149,7 @@ export class BinaryCmd extends Cmd { return res.stdout } - private async fetch(targetPath: string, logEntry?: LogEntry) { + private async fetch(targetPath: string, log: LogEntry) { const response = await Axios({ method: "GET", url: this.spec.url, @@ -163,7 +163,7 @@ export class BinaryCmd extends Cmd { return new Promise((resolve, reject) => { response.data.on("error", (err) => { - logEntry && logEntry.setError(`Failed fetching ${response.request.url}`) + log.setError(`Failed fetching ${response.request.url}`) reject(err) }) @@ -205,7 +205,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.setError(`Failed extracting ${format} archive ${this.spec.url}`) reject(err) }) } 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 992e020b91d..f92c8d87d87 100644 --- a/garden-service/src/vcs/git.ts +++ b/garden-service/src/vcs/git.ts @@ -107,7 +107,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) @@ -116,7 +116,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) try { @@ -135,14 +135,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 1a6e08c7fe4..cafe6ce2855 100644 --- a/garden-service/test/helpers.ts +++ b/garden-service/test/helpers.ts @@ -139,10 +139,11 @@ export const testPlugin: PluginFactory = (): GardenPlugin => { runModule, async runService( - { ctx, service, interactive, runtimeContext, timeout, buildDependencies }: RunServiceParams, + { ctx, service, interactive, runtimeContext, timeout, log, buildDependencies }: 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 469f5e8348a..29e2dcbf5f7 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, @@ -39,6 +40,7 @@ const now = new Date() describe("ActionHelper", () => { let garden: Garden + let log: LogEntry let actions: ActionHelper let module: Module let service: Service @@ -46,6 +48,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") @@ -55,7 +58,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 }, @@ -63,7 +66,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 }, }) @@ -72,7 +75,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, @@ -80,7 +83,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, }) @@ -89,7 +92,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 }, @@ -97,7 +100,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 }, }) @@ -106,21 +109,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 }) }) }) @@ -129,7 +132,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, }) @@ -138,14 +141,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", () => { describe("hotReload", () => { it("should correctly call the corresponding plugin handler", async () => { const result = await actions.hotReload({ + log, module, runtimeContext: { envVars: { FOO: "bar" }, @@ -169,6 +173,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, @@ -192,6 +197,7 @@ describe("ActionHelper", () => { describe("testModule", () => { it("should correctly call the corresponding plugin handler", async () => { const result = await actions.testModule({ + log, module, interactive: true, runtimeContext: { @@ -222,6 +228,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, @@ -243,35 +250,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"], interactive: false }) + const result = await actions.execInService({ log, service, command: ["foo"], interactive: false }) expect(result).to.eql({ code: 0, output: "bla bla" }) }) }) @@ -279,7 +286,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({}) }) }) @@ -287,6 +294,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 30e955fe6c1..25ae9502806 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, }, @@ -97,10 +99,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/logger.ts b/garden-service/test/src/logger.ts index 09bb0532f2b..12edc538bdc 100644 --- a/garden-service/test/src/logger.ts +++ b/garden-service/test/src/logger.ts @@ -192,10 +192,10 @@ describe("LogEntry", () => { const deepDeepNested = deepNested.info("deep deep inside") const deepDeepEmpty = deepDeepNested.info() const indentations = [ - nested.opts.indentationLevel, - deepNested.opts.indentationLevel, - deepDeepNested.opts.indentationLevel, - deepDeepEmpty.opts.indentationLevel, + nested.opts.indent, + deepNested.opts.indent, + deepDeepNested.opts.indent, + deepDeepEmpty.opts.indent, ] expect(indentations).to.eql([1, 2, 3, 3]) }) diff --git a/garden-service/test/src/plugins/container.ts b/garden-service/test/src/plugins/container.ts index 648bc1ced9c..8a496e0a9cf 100644 --- a/garden-service/test/src/plugins/container.ts +++ b/garden-service/test/src/plugins/container.ts @@ -18,6 +18,7 @@ import { } from "../../helpers" import { moduleFromConfig } from "../../../src/types/module" import { ModuleConfig } from "../../../src/config/module" +import { LogEntry } from "../../../src/logger/log-entry" describe("plugins.container", () => { const projectRoot = resolve(dataDir, "test-project-container") @@ -53,9 +54,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) @@ -467,7 +470,7 @@ describe("plugins.container", () => { td.replace(helpers, "imageExistsLocally", async () => true) - const result = await getBuildStatus({ ctx, module, buildDependencies: {} }) + const result = await getBuildStatus({ ctx, log, module, buildDependencies: {} }) expect(result).to.eql({ ready: true }) }) @@ -476,7 +479,7 @@ describe("plugins.container", () => { td.replace(helpers, "imageExistsLocally", async () => false) - const result = await getBuildStatus({ ctx, module, buildDependencies: {} }) + const result = await getBuildStatus({ ctx, log, module, buildDependencies: {} }) expect(result).to.eql({ ready: false }) }) }) @@ -491,7 +494,7 @@ describe("plugins.container", () => { td.replace(helpers, "pullImage", async () => null) td.replace(helpers, "imageExistsLocally", async () => false) - const result = await build({ ctx, module, buildDependencies: {} }) + const result = await build({ ctx, log, module, buildDependencies: {} }) expect(result).to.eql({ fetched: true }) }) @@ -507,7 +510,7 @@ describe("plugins.container", () => { const dockerCli = td.replace(helpers, "dockerCli") - const result = await build({ ctx, module, buildDependencies: {} }) + const result = await build({ ctx, log, module, buildDependencies: {} }) expect(result).to.eql({ fresh: true, @@ -530,7 +533,7 @@ describe("plugins.container", () => { const dockerCli = td.replace(helpers, "dockerCli") - const result = await build({ ctx, module, buildDependencies: {} }) + const result = await build({ ctx, log, module, buildDependencies: {} }) expect(result).to.eql({ fresh: true, @@ -557,7 +560,7 @@ describe("plugins.container", () => { td.replace(helpers, "hasDockerfile", async () => false) - const result = await publishModule({ ctx, module, buildDependencies: {} }) + const result = await publishModule({ ctx, log, module, buildDependencies: {} }) expect(result).to.eql({ published: false }) }) @@ -572,7 +575,7 @@ describe("plugins.container", () => { const dockerCli = td.replace(helpers, "dockerCli") - const result = await publishModule({ ctx, module, buildDependencies: {} }) + const result = await publishModule({ ctx, log, module, buildDependencies: {} }) expect(result).to.eql({ message: "Published some/image:12345", published: true }) td.verify(dockerCli(module, ["tag", "some/image:12345", "some/image:12345"]), { times: 0 }) @@ -590,7 +593,7 @@ describe("plugins.container", () => { const dockerCli = td.replace(helpers, "dockerCli") - const result = await publishModule({ ctx, module, buildDependencies: {} }) + const result = await publishModule({ ctx, log, module, buildDependencies: {} }) 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..6978b839ea0 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, @@ -90,7 +91,7 @@ describe("task-graph", () => { it("should successfully process a single task without dependencies", async () => { const garden = await getGarden() - const graph = new TaskGraph(garden) + const graph = new TaskGraph(garden.log.info()) const task = new TestTask(garden, "a") await graph.addTask(task) @@ -113,7 +114,7 @@ describe("task-graph", () => { it("should process multiple tasks in dependency order", async () => { const garden = await getGarden() - const graph = new TaskGraph(garden) + const graph = new TaskGraph(garden.log.info()) const callbackResults = {} const resultOrder: string[] = [] @@ -205,7 +206,7 @@ describe("task-graph", () => { it("should recursively cancel a task's dependants when it throws an error", async () => { const garden = await getGarden() - const graph = new TaskGraph(garden) + const graph = new TaskGraph(garden.log.info()) const resultOrder: string[] = [] @@ -246,7 +247,7 @@ describe("task-graph", () => { "should process a task as an inheritor of an existing, in-progress task when they have the same base key", async () => { const garden = await getGarden() - const graph = new TaskGraph(garden) + const graph = new TaskGraph(garden.log.info()) let callbackResults = {} let resultOrder: string[] = [] 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,