From 5769aeb10f33b9be77bb3cea108751670391e98e Mon Sep 17 00:00:00 2001 From: Thorarinn Sigurdsson Date: Mon, 18 Mar 2019 21:49:24 +0100 Subject: [PATCH] feat(k8s): cache task results Added caching for task results. Similarly to the caching for test runs that was already in place, these are stored by version as ConfigMap-s. The version used to index these results includes the task's module's current version, along with the module versions of the task's runtime dependencies (if any). This is the same formula that is used for computing test task versions. Currently, tasks always execute, regardless of whether they have cached results for the current version, since we need to finish other changes that will provide dependency results to the process methods of task classes before the caching semantics can be finalized for tasks, in relation to dependency calculations. A versioning bug was also fixed for the test result caching functionality. Here, the version used was just the test config's module's version, whereas now the corresponding test task's version is used to index it instead (the same as is now also used to cache task results). --- garden-service/src/actions.ts | 11 ++- garden-service/src/commands/run/task.ts | 2 +- garden-service/src/commands/run/test.ts | 4 + .../plugins/kubernetes/container/handlers.ts | 2 + .../src/plugins/kubernetes/container/run.ts | 17 ++-- .../src/plugins/kubernetes/container/test.ts | 4 +- .../src/plugins/kubernetes/helm/run.ts | 15 +++- .../src/plugins/kubernetes/helm/test.ts | 4 +- .../src/plugins/kubernetes/task-results.ts | 81 +++++++++++++++++++ garden-service/src/plugins/kubernetes/test.ts | 14 ++-- garden-service/src/tasks/deploy.ts | 6 +- garden-service/src/tasks/task.ts | 55 +++++++++++-- garden-service/src/tasks/test.ts | 7 +- garden-service/src/types/plugin/outputs.ts | 13 +-- garden-service/src/types/plugin/params.ts | 32 ++++++-- garden-service/src/types/plugin/plugin.ts | 18 +++-- garden-service/test/unit/src/actions.ts | 20 +++-- 17 files changed, 241 insertions(+), 64 deletions(-) create mode 100644 garden-service/src/plugins/kubernetes/task-results.ts diff --git a/garden-service/src/actions.ts b/garden-service/src/actions.ts index 6733f2ab64..b4db998b8a 100644 --- a/garden-service/src/actions.ts +++ b/garden-service/src/actions.ts @@ -37,9 +37,9 @@ import { TestResult, PluginActionOutputs, PublishResult, - RunTaskResult, TaskActionOutputs, HotReloadServiceResult, + RunTaskResult, } from "./types/plugin/outputs" import { BuildModuleParams, @@ -70,6 +70,7 @@ import { PluginTaskActionParamsBase, RunTaskParams, TaskActionParams, + GetTaskResultParams, } from "./types/plugin/params" import { Service, ServiceStatus, getServiceRuntimeContext } from "./types/service" import { mapValues, values, keyBy, omit, pickBy, fromPairs } from "lodash" @@ -329,6 +330,14 @@ export class ActionHelper implements TypeGuard { return this.callTaskHandler({ params, actionType: "runTask" }) } + async getTaskResult(params: TaskActionHelperParams): Promise { + return this.callTaskHandler({ + params, + actionType: "getTaskResult", + defaultHandler: async () => null, + }) + } + //endregion //=========================================================================== diff --git a/garden-service/src/commands/run/task.ts b/garden-service/src/commands/run/task.ts index 6ec1543710..ae81afa23d 100644 --- a/garden-service/src/commands/run/task.ts +++ b/garden-service/src/commands/run/task.ts @@ -59,7 +59,7 @@ export class RunTaskCommand extends Command { await garden.actions.prepareEnvironment({ log }) - const taskTask = new TaskTask({ garden, graph, task, log, force: true, forceBuild: opts["force-build"] }) + const taskTask = await TaskTask.factory({ garden, graph, task, log, force: true, forceBuild: opts["force-build"] }) await garden.addTask(taskTask) const result = (await garden.processTasks())[taskTask.getBaseKey()] diff --git a/garden-service/src/commands/run/test.ts b/garden-service/src/commands/run/test.ts index ebbc563220..acd13705bc 100644 --- a/garden-service/src/commands/run/test.ts +++ b/garden-service/src/commands/run/test.ts @@ -25,6 +25,7 @@ import dedent = require("dedent") import { prepareRuntimeContext } from "../../types/service" import { logHeader } from "../../logger/util" import { PushTask } from "../../tasks/push" +import { getTestVersion } from "../../tasks/test" const runArgs = { module: new StringParameter({ @@ -101,6 +102,8 @@ export class RunTestCommand extends Command { printRuntimeContext(log, runtimeContext) + const testVersion = await getTestVersion(garden, graph, module, testConfig) + const result = await garden.actions.testModule({ log, module, @@ -108,6 +111,7 @@ export class RunTestCommand extends Command { runtimeContext, silent: false, testConfig, + testVersion, }) return { result } diff --git a/garden-service/src/plugins/kubernetes/container/handlers.ts b/garden-service/src/plugins/kubernetes/container/handlers.ts index c39b671659..c3a41c2213 100644 --- a/garden-service/src/plugins/kubernetes/container/handlers.ts +++ b/garden-service/src/plugins/kubernetes/container/handlers.ts @@ -19,6 +19,7 @@ import { getContainerServiceStatus } from "./status" import { getTestResult } from "../test" import { ContainerModule } from "../../container/config" import { configureMavenContainerModule, MavenContainerModule } from "../../maven-container/maven-container" +import { getTaskResult } from "../task-results" async function configure(params: ConfigureModuleParams) { const config = await configureContainerModule(params) @@ -46,6 +47,7 @@ export const containerHandlers = { runModule: runContainerModule, runService: runContainerService, runTask: runContainerTask, + getTaskResult, testModule: testContainerModule, } diff --git a/garden-service/src/plugins/kubernetes/container/run.ts b/garden-service/src/plugins/kubernetes/container/run.ts index 8832559278..c4a25d88c7 100644 --- a/garden-service/src/plugins/kubernetes/container/run.ts +++ b/garden-service/src/plugins/kubernetes/container/run.ts @@ -23,6 +23,7 @@ import { getContainerServiceStatus } from "./status" import { runPod } from "../run" import { containerHelpers } from "../../container/helpers" import { KubernetesPluginContext, KubernetesProvider } from "../kubernetes" +import { storeTaskResult } from "../task-results" export async function execInService(params: ExecInServiceParams) { const { ctx, service, command, interactive } = params @@ -115,7 +116,7 @@ export async function runContainerService( } export async function runContainerTask( - { ctx, log, module, task, interactive, runtimeContext }: RunTaskParams, + { ctx, log, module, task, taskVersion, interactive, runtimeContext }: RunTaskParams, ): Promise { extend(runtimeContext.envVars, task.spec.env || {}) @@ -124,7 +125,7 @@ export async function runContainerTask( const namespace = await getAppNamespace(ctx, provider) const image = await containerHelpers.getDeploymentImageId(module, provider.config.deploymentRegistry) - const result = await runPod({ + const res = await runPod({ context, namespace, module, @@ -139,8 +140,14 @@ export async function runContainerTask( log, }) - return { - ...result, + const result = { ...res, taskName: task.name } + + await storeTaskResult({ + ctx, + result, + taskVersion, taskName: task.name, - } + }) + + return result } diff --git a/garden-service/src/plugins/kubernetes/container/test.ts b/garden-service/src/plugins/kubernetes/container/test.ts index b10c9560b7..b7fed88b01 100644 --- a/garden-service/src/plugins/kubernetes/container/test.ts +++ b/garden-service/src/plugins/kubernetes/container/test.ts @@ -14,7 +14,7 @@ import { runContainerModule } from "./run" import { storeTestResult } from "../test" export async function testContainerModule( - { ctx, interactive, module, runtimeContext, testConfig, log }: + { ctx, interactive, module, runtimeContext, testConfig, testVersion, log }: TestModuleParams, ): Promise { const testName = testConfig.name @@ -32,5 +32,5 @@ export async function testContainerModule( log, }) - return storeTestResult({ ctx, module, testName, result }) + return storeTestResult({ ctx, module, testName, testVersion, result }) } diff --git a/garden-service/src/plugins/kubernetes/helm/run.ts b/garden-service/src/plugins/kubernetes/helm/run.ts index d593fbc488..194359aaf2 100644 --- a/garden-service/src/plugins/kubernetes/helm/run.ts +++ b/garden-service/src/plugins/kubernetes/helm/run.ts @@ -16,6 +16,7 @@ import { PluginContext } from "../../../plugin-context" import { LogEntry } from "../../../logger/log-entry" import { ConfigurationError } from "../../../exceptions" import { KubernetesPluginContext } from "../kubernetes" +import { storeTaskResult } from "../task-results" export async function runHelmModule( { @@ -52,7 +53,7 @@ export async function runHelmModule( } export async function runHelmTask( - { ctx, log, module, task, interactive, runtimeContext, timeout }: RunTaskParams, + { ctx, log, module, task, taskVersion, interactive, runtimeContext, timeout }: RunTaskParams, ): Promise { const k8sCtx = ctx const context = k8sCtx.provider.config.context @@ -74,10 +75,16 @@ export async function runHelmTask( log, }) - return { + const result = { ...res, taskName: task.name } + + await storeTaskResult({ + ctx, + result, + taskVersion, taskName: task.name, - ...res, - } + }) + + return result } async function getImage(ctx: PluginContext, module: HelmModule, log: LogEntry, resourceSpec: HelmResourceSpec) { diff --git a/garden-service/src/plugins/kubernetes/helm/test.ts b/garden-service/src/plugins/kubernetes/helm/test.ts index ea06fb904a..e4e3b76d76 100644 --- a/garden-service/src/plugins/kubernetes/helm/test.ts +++ b/garden-service/src/plugins/kubernetes/helm/test.ts @@ -17,7 +17,7 @@ import { findServiceResource, getChartResources, getResourceContainer, getServic import { KubernetesPluginContext } from "../kubernetes" export async function testHelmModule( - { ctx, log, interactive, module, runtimeContext, testConfig }: + { ctx, log, interactive, module, runtimeContext, testConfig, testVersion }: TestModuleParams, ): Promise { const testName = testConfig.name @@ -48,5 +48,5 @@ export async function testHelmModule( log, }) - return storeTestResult({ ctx: k8sCtx, module, testName, result }) + return storeTestResult({ ctx: k8sCtx, module, testName, testVersion, result }) } diff --git a/garden-service/src/plugins/kubernetes/task-results.ts b/garden-service/src/plugins/kubernetes/task-results.ts new file mode 100644 index 0000000000..82138b70fc --- /dev/null +++ b/garden-service/src/plugins/kubernetes/task-results.ts @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2018 Garden Technologies, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +import { GetTaskResultParams } from "../../types/plugin/params" +import { ContainerModule } from "../container/config" +import { HelmModule } from "./helm/config" +import { ModuleVersion } from "../../vcs/base" +import { KubernetesPluginContext, KubernetesProvider } from "./kubernetes" +import { KubeApi } from "./api" +import { getMetadataNamespace } from "./namespace" +import { RunTaskResult } from "../../types/plugin/outputs" +import { deserializeValues, serializeValues } from "../../util/util" +import { PluginContext } from "../../plugin-context" + +export async function getTaskResult( + { ctx, task, taskVersion }: GetTaskResultParams, +): Promise { + const k8sCtx = ctx + const api = new KubeApi(k8sCtx.provider.config.context) + const ns = await getMetadataNamespace(k8sCtx, k8sCtx.provider) + const resultKey = getTaskResultKey(task.name, taskVersion) + + try { + const res = await api.core.readNamespacedConfigMap(resultKey, ns) + return deserializeValues(res.body.data) + } catch (err) { + if (err.code === 404) { + return null + } else { + throw err + } + } +} + +export function getTaskResultKey(taskName: string, version: ModuleVersion) { + return `task-result--${taskName}--${version.versionString}` +} + +/** + * Store a task run result as a ConfigMap in the cluster. + * + * TODO: Implement a CRD for this. + */ +export async function storeTaskResult( + { ctx, taskName, taskVersion, result }: + { ctx: PluginContext, taskName: string, taskVersion: ModuleVersion, result: RunTaskResult }, +): Promise { + const provider = ctx.provider + const api = new KubeApi(provider.config.context) + const ns = await getMetadataNamespace(ctx, provider) + const resultKey = getTaskResultKey(taskName, taskVersion) + + const body = { + apiVersion: "v1", + kind: "ConfigMap", + metadata: { + name: resultKey, + annotations: { + "garden.io/generated": "true", + }, + }, + data: serializeValues(result), + } + + try { + await api.core.createNamespacedConfigMap(ns, body) + } catch (err) { + if (err.code === 409) { + await api.core.patchNamespacedConfigMap(resultKey, ns, body) + } else { + throw err + } + } + + return result +} diff --git a/garden-service/src/plugins/kubernetes/test.ts b/garden-service/src/plugins/kubernetes/test.ts index 59a8406293..7ee8a249cd 100644 --- a/garden-service/src/plugins/kubernetes/test.ts +++ b/garden-service/src/plugins/kubernetes/test.ts @@ -19,12 +19,12 @@ import { PluginContext } from "../../plugin-context" import { KubernetesPluginContext } from "./kubernetes" export async function getTestResult( - { ctx, module, testName, version }: GetTestResultParams, -) { + { ctx, module, testName, testVersion }: GetTestResultParams, +): Promise { const k8sCtx = ctx const api = new KubeApi(k8sCtx.provider.config.context) const ns = await getMetadataNamespace(k8sCtx, k8sCtx.provider) - const resultKey = getTestResultKey(module, testName, version) + const resultKey = getTestResultKey(module, testName, testVersion) try { const res = await api.core.readNamespacedConfigMap(resultKey, ns) @@ -48,9 +48,9 @@ export function getTestResultKey(module: Module, testName: string, version: Modu * TODO: Implement a CRD for this. */ export async function storeTestResult( - { ctx, module, testName, result }: - { ctx: PluginContext, module: Module, testName: string, result: RunResult }, -) { + { ctx, module, testName, testVersion, result }: + { ctx: PluginContext, module: Module, testName: string, testVersion: ModuleVersion, result: RunResult }, +): Promise { const k8sCtx = ctx const api = new KubeApi(k8sCtx.provider.config.context) @@ -60,7 +60,7 @@ export async function storeTestResult( } const ns = await getMetadataNamespace(k8sCtx, k8sCtx.provider) - const resultKey = getTestResultKey(module, testName, result.version) + const resultKey = getTestResultKey(module, testName, testVersion) const body = { apiVersion: "v1", kind: "ConfigMap", diff --git a/garden-service/src/tasks/deploy.ts b/garden-service/src/tasks/deploy.ts index a098de98a1..1c4f0d82c0 100644 --- a/garden-service/src/tasks/deploy.ts +++ b/garden-service/src/tasks/deploy.ts @@ -72,13 +72,13 @@ export class DeployTask extends BaseTask { if (this.fromWatch && includes(this.hotReloadServiceNames, this.service.name)) { return deployTasks } else { - const taskTasks = deps.task.map(task => { - return new TaskTask({ + const taskTasks = await Bluebird.map(deps.task, (task) => { + return TaskTask.factory({ task, garden: this.garden, log: this.log, graph: this.graph, - force: false, + force: this.force, forceBuild: this.forceBuild, }) }) diff --git a/garden-service/src/tasks/task.ts b/garden-service/src/tasks/task.ts index 3a294925b0..1557184b9d 100644 --- a/garden-service/src/tasks/task.ts +++ b/garden-service/src/tasks/task.ts @@ -6,8 +6,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +import * as Bluebird from "bluebird" import chalk from "chalk" -import { BaseTask } from "../tasks/base" +import { BaseTask, TaskParams } from "../tasks/base" import { Garden } from "../garden" import { Task } from "../types/task" import { PushTask } from "./push" @@ -16,6 +17,7 @@ import { LogEntry } from "../logger/log-entry" import { RunTaskResult } from "../types/plugin/outputs" import { prepareRuntimeContext } from "../types/service" import { DependencyGraphNodeType, ConfigGraph } from "../config-graph" +import { ModuleVersion } from "../vcs/base" export interface TaskTaskParams { garden: Garden @@ -34,13 +36,20 @@ export class TaskTask extends BaseTask { // ... to be renamed soon. private task: Task private forceBuild: boolean - constructor({ garden, log, graph, task, force, forceBuild }: TaskTaskParams) { - super({ garden, log, force, version: task.module.version }) + constructor({ garden, log, graph, task, version, force, forceBuild }: TaskTaskParams & TaskParams) { + super({ garden, log, force, version }) this.graph = graph this.task = task + this.force = force this.forceBuild = forceBuild } + static async factory(initArgs: TaskTaskParams): Promise { + const { garden, graph, task } = initArgs + const version = await getTaskVersion(garden, graph, task) + return new TaskTask({ ...initArgs, version }) + } + async getDependencies(): Promise { const pushTask = new PushTask({ @@ -64,8 +73,8 @@ export class TaskTask extends BaseTask { // ... to be renamed soon. }) }) - const taskTasks = deps.task.map(task => { - return new TaskTask({ + const taskTasks = await Bluebird.map(deps.task, (task) => { + return TaskTask.factory({ task, log: this.log, garden: this.garden, @@ -91,6 +100,18 @@ export class TaskTask extends BaseTask { // ... to be renamed soon. const task = this.task const module = task.module + // TODO: Re-enable this logic when we've started providing task graph results to process methods. + + // const cachedResult = await this.getTaskReosult() + + // if (cachedResult && cachedResult.success) { + // this.log.info({ + // section: task.name, + // }).setSuccess({ msg: chalk.green("Already run") }) + + // return cachedResult + // } + const log = this.log.info({ section: task.name, msg: "Running", @@ -108,6 +129,7 @@ export class TaskTask extends BaseTask { // ... to be renamed soon. log, runtimeContext, interactive: false, + taskVersion: this.version, }) } catch (err) { log.setError() @@ -120,4 +142,27 @@ export class TaskTask extends BaseTask { // ... to be renamed soon. } + // private async getTaskResult(): Promise { + // if (this.force) { + // return null + // } + + // return this.garden.actions.getTaskResult({ + // log: this.log, + // task: this.task, + // taskVersion: this.version, + // }) + // } + +} + +/** + * Determine the version of the task run, based on the version of the module and each of its dependencies. + */ +export async function getTaskVersion( + garden: Garden, graph: ConfigGraph, task: Task, +): Promise { + const { module } = task + const moduleDeps = await graph.resolveDependencyModules(module.build.dependencies, task.config.dependencies) + return garden.resolveVersion(module.name, moduleDeps) } diff --git a/garden-service/src/tasks/test.ts b/garden-service/src/tasks/test.ts index 392a722daa..0970afa4a3 100644 --- a/garden-service/src/tasks/test.ts +++ b/garden-service/src/tasks/test.ts @@ -130,6 +130,7 @@ export class TestTask extends BaseTask { runtimeContext, silent: true, testConfig: this.testConfig, + testVersion: this.version, }) } catch (err) { log.setError() @@ -145,7 +146,7 @@ export class TestTask extends BaseTask { return result } - private async getTestResult() { + private async getTestResult(): Promise { if (this.force) { return null } @@ -154,7 +155,7 @@ export class TestTask extends BaseTask { log: this.log, module: this.module, testName: this.testConfig.name, - version: this.version, + testVersion: this.version, }) } } @@ -192,7 +193,7 @@ async function getTestDependencies(graph: ConfigGraph, testConfig: TestConfig) { /** * Determine the version of the test run, based on the version of the module and each of its dependencies. */ -async function getTestVersion( +export async function getTestVersion( garden: Garden, graph: ConfigGraph, module: Module, testConfig: TestConfig, ): Promise { const moduleDeps = await graph.resolveDependencyModules(module.build.dependencies, testConfig.dependencies) diff --git a/garden-service/src/types/plugin/outputs.ts b/garden-service/src/types/plugin/outputs.ts index a1c8ca502b..3b7fe228b7 100644 --- a/garden-service/src/types/plugin/outputs.ts +++ b/garden-service/src/types/plugin/outputs.ts @@ -302,16 +302,7 @@ export const runTaskResultSchema = Joi.object() .description("The output log from the run."), }) -export interface TaskStatus { - done: boolean -} - -export const taskStatusSchema = Joi.object() - .keys({ - done: Joi.boolean() - .required() - .description("Whether the task has been successfully executed for the module's current version."), - }) +export const getTaskResultSchema = runTaskResultSchema.allow(null) export interface PluginActionOutputs { configureProvider: Promise @@ -336,8 +327,8 @@ export interface ServiceActionOutputs { } export interface TaskActionOutputs { - getTaskStatus: Promise runTask: Promise + getTaskResult: Promise } export interface ModuleActionOutputs extends ServiceActionOutputs { diff --git a/garden-service/src/types/plugin/params.ts b/garden-service/src/types/plugin/params.ts index 6ca0f1a662..75b1d76c8b 100644 --- a/garden-service/src/types/plugin/params.ts +++ b/garden-service/src/types/plugin/params.ts @@ -20,6 +20,7 @@ import { moduleConfigSchema } from "../../config/module" import { testConfigSchema } from "../../config/test" import { taskSchema } from "../../config/task" import { ProviderConfig, projectNameSchema, providerConfigBaseSchema } from "../../config/project" +import { deline } from "../../util/string" export interface PluginActionContextParams { ctx: PluginContext @@ -196,26 +197,30 @@ export const runModuleParamsSchema = runModuleBaseSchema .description("The command to run in the module."), }) +export const testVersionSchema = moduleVersionSchema + .description(deline` + The test run's version. In addition to the parent module's version, this also + factors in the module versions of the test's runtime dependencies (if any).`) + export interface TestModuleParams extends PluginModuleActionParamsBase { interactive: boolean runtimeContext: RuntimeContext silent: boolean testConfig: T["testConfigs"][0] + testVersion: ModuleVersion } export const testModuleParamsSchema = runModuleBaseSchema - .keys({ - testConfig: testConfigSchema, - }) + .keys({ testConfig: testConfigSchema, testVersion: testVersionSchema }) export interface GetTestResultParams extends PluginModuleActionParamsBase { testName: string - version: ModuleVersion + testVersion: ModuleVersion } export const getTestResultParamsSchema = moduleActionParamsSchema .keys({ testName: Joi.string() .description("A unique name to identify the test run."), - version: moduleVersionSchema, + testVersion: testVersionSchema, }) /** @@ -319,16 +324,27 @@ export const runServiceParamsSchema = serviceActionParamsSchema /** * Task actions */ -export interface GetTaskStatusParams extends PluginTaskActionParamsBase { } -export const getTaskStatusParamsSchema = taskActionParamsSchema + +export const taskVersionSchema = moduleVersionSchema + .description(deline` + The task run's version. In addition to the parent module's version, this also + factors in the module versions of the tasks's runtime dependencies (if any).`) + +export interface GetTaskResultParams extends PluginTaskActionParamsBase { + taskVersion: ModuleVersion +} +export const getTaskResultParamsSchema = taskActionParamsSchema + .keys({ taskVersion: taskVersionSchema }) export interface RunTaskParams extends PluginTaskActionParamsBase { interactive: boolean runtimeContext: RuntimeContext + taskVersion: ModuleVersion timeout?: number } export const runTaskParamsSchema = taskActionParamsSchema .keys(runBaseParams) + .keys({ taskVersion: taskVersionSchema }) export interface ServiceActionParams { getServiceStatus: GetServiceStatusParams @@ -341,7 +357,7 @@ export interface ServiceActionParams { } export interface TaskActionParams { - getTaskStatus: GetTaskStatusParams + getTaskResult: GetTaskResultParams runTask: RunTaskParams } diff --git a/garden-service/src/types/plugin/plugin.ts b/garden-service/src/types/plugin/plugin.ts index 426eeed600..b9f99eae5d 100644 --- a/garden-service/src/types/plugin/plugin.ts +++ b/garden-service/src/types/plugin/plugin.ts @@ -44,7 +44,7 @@ import { testModuleParamsSchema, getTestResultParamsSchema, publishModuleParamsSchema, - getTaskStatusParamsSchema, + getTaskResultParamsSchema, runTaskParamsSchema, configureProviderParamsSchema, } from "./params" @@ -71,8 +71,8 @@ import { testResultSchema, configureModuleResultSchema, publishModuleResultSchema, - taskStatusSchema, runTaskResultSchema, + getTaskResultSchema, configureProviderResultSchema, } from "./outputs" @@ -263,13 +263,17 @@ export const serviceActionDescriptions: { [P in ServiceActionName]: PluginAction export const taskActionDescriptions: { [P in TaskActionName]: PluginActionDescription } = { // TODO: see if this is actually necessary or useful - getTaskStatus: { + getTaskResult: { description: dedent` - Check and return the execution status of a task, i.e. whether the task has been successfully - completed for the module's current version. + Retrieve the task result for the specified version. Use this along with the \`runTask\` handler + to avoid running the same task repeatedly when its dependencies haven't changed. + + Note that the version string provided to this handler may be a hash of the module's version, as + well as any runtime dependencies configured for the task, so it may not match the current version + of the module itself. `, - paramsSchema: getTaskStatusParamsSchema, - resultSchema: taskStatusSchema, + paramsSchema: getTaskResultParamsSchema, + resultSchema: getTaskResultSchema, }, runTask: { description: dedent` diff --git a/garden-service/test/unit/src/actions.ts b/garden-service/test/unit/src/actions.ts index 962d1b3ada..921455df88 100644 --- a/garden-service/test/unit/src/actions.ts +++ b/garden-service/test/unit/src/actions.ts @@ -27,7 +27,7 @@ import { execInServiceParamsSchema, getServiceLogsParamsSchema, runServiceParamsSchema, - getTaskStatusParamsSchema, + getTaskResultParamsSchema, runTaskParamsSchema, getEnvironmentStatusParamsSchema, prepareEnvironmentParamsSchema, @@ -218,6 +218,7 @@ describe("ActionHelper", () => { timeout: 1234, spec: {}, }, + testVersion: module.version, }) expect(result).to.eql({ moduleName: module.name, @@ -238,7 +239,7 @@ describe("ActionHelper", () => { log, module, testName: "test", - version: module.version, + testVersion: module.version, }) expect(result).to.eql({ moduleName: module.name, @@ -331,6 +332,7 @@ describe("ActionHelper", () => { envVars: { FOO: "bar" }, dependencies: {}, }, + taskVersion: task.module.version, }) expect(result).to.eql({ moduleName: task.module.name, @@ -582,10 +584,18 @@ const testPlugin: PluginFactory = async () => ({ } }, - getTaskStatus: async (params) => { - validate(params, getTaskStatusParamsSchema) + getTaskResult: async (params) => { + validate(params, getTaskResultParamsSchema) + const module = params.task.module return { - done: true, + moduleName: module.name, + taskName: params.task.name, + command: ["foo"], + completedAt: now, + output: "bla bla", + success: true, + startedAt: now, + version: params.module.version, } },