diff --git a/core/src/garden.ts b/core/src/garden.ts index e43e36ca5f..62b97d7205 100644 --- a/core/src/garden.ts +++ b/core/src/garden.ts @@ -172,6 +172,7 @@ import { styles } from "./logger/styles.js" import { renderDuration } from "./logger/util.js" import { getCloudDistributionName, getCloudLogSectionName } from "./util/cloud.js" import { makeDocsLinkStyled } from "./docs/common.js" +import { ActionConfigContext } from "./config/template-contexts/actions.js" const defaultLocalAddress = "localhost" @@ -260,9 +261,16 @@ export class Garden { public log: Log private gardenInitLog?: Log private loadedPlugins?: GardenPluginSpec[] + + /** + * These 3 fields store the raw action configs, + * i.e. unresolved action-, module-, and workflow configs detected by {@link #scanAndAddConfigs} + * loaded from the disk. + */ protected readonly actionConfigs: ActionConfigMap protected readonly moduleConfigs: ModuleConfigMap protected readonly workflowConfigs: WorkflowConfigMap + protected configPaths: Set private resolvedProviders: { [key: string]: Provider } protected readonly state: GardenInstanceState @@ -1501,6 +1509,35 @@ export class Garden { }) } + private evaluateDisabledFlag(config: BaseActionConfig): boolean { + // It can be a template string that must be resolved at this stage + const disabledFlag = config.disabled as boolean | string | undefined + + if (disabledFlag === undefined) { + return false + } + + if (typeof disabledFlag === "boolean") { + return disabledFlag + } + + const context = new ActionConfigContext({ + garden: this, + config, + thisContextParams: { + name: config.name, + // TODO: resolve this if necessary + mode: "default", + }, + variables: this.variables, + }) + + return resolveTemplateString({ + string: disabledFlag, + context, + }) + } + /** * Add an action config to the context, after validating and calling the appropriate configure plugin handler. */ @@ -1509,6 +1546,9 @@ export class Garden { const key = actionReferenceToString(config) const existing = this.actionConfigs[config.kind][config.name] + // Resolve the actual values of the `disabled` flag + config.disabled = this.evaluateDisabledFlag(config) + if (existing) { if (actionIsDisabled(config, this.environmentName)) { this.log.silly( diff --git a/core/test/data/test-projects/disabled-action-with-duplicate-name/project.garden.yml b/core/test/data/test-projects/disabled-action-with-duplicate-name/project.garden.yml new file mode 100644 index 0000000000..efe83351f9 --- /dev/null +++ b/core/test/data/test-projects/disabled-action-with-duplicate-name/project.garden.yml @@ -0,0 +1,10 @@ +apiVersion: garden.io/v1 +kind: Project +name: disabled-action-with-duplicate-name +defaultEnvironment: local +environments: + - name: local + - name: remote +providers: + - name: exec + environments: [ local, remote ] diff --git a/core/test/data/test-projects/disabled-action-with-duplicate-name/runs.garden.yml b/core/test/data/test-projects/disabled-action-with-duplicate-name/runs.garden.yml new file mode 100644 index 0000000000..1dfb6f9d14 --- /dev/null +++ b/core/test/data/test-projects/disabled-action-with-duplicate-name/runs.garden.yml @@ -0,0 +1,15 @@ +kind: Run +name: run-script +type: exec +disabled: "${environment.name != 'local'}" +spec: + command: ["sh", "-c", "echo 'Hello from local'"] + +--- + +kind: Run +name: run-script +type: exec +disabled: "${environment.name != 'remote'}" +spec: + command: ["sh", "-c", "echo 'Hello from remote'"] diff --git a/core/test/unit/src/garden.ts b/core/test/unit/src/garden.ts index f419c7c82d..c3adf8e6a6 100644 --- a/core/test/unit/src/garden.ts +++ b/core/test/unit/src/garden.ts @@ -3041,6 +3041,17 @@ describe("Garden", () => { expect(omit(test.internal, "yamlDoc")).to.eql(internal) }) + it("should resolve disabled flag in actions and allow two actions with same key if one is disabled", async () => { + const garden = await makeTestGarden(getDataDir("test-projects", "disabled-action-with-duplicate-name")) + const graph = await garden.getConfigGraph({ log: garden.log, emit: false }) + + // There are 2 'run-script' actions defined in the project, one per environment. + // This test uses 'local' environment, so the action for 'remote' environment should be disabled and skipped. + const runScript = graph.getRun("run-script") + expect(runScript.isDisabled()).to.be.false + expect(runScript.getConfig().spec.command).to.eql(["sh", "-c", "echo 'Hello from local'"]) + }) + it("should resolve actions from templated config templates", async () => { const garden = await makeTestGarden(getDataDir("test-projects", "config-templates-with-templating")) await garden.scanAndAddConfigs() @@ -3069,6 +3080,7 @@ describe("Garden", () => { kind: "Run", type: "exec", name: runNameA, + disabled: false, spec: { command: ["echo", runNameA], }, @@ -3081,6 +3093,7 @@ describe("Garden", () => { kind: "Run", type: "exec", name: runNameB, + disabled: false, spec: { command: ["echo", runNameB], },