diff --git a/garden-service/src/config-graph.ts b/garden-service/src/config-graph.ts index 98da765b72..88e908c443 100644 --- a/garden-service/src/config-graph.ts +++ b/garden-service/src/config-graph.ts @@ -46,8 +46,36 @@ export type DependencyRelationFilterFn = (DependencyGraphNode) => boolean // Output types for rendering/logging export type RenderedGraph = { nodes: RenderedNode[], relationships: RenderedEdge[] } export type RenderedEdge = { dependant: RenderedNode, dependency: RenderedNode } -export type RenderedNode = { type: RenderedNodeType, name: string } export type RenderedNodeType = "build" | "deploy" | "run" | "test" | "push" | "publish" +export interface RenderedNodeBase { + type: RenderedNodeType + name: string + moduleName: string + key: string +} +export interface RenderedBuildNode extends RenderedNodeBase { + type: "build" +} +export interface RenderedPushNode extends RenderedNodeBase { + type: "push" +} +export interface RenderedPublishNode extends RenderedNodeBase { + type: "publish" +} +export interface RenderedServiceNode extends RenderedNodeBase { + type: "deploy" + serviceName: string +} +export interface RenderedTaskNode extends RenderedNodeBase { + type: "run" + taskName: string +} +export interface RenderedTestNode extends RenderedNodeBase { + type: "test" + testName: string +} +export type RenderedNode = RenderedBuildNode | RenderedPushNode | RenderedPublishNode + | RenderedServiceNode | RenderedTaskNode | RenderedTestNode /** * A graph data structure that facilitates querying (recursive or non-recursive) of the project's dependency and @@ -172,7 +200,7 @@ export class ConfigGraph { // Test dependencies for (const testConfig of moduleConfig.testConfigs) { - const testConfigName = `${moduleConfig.name}.${testConfig.name}` + const testConfigName = testKey(moduleConfig.name, testConfig.name) this.testConfigs[testConfigName] = { moduleKey, config: testConfig } @@ -524,9 +552,47 @@ export class DependencyGraphNode { } render(): RenderedNode { - return { - type: renderedNodeTypeMap[this.type], + const type = renderedNodeTypeMap[this.type] + const renderedNode = { name: this.name, + moduleName: this.moduleName, + key: nodeKey(this.type, this.name), + } + switch (type) { + case "build": + return { + type, + ...renderedNode, + } + case "deploy": + return { + type, + serviceName: this.name, + ...renderedNode, + } + case "run": + return { + type, + taskName: this.name, + ...renderedNode, + } + case "test": + const { testName } = parseTestKey(this.name) + return { + type, + testName, + ...renderedNode, + } + case "push": + return { + type, + ...renderedNode, + } + case "publish": + return { + type, + ...renderedNode, + } } } @@ -576,6 +642,15 @@ function nodeKey(type: DependencyGraphNodeType, name: string) { return `${type}.${name}` } +function testKey(moduleName: string, testName: string) { + return `${moduleName}.${testName}` +} + +function parseTestKey(key: string) { + const [moduleName, testName] = key.split(".") + return { moduleName, testName } +} + function serviceTaskConflict(conflictingName: string, moduleWithTask: string, moduleWithService: string) { return new ConfigurationError(deline` Service and task names must be mutually unique - the name '${conflictingName}' is used for a task in diff --git a/garden-service/test/unit/src/config-graph.ts b/garden-service/test/unit/src/config-graph.ts index 541fd76045..1de49aeb24 100644 --- a/garden-service/test/unit/src/config-graph.ts +++ b/garden-service/test/unit/src/config-graph.ts @@ -2,7 +2,7 @@ import { resolve } from "path" import { expect } from "chai" import { makeTestGardenA, makeTestGarden, dataDir, expectError } from "../../helpers" import { getNames } from "../../../src/util/util" -import { ConfigGraph } from "../../../src/config-graph" +import { ConfigGraph, DependencyGraphNode } from "../../../src/config-graph" import { Garden } from "../../../src/garden" describe("ConfigGraph", () => { @@ -182,4 +182,161 @@ describe("ConfigGraph", () => { expect(getNames(modules)).to.eql(["module-a", "module-b", "module-c"]) }) }) + + describe("render", () => { + it("should render config graph nodes with test names", () => { + const rendered = graphA.render() + expect(rendered.nodes).to.have.deep.members([ + { + type: "build", + name: "module-a", + moduleName: "module-a", + key: "build.module-a", + }, + { + type: "build", + name: "module-b", + moduleName: "module-b", + key: "build.module-b", + }, + { + type: "build", + name: "module-c", + moduleName: "module-c", + key: "build.module-c", + }, + { + type: "test", + testName: "unit", + name: "module-c.unit", + moduleName: "module-c", + key: "test.module-c.unit", + }, + { + type: "run", + taskName: "task-c", + name: "task-c", + moduleName: "module-c", + key: "task.task-c", + }, + { + type: "deploy", + serviceName: "service-c", + name: "service-c", + moduleName: "module-c", + key: "service.service-c", + }, + { + type: "test", + testName: "unit", + name: "module-a.unit", + moduleName: "module-a", + key: "test.module-a.unit", + }, + { + type: "run", + taskName: "task-a", + name: "task-a", + moduleName: "module-a", + key: "task.task-a", + }, + { + type: "test", + testName: "unit", + name: "module-b.unit", + moduleName: "module-b", + key: "test.module-b.unit", + }, + { + type: "run", + taskName: "task-b", + name: "task-b", + moduleName: "module-b", + key: "task.task-b", + }, + { + type: "deploy", + serviceName: "service-a", + name: "service-a", + moduleName: "module-a", + key: "service.service-a", + }, + { + type: "deploy", + serviceName: "service-b", + name: "service-b", + moduleName: "module-b", + key: "service.service-b", + }, + ]) + }) + }) +}) + +describe("DependencyGraphNode", () => { + describe("render", () => { + it("should render a build node", () => { + const node = new DependencyGraphNode("build", "module-a", "module-a") + const res = node.render() + expect(res).to.eql({ + type: "build", + name: "module-a", + moduleName: "module-a", + key: "build.module-a", + }) + }) + it("should render a deploy node", () => { + const node = new DependencyGraphNode("service", "service-a", "module-a") + const res = node.render() + expect(res).to.eql({ + type: "deploy", + name: "service-a", + moduleName: "module-a", + serviceName: "service-a", + key: "service.service-a", + }) + }) + it("should render a run node", () => { + const node = new DependencyGraphNode("task", "task-a", "module-a") + const res = node.render() + expect(res).to.eql({ + type: "run", + name: "task-a", + moduleName: "module-a", + taskName: "task-a", + key: "task.task-a", + }) + }) + it("should render a test node", () => { + const node = new DependencyGraphNode("test", "module-a.test-a", "module-a") + const res = node.render() + expect(res).to.eql({ + type: "test", + name: "module-a.test-a", + moduleName: "module-a", + testName: "test-a", + key: "test.module-a.test-a", + }) + }) + it("should render a push node", () => { + const node = new DependencyGraphNode("push", "module-a", "module-a") + const res = node.render() + expect(res).to.eql({ + type: "push", + name: "module-a", + moduleName: "module-a", + key: "push.module-a", + }) + }) + it("should render a publish node", () => { + const node = new DependencyGraphNode("publish", "module-a", "module-a") + const res = node.render() + expect(res).to.eql({ + type: "publish", + name: "module-a", + moduleName: "module-a", + key: "publish.module-a", + }) + }) + }) })