From d26595f6775887c3cbeb8ab6ae4ae78c5cdafe8d Mon Sep 17 00:00:00 2001 From: Jon Edvald Date: Wed, 27 Nov 2019 16:05:57 +0100 Subject: [PATCH] fix(core): error when services had runtime dependencies on task outputs --- garden-service/src/actions.ts | 1 + .../src/tasks/get-service-status.ts | 11 +- .../test-projects/exec-artifacts/garden.yml | 2 - .../exec-artifacts/module-a/garden.yml | 9 -- .../exec-artifacts/module-b/garden.yml | 9 -- garden-service/test/unit/src/tasks/deploy.ts | 139 ++++++++++++++++++ .../test/unit/src/tasks/get-service-status.ts | 132 +++++++++++++++++ 7 files changed, 278 insertions(+), 25 deletions(-) delete mode 100644 garden-service/test/unit/data/test-projects/exec-artifacts/garden.yml delete mode 100644 garden-service/test/unit/data/test-projects/exec-artifacts/module-a/garden.yml delete mode 100644 garden-service/test/unit/data/test-projects/exec-artifacts/module-b/garden.yml create mode 100644 garden-service/test/unit/src/tasks/deploy.ts create mode 100644 garden-service/test/unit/src/tasks/get-service-status.ts diff --git a/garden-service/src/actions.ts b/garden-service/src/actions.ts index 482334909a..53e6b28eb0 100644 --- a/garden-service/src/actions.ts +++ b/garden-service/src/actions.ts @@ -764,6 +764,7 @@ export class ActionRouter implements TypeGuard { const handlerParams = { ...(await this.commonParams(handler, log)), ...params, + service, module, runtimeContext, } diff --git a/garden-service/src/tasks/get-service-status.ts b/garden-service/src/tasks/get-service-status.ts index d849154755..967c4837f5 100644 --- a/garden-service/src/tasks/get-service-status.ts +++ b/garden-service/src/tasks/get-service-status.ts @@ -14,8 +14,7 @@ import { Garden } from "../garden" import { ConfigGraph } from "../config-graph" import { TaskResults } from "../task-graph" import { prepareRuntimeContext } from "../runtime-context" -import { GetTaskResultTask } from "./get-task-result" -import { getTaskVersion } from "./task" +import { getTaskVersion, TaskTask } from "./task" import Bluebird from "bluebird" export interface GetServiceStatusTaskParams { @@ -55,17 +54,19 @@ export class GetServiceStatusTask extends BaseTask { }) }) - const taskResultTasks = await Bluebird.map(deps.task, async (task) => { - return new GetTaskResultTask({ + const taskTasks = await Bluebird.map(deps.task, async (task) => { + return new TaskTask({ garden: this.garden, + graph: this.graph, log: this.log, task, force: false, + forceBuild: false, version: await getTaskVersion(this.garden, this.graph, task), }) }) - return [...statusTasks, ...taskResultTasks] + return [...statusTasks, ...taskTasks] } getName() { diff --git a/garden-service/test/unit/data/test-projects/exec-artifacts/garden.yml b/garden-service/test/unit/data/test-projects/exec-artifacts/garden.yml deleted file mode 100644 index 5cff439fd2..0000000000 --- a/garden-service/test/unit/data/test-projects/exec-artifacts/garden.yml +++ /dev/null @@ -1,2 +0,0 @@ -kind: Project -name: exec-task-outputs diff --git a/garden-service/test/unit/data/test-projects/exec-artifacts/module-a/garden.yml b/garden-service/test/unit/data/test-projects/exec-artifacts/module-a/garden.yml deleted file mode 100644 index 8b53e19079..0000000000 --- a/garden-service/test/unit/data/test-projects/exec-artifacts/module-a/garden.yml +++ /dev/null @@ -1,9 +0,0 @@ -kind: Module -name: module-a -type: exec -tasks: - - name: task-a - command: [sh, -c, '"touch foo.txt"'] - artifacts: - - source: foo.* - target: bar/ diff --git a/garden-service/test/unit/data/test-projects/exec-artifacts/module-b/garden.yml b/garden-service/test/unit/data/test-projects/exec-artifacts/module-b/garden.yml deleted file mode 100644 index 14241607ca..0000000000 --- a/garden-service/test/unit/data/test-projects/exec-artifacts/module-b/garden.yml +++ /dev/null @@ -1,9 +0,0 @@ -kind: Module -name: module-b -type: exec -tasks: - - name: task-b - dependencies: [task-a] - command: [sh, -c, '"mkdir -p moo && touch moo/boo.txt"'] - artifacts: - - source: moo/* diff --git a/garden-service/test/unit/src/tasks/deploy.ts b/garden-service/test/unit/src/tasks/deploy.ts new file mode 100644 index 0000000000..b591751fa0 --- /dev/null +++ b/garden-service/test/unit/src/tasks/deploy.ts @@ -0,0 +1,139 @@ +import tmp from "tmp-promise" +import execa from "execa" + +import { ProjectConfig } from "../../../../src/config/project" +import { DEFAULT_API_VERSION } from "../../../../src/constants" +import { Garden } from "../../../../src/garden" +import { GardenPlugin } from "../../../../src/types/plugin/plugin" +import { joi } from "../../../../src/config/common" +import { ServiceState } from "../../../../src/types/service" +import { DeployTask } from "../../../../src/tasks/deploy" +import { DeployServiceParams } from "../../../../src/types/plugin/service/deployService" +import { RunTaskParams } from "../../../../src/types/plugin/task/runTask" +import { expect } from "chai" + +describe("DeployTask", () => { + let tmpDir: tmp.DirectoryResult + let config: ProjectConfig + + before(async () => { + tmpDir = await tmp.dir({ unsafeCleanup: true }) + + await execa("git", ["init"], { cwd: tmpDir.path }) + + config = { + apiVersion: DEFAULT_API_VERSION, + kind: "Project", + name: "test", + path: tmpDir.path, + defaultEnvironment: "default", + dotIgnoreFiles: [], + environments: [{ name: "default", variables: {} }], + providers: [{ name: "test" }], + variables: {}, + } + }) + + after(async () => { + await tmpDir.cleanup() + }) + + describe("process", () => { + it("should correctly resolve runtime outputs from tasks", async () => { + const testPlugin: GardenPlugin = { + name: "test", + createModuleTypes: [ + { + name: "test", + docs: "test", + serviceOutputsSchema: joi.object().keys({ log: joi.string() }), + handlers: { + build: async () => ({}), + getServiceStatus: async () => { + return { + state: "missing", + detail: {}, + outputs: {}, + } + }, + deployService: async ({ service }: DeployServiceParams) => { + return { + state: "ready", + detail: {}, + outputs: { log: service.spec.log }, + } + }, + runTask: async ({ task }: RunTaskParams) => { + const log = task.spec.log + + return { + taskName: task.name, + moduleName: task.module.name, + success: true, + outputs: { log }, + command: [], + log, + startedAt: new Date(), + completedAt: new Date(), + version: task.module.version.versionString, + } + }, + }, + }, + ], + } + + const garden = await Garden.factory(tmpDir.path, { config, plugins: [testPlugin] }) + + garden["moduleConfigs"] = { + test: { + apiVersion: DEFAULT_API_VERSION, + name: "test", + type: "test", + allowPublish: false, + build: { dependencies: [] }, + outputs: {}, + path: tmpDir.path, + serviceConfigs: [ + { + name: "test-service", + dependencies: ["test-task"], + hotReloadable: false, + spec: { + log: "${runtime.tasks.test-task.outputs.log}", + }, + }, + ], + taskConfigs: [ + { + name: "test-task", + dependencies: [], + spec: { + log: "test output", + }, + timeout: 10, + }, + ], + testConfigs: [], + spec: { bla: "fla" }, + }, + } + + const graph = await garden.getConfigGraph() + const testService = await graph.getService("test-service") + + const deployTask = new DeployTask({ + garden, + graph, + service: testService, + force: true, + forceBuild: false, + log: garden.log, + }) + + const result = await garden.processTasks([deployTask]) + + expect(result[deployTask.getKey()]!.output.outputs).to.eql({ log: "test output" }) + }) + }) +}) diff --git a/garden-service/test/unit/src/tasks/get-service-status.ts b/garden-service/test/unit/src/tasks/get-service-status.ts new file mode 100644 index 0000000000..e322c9cc5a --- /dev/null +++ b/garden-service/test/unit/src/tasks/get-service-status.ts @@ -0,0 +1,132 @@ +import tmp from "tmp-promise" +import execa from "execa" + +import { ProjectConfig } from "../../../../src/config/project" +import { DEFAULT_API_VERSION } from "../../../../src/constants" +import { Garden } from "../../../../src/garden" +import { GardenPlugin } from "../../../../src/types/plugin/plugin" +import { joi } from "../../../../src/config/common" +import { ServiceState } from "../../../../src/types/service" +import { DeployServiceParams } from "../../../../src/types/plugin/service/deployService" +import { RunTaskParams } from "../../../../src/types/plugin/task/runTask" +import { expect } from "chai" +import { GetServiceStatusTask } from "../../../../src/tasks/get-service-status" +import { GetServiceStatusParams } from "../../../../src/types/plugin/service/getServiceStatus" + +describe("GetServiceStatusTask", () => { + let tmpDir: tmp.DirectoryResult + let config: ProjectConfig + + before(async () => { + tmpDir = await tmp.dir({ unsafeCleanup: true }) + + await execa("git", ["init"], { cwd: tmpDir.path }) + + config = { + apiVersion: DEFAULT_API_VERSION, + kind: "Project", + name: "test", + path: tmpDir.path, + defaultEnvironment: "default", + dotIgnoreFiles: [], + environments: [{ name: "default", variables: {} }], + providers: [{ name: "test" }], + variables: {}, + } + }) + + after(async () => { + await tmpDir.cleanup() + }) + + describe("process", () => { + it("should correctly resolve runtime outputs from tasks", async () => { + const testPlugin: GardenPlugin = { + name: "test", + createModuleTypes: [ + { + name: "test", + docs: "test", + serviceOutputsSchema: joi.object().keys({ log: joi.string() }), + handlers: { + build: async () => ({}), + getServiceStatus: async ({ service }: GetServiceStatusParams) => { + return { + state: "ready", + detail: {}, + outputs: { log: service.spec.log }, + } + }, + runTask: async ({ task }: RunTaskParams) => { + const log = task.spec.log + + return { + taskName: task.name, + moduleName: task.module.name, + success: true, + outputs: { log }, + command: [], + log, + startedAt: new Date(), + completedAt: new Date(), + version: task.module.version.versionString, + } + }, + }, + }, + ], + } + + const garden = await Garden.factory(tmpDir.path, { config, plugins: [testPlugin] }) + + garden["moduleConfigs"] = { + test: { + apiVersion: DEFAULT_API_VERSION, + name: "test", + type: "test", + allowPublish: false, + build: { dependencies: [] }, + outputs: {}, + path: tmpDir.path, + serviceConfigs: [ + { + name: "test-service", + dependencies: ["test-task"], + hotReloadable: false, + spec: { + log: "${runtime.tasks.test-task.outputs.log}", + }, + }, + ], + taskConfigs: [ + { + name: "test-task", + dependencies: [], + spec: { + log: "test output", + }, + timeout: 10, + }, + ], + testConfigs: [], + spec: { bla: "fla" }, + }, + } + + const graph = await garden.getConfigGraph() + const testService = await graph.getService("test-service") + + const statusTask = new GetServiceStatusTask({ + garden, + graph, + service: testService, + force: true, + log: garden.log, + }) + + const result = await garden.processTasks([statusTask]) + + expect(result[statusTask.getKey()]!.output.outputs).to.eql({ log: "test output" }) + }) + }) +})