diff --git a/garden-service/src/commands/run/workflow.ts b/garden-service/src/commands/run/workflow.ts index c08219702e..520f05d354 100644 --- a/garden-service/src/commands/run/workflow.ts +++ b/garden-service/src/commands/run/workflow.ts @@ -97,6 +97,17 @@ export class RunWorkflowCommand extends Command { const stepBodyLog = outerLog.placeholder({ indent: 1, metadata }) const stepFooterLog = outerLog.placeholder({ indent: 1, metadata }) garden.log.setState({ metadata }) + + if (step.skip) { + stepBodyLog.setState(chalk.yellow(`Skipping`)) + result.steps[stepName] = { + number: index + 1, + outputs: {}, + log: "", + } + continue + } + let stepResult: CommandResult const inheritedOpts = cloneDeep(opts) diff --git a/garden-service/src/config/workflow.ts b/garden-service/src/config/workflow.ts index 98fe8e7027..3185673e3c 100644 --- a/garden-service/src/config/workflow.ts +++ b/garden-service/src/config/workflow.ts @@ -136,6 +136,7 @@ export interface WorkflowStepSpec { command?: string[] description?: string script?: string + skip?: boolean } export const workflowStepSchema = () => { @@ -175,7 +176,7 @@ export const workflowStepSchema = () => { .example(["run", "task", "my-task"]), description: joi.string().description("A description of the workflow step."), script: joi.string().description( - deline` + dedent` A bash script to run. Note that the host running the workflow must have bash installed and on path. It is considered to have run successfully if it returns an exit code of 0. Any other exit code signals an error, and the remainder of the workflow is aborted. @@ -183,6 +184,13 @@ export const workflowStepSchema = () => { The script may include template strings, including references to previous steps. ` ), + skip: joi + .boolean() + .default(false) + .description( + `Set to true to skip this step. Use this with template conditionals to skip steps for certain environments or scenarios.` + ) + .example("${environment.name != 'prod'}"), }) .xor("command", "script") .description("A workflow step. Must specify either `command` or `script` (but not both).") diff --git a/garden-service/test/unit/src/commands/run/workflow.ts b/garden-service/test/unit/src/commands/run/workflow.ts index 97918f7c6e..f3536d9656 100644 --- a/garden-service/test/unit/src/commands/run/workflow.ts +++ b/garden-service/test/unit/src/commands/run/workflow.ts @@ -473,6 +473,28 @@ describe("RunWorkflowCommand", () => { expect(result?.steps["step-1"].log).to.equal(garden.projectRoot) }) + it("should skip disabled steps", async () => { + garden.setWorkflowConfigs([ + { + apiVersion: DEFAULT_API_VERSION, + name: "workflow-a", + kind: "Workflow", + path: garden.projectRoot, + files: [], + steps: [{ script: "pwd" }, { script: "echo fail!; exit 1", skip: true }], + }, + ]) + + await cmd.action({ ...defaultParams, args: { workflow: "workflow-a" } }) + + const { result, errors } = await cmd.action({ ...defaultParams, args: { workflow: "workflow-a" } }) + + expect(result).to.exist + expect(errors).to.not.exist + expect(result?.steps["step-2"].outputs).to.eql({}) + expect(result?.steps["step-2"].log).to.equal("") + }) + it("should collect log outputs, including stderr, from a script step", async () => { garden.setWorkflowConfigs([ { diff --git a/garden-service/test/unit/src/config/workflow.ts b/garden-service/test/unit/src/config/workflow.ts index 0a35d809fc..d8d76ee9d4 100644 --- a/garden-service/test/unit/src/config/workflow.ts +++ b/garden-service/test/unit/src/config/workflow.ts @@ -41,7 +41,10 @@ describe("resolveWorkflowConfig", () => { name: "workflow-a", path: "/tmp/foo", description: "Sample workflow", - steps: [{ description: "Deploy the stack", command: ["deploy"] }, { command: ["test"] }], + steps: [ + { description: "Deploy the stack", command: ["deploy"], skip: false }, + { command: ["test"], skip: false }, + ], triggers: [ { environment: "local", @@ -68,7 +71,10 @@ describe("resolveWorkflowConfig", () => { name: "workflow-a", path: "/tmp/foo", description: "Secret: ${secrets.foo}, var: ${variables.foo}", - steps: [{ description: "Deploy the stack", command: ["deploy"] }, { command: ["test"] }], + steps: [ + { description: "Deploy the stack", command: ["deploy"], skip: false }, + { command: ["test"], skip: false }, + ], } expect(resolveWorkflowConfig(garden, config)).to.eql({ @@ -87,7 +93,14 @@ describe("resolveWorkflowConfig", () => { steps: [{ description: "Deploy the stack", command: ["deploy"] }, { command: ["test"] }], } - expect(resolveWorkflowConfig(garden, config)).to.eql({ ...config, ...defaults }) + expect(resolveWorkflowConfig(garden, config)).to.eql({ + ...config, + ...defaults, + steps: [ + { description: "Deploy the stack", command: ["deploy"], skip: false }, + { command: ["test"], skip: false }, + ], + }) }) it("should throw if a step uses an invalid/unsupported command", async () => {