From 353a05e67753fe8ffc15dd0ca28a8d7924a9b15f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ey=C3=BE=C3=B3r=20Magn=C3=BAsson?= Date: Tue, 4 Feb 2020 22:18:52 +0100 Subject: [PATCH] fix(cli): add exclude-disabled option to get config command The dashboard fails to render if there are disabled services in the config that it loads via the 'get config' command. --- dashboard/src/api/api.ts | 2 +- dashboard/src/containers/overview.tsx | 6 +- docs/reference/commands.md | 8 +- garden-service/src/commands/get/get-config.ts | 31 +- .../test/unit/src/commands/get/get-config.ts | 355 ++++++++++++++++++ 5 files changed, 394 insertions(+), 8 deletions(-) diff --git a/dashboard/src/api/api.ts b/dashboard/src/api/api.ts index bf125d1a4c..dd0f13d9c1 100644 --- a/dashboard/src/api/api.ts +++ b/dashboard/src/api/api.ts @@ -24,7 +24,7 @@ export interface ApiRequest { const MAX_LOG_LINES = 5000 export async function fetchConfig() { - return apiPost("get.config") + return apiPost("get.config", { "exclude-disabled": true }) } export async function fetchGraph() { diff --git a/dashboard/src/containers/overview.tsx b/dashboard/src/containers/overview.tsx index ac71164c47..0ded8efde2 100644 --- a/dashboard/src/containers/overview.tsx +++ b/dashboard/src/containers/overview.tsx @@ -104,9 +104,9 @@ export default () => { } const moduleProps: ModuleProps[] = Object.values(modules).map((module: Module) => { - const serviceEntities = module.services.map((serviceKey) => services[serviceKey]) || [] - const testEntities = module.tests.map((testKey) => tests[testKey]) || [] - const taskEntities = module.tasks.map((taskKey) => tasks[taskKey]) || [] + const serviceEntities = module.services.map((serviceKey) => services[serviceKey]).filter(Boolean) + const testEntities = module.tests.map((testKey) => tests[testKey]).filter(Boolean) + const taskEntities = module.tasks.map((taskKey) => tasks[taskKey]).filter(Boolean) return { name: module.name, diff --git a/docs/reference/commands.md b/docs/reference/commands.md index 20b09a36a9..20dcd10dd6 100644 --- a/docs/reference/commands.md +++ b/docs/reference/commands.md @@ -259,7 +259,13 @@ Outputs the fully resolved configuration for this project and environment. ##### Usage - garden get config + garden get config [options] + +##### Options + +| Argument | Alias | Type | Description | +| -------- | ----- | ---- | ----------- | + | `--exclude-disabled` | | boolean | Exclude disabled module, service, test, and task configs from output. ### garden get eysi diff --git a/garden-service/src/commands/get/get-config.ts b/garden-service/src/commands/get/get-config.ts index f6526c2bbb..cc56829415 100644 --- a/garden-service/src/commands/get/get-config.ts +++ b/garden-service/src/commands/get/get-config.ts @@ -6,16 +6,41 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { Command, CommandResult, CommandParams } from "../base" +import { Command, CommandResult, CommandParams, BooleanParameter } from "../base" import { ConfigDump } from "../../garden" -export class GetConfigCommand extends Command { +const options = { + "exclude-disabled": new BooleanParameter({ + help: "Exclude disabled module, service, test, and task configs from output.", + }), +} + +type Opts = typeof options + +export class GetConfigCommand extends Command<{}, Opts> { name = "config" help = "Outputs the fully resolved configuration for this project and environment." + options = options - async action({ garden, log }: CommandParams): Promise> { + async action({ garden, log, opts }: CommandParams<{}, Opts>): Promise> { const config = await garden.dumpConfig(log) + if (opts["exclude-disabled"]) { + const filteredModuleConfigs = config.moduleConfigs + .filter((moduleConfig) => !moduleConfig.disabled) + .map((moduleConfig) => { + const filteredConfig = { + ...moduleConfig, + serviceConfigs: moduleConfig.serviceConfigs.filter((c) => !c.disabled), + taskConfigs: moduleConfig.taskConfigs.filter((c) => !c.disabled), + testConfigs: moduleConfig.testConfigs.filter((c) => !c.disabled), + } + return filteredConfig + }) + + config.moduleConfigs = filteredModuleConfigs + } + // TODO: do a nicer print of this by default log.info({ data: config }) diff --git a/garden-service/test/unit/src/commands/get/get-config.ts b/garden-service/test/unit/src/commands/get/get-config.ts index 8e2c60e898..1b23855ad5 100644 --- a/garden-service/test/unit/src/commands/get/get-config.ts +++ b/garden-service/test/unit/src/commands/get/get-config.ts @@ -10,6 +10,7 @@ import { expect } from "chai" import { makeTestGardenA, withDefaultGlobalOpts } from "../../../../helpers" import { GetConfigCommand } from "../../../../../src/commands/get/get-config" import { sortBy } from "lodash" +import { DEFAULT_API_VERSION } from "../../../../../src/constants" describe("GetConfigCommand", () => { const pluginName = "test-plugin" @@ -41,4 +42,358 @@ describe("GetConfigCommand", () => { expect(config).to.deep.equal(res.result) }) + + it("should exclude disabled module configs", async () => { + const garden = await makeTestGardenA() + const log = garden.log + const command = new GetConfigCommand() + + garden.setModuleConfigs([ + { + apiVersion: DEFAULT_API_VERSION, + allowPublish: false, + build: { dependencies: [] }, + disabled: true, + name: "a-disabled", + include: [], + outputs: {}, + path: garden.projectRoot, + serviceConfigs: [], + taskConfigs: [], + spec: { + services: [ + { + name: "service", + dependencies: [], + disabled: false, + spec: {}, + }, + ], + }, + testConfigs: [], + type: "test", + }, + { + apiVersion: DEFAULT_API_VERSION, + allowPublish: false, + build: { dependencies: [] }, + disabled: false, + include: [], + name: "b-enabled", + outputs: {}, + path: garden.projectRoot, + serviceConfigs: [], + taskConfigs: [], + spec: { + services: [ + { + name: "service", + dependencies: [], + disabled: false, + spec: {}, + }, + ], + }, + testConfigs: [], + type: "test", + }, + ]) + + const res = await command.action({ + garden, + log, + headerLog: log, + footerLog: log, + args: { provider }, + opts: withDefaultGlobalOpts({ "exclude-disabled": true }), + }) + + const providers = await garden.resolveProviders() + + // Remove the disabled config, the first one in the array + let expectedModuleConfigs = sortBy(await garden["resolveModuleConfigs"](log), "name").slice(1) + + const config = { + environmentName: garden.environmentName, + providers, + variables: garden.variables, + moduleConfigs: expectedModuleConfigs, + projectRoot: garden.projectRoot, + } + + expect(config).to.deep.equal(res.result) + }) + + it("should exclude disabled service configs", async () => { + const garden = await makeTestGardenA() + const log = garden.log + const command = new GetConfigCommand() + + garden.setModuleConfigs([ + { + apiVersion: DEFAULT_API_VERSION, + allowPublish: false, + build: { dependencies: [] }, + disabled: false, + name: "enabled", + include: [], + outputs: {}, + path: garden.projectRoot, + serviceConfigs: [], + taskConfigs: [], + spec: { + services: [ + { + name: "service-disabled", + dependencies: [], + disabled: true, + hotReloadable: false, + spec: {}, + }, + { + name: "service-enabled", + dependencies: [], + disabled: false, + hotReloadable: false, + spec: {}, + }, + ], + tasks: [ + { + name: "task-enabled", + dependencies: [], + disabled: false, + }, + ], + }, + testConfigs: [], + type: "test", + }, + ]) + + const res = await command.action({ + garden, + log, + headerLog: log, + footerLog: log, + args: { provider }, + opts: withDefaultGlobalOpts({ "exclude-disabled": true }), + }) + + const providers = await garden.resolveProviders() + + const expectedModuleConfigs = await garden["resolveModuleConfigs"](log) + // Remove the disabled service + expectedModuleConfigs[0].serviceConfigs = [ + { + name: "service-enabled", + dependencies: [], + disabled: false, + sourceModuleName: undefined, + spec: { + name: "service-enabled", + dependencies: [], + disabled: false, + hotReloadable: false, + spec: {}, + annotations: {}, + daemon: false, + ingresses: [], + env: {}, + limits: { + cpu: 1000, + memory: 1024, + }, + ports: [], + volumes: [], + }, + hotReloadable: false, + }, + ] + + const config = { + environmentName: garden.environmentName, + providers, + variables: garden.variables, + moduleConfigs: expectedModuleConfigs, + projectRoot: garden.projectRoot, + } + + expect(config).to.deep.equal(res.result) + }) + + it("should exclude disabled task configs", async () => { + const garden = await makeTestGardenA() + const log = garden.log + const command = new GetConfigCommand() + + garden.setModuleConfigs([ + { + apiVersion: DEFAULT_API_VERSION, + allowPublish: false, + build: { dependencies: [] }, + disabled: false, + name: "enabled", + include: [], + outputs: {}, + path: garden.projectRoot, + serviceConfigs: [], + taskConfigs: [], + spec: { + services: [ + { + name: "service", + dependencies: [], + disabled: false, + spec: {}, + }, + ], + tasks: [ + { + name: "task-disabled", + dependencies: [], + disabled: true, + }, + { + name: "task-enabled", + dependencies: [], + disabled: false, + }, + ], + }, + testConfigs: [], + type: "test", + }, + ]) + + const res = await command.action({ + garden, + log, + headerLog: log, + footerLog: log, + args: { provider }, + opts: withDefaultGlobalOpts({ "exclude-disabled": true }), + }) + + const providers = await garden.resolveProviders() + + const expectedModuleConfigs = await garden["resolveModuleConfigs"](log) + // Remove the disabled task + expectedModuleConfigs[0].taskConfigs = [ + { + name: "task-enabled", + dependencies: [], + disabled: false, + spec: { + name: "task-enabled", + dependencies: [], + disabled: false, + timeout: null, + env: {}, + }, + timeout: null, + }, + ] + + const config = { + environmentName: garden.environmentName, + providers, + variables: garden.variables, + moduleConfigs: expectedModuleConfigs, + projectRoot: garden.projectRoot, + } + + expect(config).to.deep.equal(res.result) + }) + + it("should exclude disabled test configs", async () => { + const garden = await makeTestGardenA() + const log = garden.log + const command = new GetConfigCommand() + + garden.setModuleConfigs([ + { + apiVersion: DEFAULT_API_VERSION, + allowPublish: false, + build: { dependencies: [] }, + disabled: false, + name: "enabled", + include: [], + outputs: {}, + path: garden.projectRoot, + serviceConfigs: [], + taskConfigs: [], + spec: { + services: [ + { + name: "service", + dependencies: [], + disabled: false, + spec: {}, + }, + ], + tasks: [ + { + name: "task-enabled", + dependencies: [], + disabled: false, + }, + ], + tests: [ + { + name: "test-enabled", + dependencies: [], + disabled: false, + }, + { + name: "test-disabled", + dependencies: [], + disabled: true, + }, + ], + }, + testConfigs: [], + type: "test", + }, + ]) + + const res = await command.action({ + garden, + log, + headerLog: log, + footerLog: log, + args: { provider }, + opts: withDefaultGlobalOpts({ "exclude-disabled": true }), + }) + + const providers = await garden.resolveProviders() + + const expectedModuleConfigs = await garden["resolveModuleConfigs"](log) + // Remove the disabled task + expectedModuleConfigs[0].testConfigs = [ + { + name: "test-enabled", + dependencies: [], + disabled: false, + spec: { + name: "test-enabled", + dependencies: [], + disabled: false, + timeout: null, + env: {}, + }, + timeout: null, + }, + ] + + const config = { + environmentName: garden.environmentName, + providers, + variables: garden.variables, + moduleConfigs: expectedModuleConfigs, + projectRoot: garden.projectRoot, + } + + expect(config).to.deep.equal(res.result) + }) })