diff --git a/core/src/config/render-template.ts b/core/src/config/render-template.ts index a1ff67410e..b43335abb1 100644 --- a/core/src/config/render-template.ts +++ b/core/src/config/render-template.ts @@ -139,6 +139,7 @@ export async function renderConfigTemplate({ context: templateContext, contextOpts: { allowPartial: true, + legacyAllowPartial: true, }, source: { yamlDoc, path: ["inputs"] }, }) @@ -213,7 +214,7 @@ async function renderModules({ const spec = resolveTemplateStrings({ value: m, context, - contextOpts: { allowPartial: true }, + contextOpts: { allowPartial: true, legacyAllowPartial: true }, source: { yamlDoc, path: ["modules", i] }, }) const renderConfigPath = renderConfig.internal.configFilePath || renderConfig.internal.basePath @@ -280,7 +281,7 @@ async function renderConfigs({ const partiallyResolvedTemplateConfigs = resolveTemplateStrings({ value: templateConfigs, context, - contextOpts: { allowPartial: true }, + contextOpts: { allowPartial: true, legacyAllowPartial: true }, source, }) diff --git a/core/src/config/workflow.ts b/core/src/config/workflow.ts index 856feeb2b4..0a40b5bdfa 100644 --- a/core/src/config/workflow.ts +++ b/core/src/config/workflow.ts @@ -380,6 +380,7 @@ export function resolveWorkflowConfig(garden: Garden, config: WorkflowConfig) { context, contextOpts: { allowPartial: true, + legacyAllowPartial: true, }, // TODO: Map inputs to their original YAML sources source: undefined, diff --git a/core/src/graph/actions.ts b/core/src/graph/actions.ts index a776920e60..1ca8f7d334 100644 --- a/core/src/graph/actions.ts +++ b/core/src/graph/actions.ts @@ -747,7 +747,7 @@ export const preprocessActionConfig = profileAsync(async function preprocessActi }, variables, }), - contextOpts: { allowPartial: true }, + contextOpts: { allowPartial: true, legacyAllowPartial: true }, // TODO: See about mapping this to the original variable sources source: undefined, }) @@ -765,7 +765,7 @@ export const preprocessActionConfig = profileAsync(async function preprocessActi }, variables: resolvedVariables, }), - contextOpts: { allowPartial: true }, + contextOpts: { allowPartial: true, legacyAllowPartial: true }, // TODO: See about mapping this to the original inputs source source: undefined, }) @@ -844,6 +844,7 @@ export const preprocessActionConfig = profileAsync(async function preprocessActi context: builtinFieldContext, contextOpts: { allowPartial: true, + legacyAllowPartial: true, }, source: { yamlDoc, path: [] }, }) diff --git a/core/src/resolve-module.ts b/core/src/resolve-module.ts index 422af69cba..2376a24a9a 100644 --- a/core/src/resolve-module.ts +++ b/core/src/resolve-module.ts @@ -540,7 +540,7 @@ export class ModuleResolver { const resolvedDeps = resolveTemplateStrings({ value: rawConfig.build.dependencies, context: configContext, - contextOpts: { allowPartial: true }, + contextOpts: { allowPartial: true, legacyAllowPartial: true }, // Note: We're not implementing the YAML source mapping for modules source: undefined, }) @@ -581,7 +581,7 @@ export class ModuleResolver { return resolveTemplateStrings({ value: inputs, context: configContext, - contextOpts: { allowPartial: true }, + contextOpts: { allowPartial: true, legacyAllowPartial: true }, // Note: We're not implementing the YAML source mapping for modules source: undefined, }) @@ -643,6 +643,7 @@ export class ModuleResolver { context: new GenericContext({ inputs }), contextOpts: { allowPartial: true, + legacyAllowPartial: true, }, // Note: We're not implementing the YAML source mapping for modules source: undefined, diff --git a/core/test/data/test-projects/config-templates-partial/garden.yml b/core/test/data/test-projects/config-templates-partial/garden.yml new file mode 100644 index 0000000000..e6f211a03f --- /dev/null +++ b/core/test/data/test-projects/config-templates-partial/garden.yml @@ -0,0 +1,36 @@ +apiVersion: garden.io/v1 +kind: Project +name: config-templates +environments: + - name: local +providers: + - name: exec +variables: + sync_targets: + test: ["foo", "bar"] + +--- + +kind: RenderTemplate +template: tpl +name: foo +inputs: + name: test + +--- + +kind: ConfigTemplate +name: tpl +inputsSchemaPath: schema.json +configs: + - kind: Build + type: exec + name: ${parent.name}-${inputs.name}-dt + include: [] + variables: + myDir: "${var.sync_root || '../../../'}${inputs.name}" + syncTargets: + - $concat: + $forEach: ${var.sync_targets[inputs.name] || []} + $return: + source: "${var.sync_root || '../../../'}${item.value}" diff --git a/core/test/data/test-projects/config-templates-partial/schema.json b/core/test/data/test-projects/config-templates-partial/schema.json new file mode 100644 index 0000000000..7d6f2c6d15 --- /dev/null +++ b/core/test/data/test-projects/config-templates-partial/schema.json @@ -0,0 +1,8 @@ +{ + "type": "object", + "properties": { + "name": { + "type": "string" + } + } +} diff --git a/core/test/unit/src/garden.ts b/core/test/unit/src/garden.ts index 73e3dd44ee..325d2b6bf4 100644 --- a/core/test/unit/src/garden.ts +++ b/core/test/unit/src/garden.ts @@ -80,6 +80,7 @@ import type { RunActionConfig } from "../../../src/actions/run.js" import type { ProjectResult } from "@garden-io/platform-api-types" import { ProjectStatus } from "@garden-io/platform-api-types" import { getCloudDistributionName } from "../../../src/cloud/util.js" +import { resolveAction } from "../../../src/graph/actions.js" const moduleDirName = dirname(fileURLToPath(import.meta.url)) @@ -3140,6 +3141,38 @@ describe("Garden", () => { expect(omit(workflow.internal, "yamlDoc")).to.eql(internal) }) + it("should not fail when input is used together with an unresolvable variable in the same template string", async () => { + const garden = await makeTestGarden(getDataDir("test-projects", "config-templates-partial")) + await garden.scanAndAddConfigs() + + const log = garden.log + + const graph = await garden.getConfigGraph({ log: garden.log, emit: false }) + + const resolved = await resolveAction({ + garden, + graph, + log, + action: graph.getActionByRef({ + kind: "Build", + name: "foo-test-dt", + }), + }) + + expect(resolved).to.exist + expect(resolved.getVariables()).to.deep.eq({ + myDir: "../../../test", + syncTargets: [ + { + source: "../../../foo", + }, + { + source: "../../../bar", + }, + ], + }) + }) + it("should throw on duplicate config template names", async () => { const garden = await makeTestGarden(getDataDir("test-projects", "duplicate-config-templates"))