diff --git a/core/src/commands/test.ts b/core/src/commands/test.ts index 6158f9c5ef..9e3d582a10 100644 --- a/core/src/commands/test.ts +++ b/core/src/commands/test.ts @@ -25,20 +25,23 @@ import { getTestTasks } from "../tasks/test" import { printHeader } from "../logger/util" import { startServer } from "../server/server" import { StringsParameter, BooleanParameter } from "../cli/params" +import { deline } from "../util/string" export const testArgs = { modules: new StringsParameter({ - help: - "The name(s) of the module(s) to test (skip to test all modules). " + - "Use comma as a separator to specify multiple modules.", + help: deline` + The name(s) of the module(s) to test (skip to test all modules). + Use comma as a separator to specify multiple modules. + `, }), } export const testOpts = { "name": new StringsParameter({ - help: - "Only run tests with the specfied name (e.g. unit or integ). " + - "Accepts glob patterns (e.g. integ* would run both 'integ' and 'integration')", + help: deline` + Only run tests with the specfied name (e.g. unit or integ). + Accepts glob patterns (e.g. integ* would run both 'integ' and 'integration'). + `, alias: "n", }), "force": new BooleanParameter({ @@ -51,6 +54,12 @@ export const testOpts = { alias: "w", cliOnly: true, }), + "skip-dependants": new BooleanParameter({ + help: deline` + When using the modules argument, only run tests for those modules (and skip tests in other modules with + dependencies on those modules). + `, + }), } type Args = typeof testArgs @@ -115,11 +124,16 @@ export class TestCommand extends Command { } const graph = await garden.getConfigGraph(log) - - const modules: GardenModule[] = args.modules - ? graph.withDependantModules(graph.getModules({ names: args.modules })) - : // All modules are included in this case, so there's no need to compute dependants. - graph.getModules() + const skipDependants = opts["skip-dependants"] + let modules: GardenModule[] + + if (args.modules) { + modules = skipDependants + ? graph.getModules({ names: args.modules }) + : graph.withDependantModules(graph.getModules({ names: args.modules })) + } else { + modules = graph.getModules() + } const filterNames = opts.name || [] const force = opts.force diff --git a/core/test/unit/src/commands/test.ts b/core/test/unit/src/commands/test.ts index 2ba3525a8c..42d47a517e 100644 --- a/core/test/unit/src/commands/test.ts +++ b/core/test/unit/src/commands/test.ts @@ -10,6 +10,7 @@ import { expect } from "chai" import { TestCommand } from "../../../../src/commands/test" import isSubset = require("is-subset") import { makeTestGardenA, taskResultOutputs, withDefaultGlobalOpts } from "../../../helpers" +import { ModuleConfig } from "../../../../src/config/module" describe("TestCommand", () => { const command = new TestCommand() @@ -30,6 +31,7 @@ describe("TestCommand", () => { "force": true, "force-build": true, "watch": false, + "skip-dependants": false, }), }) @@ -160,6 +162,7 @@ describe("TestCommand", () => { "force": true, "force-build": true, "watch": false, + "skip-dependants": false, }), }) @@ -192,6 +195,7 @@ describe("TestCommand", () => { "force": true, "force-build": true, "watch": false, + "skip-dependants": false, }), }) @@ -248,6 +252,7 @@ describe("TestCommand", () => { "force": true, "force-build": false, "watch": false, + "skip-dependants": false, }), }) @@ -284,6 +289,7 @@ describe("TestCommand", () => { "force": true, "force-build": false, "watch": false, + "skip-dependants": false, }), }) @@ -303,4 +309,88 @@ describe("TestCommand", () => { "test.module-b.unit", ]) }) + + it("should skip dependant modules if --skip-dependants is passed", async () => { + const garden = await makeTestGardenA() + const log = garden.log + + const moduleConfigs: ModuleConfig[] = [ + { + apiVersion: "garden.io/v0", + kind: "Module", + name: "module-a", + include: [], + build: { dependencies: [] }, + path: garden.projectRoot, + serviceConfigs: [], + disabled: false, + allowPublish: false, + spec: { + services: [{ name: "service-a" }], + tests: [ + { name: "unit", command: ["echo", "OK"] }, + { name: "integration", command: ["echo", "OK"], dependencies: ["service-a"] }, + ], + tasks: [], + build: { command: ["echo", "A"], dependencies: [] }, + }, + testConfigs: [], + type: "test", + taskConfigs: [], + }, + { + apiVersion: "garden.io/v0", + kind: "Module", + name: "module-b", + include: [], + build: { dependencies: [] }, + path: garden.projectRoot, + serviceConfigs: [], + disabled: false, + allowPublish: false, + spec: { + services: [{ name: "service-b" }], + tests: [ + { name: "unit", command: ["echo", "OK"] }, + { name: "integration", command: ["echo", "OK"], dependencies: ["service-a"] }, // <--- depends on service-a + ], + tasks: [], + build: { command: ["echo", "A"], dependencies: [] }, + }, + testConfigs: [], + type: "test", + taskConfigs: [], + }, + ] + + garden.setModuleConfigs(moduleConfigs) + + const { result, errors } = await command.action({ + garden, + log, + headerLog: log, + footerLog: log, + args: { modules: ["module-a"] }, + opts: withDefaultGlobalOpts({ + "name": undefined, + "force": true, + "force-build": false, + "watch": false, + "skip-dependants": true, // <---- + }), + }) + + if (errors) { + throw errors[0] + } + + expect(Object.keys(taskResultOutputs(result!)).sort()).to.eql([ + "build.module-a", + "deploy.service-a", + "get-service-status.service-a", + "stage-build.module-a", + "test.module-a.integration", + "test.module-a.unit", + ]) + }) }) diff --git a/docs/reference/commands.md b/docs/reference/commands.md index e3ba4b7056..971ab5d107 100644 --- a/docs/reference/commands.md +++ b/docs/reference/commands.md @@ -3262,10 +3262,11 @@ Examples: | Argument | Alias | Type | Description | | -------- | ----- | ---- | ----------- | - | `--name` | `-n` | array:string | Only run tests with the specfied name (e.g. unit or integ). Accepts glob patterns (e.g. integ* would run both 'integ' and 'integration') + | `--name` | `-n` | array:string | Only run tests with the specfied name (e.g. unit or integ). Accepts glob patterns (e.g. integ* would run both 'integ' and 'integration'). | `--force` | `-f` | boolean | Force re-test of module(s). | `--force-build` | | boolean | Force rebuild of module(s). | `--watch` | `-w` | boolean | Watch for changes in module(s) and auto-test. + | `--skip-dependants` | | boolean | When using the modules argument, only run tests for those modules (and skip tests in other modules with dependencies on those modules). #### Outputs