Skip to content

Commit

Permalink
fix: resolve parts of template strings, even if another part cannot b…
Browse files Browse the repository at this point in the history
…e resolved yet. (#6751)

* fix: resolve parts of template strings, even if another part cannot be
resolved yet.

* test: add test case
  • Loading branch information
stefreak authored Jan 8, 2025
1 parent e6b06fc commit aabebbd
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 6 deletions.
5 changes: 3 additions & 2 deletions core/src/config/render-template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ export async function renderConfigTemplate({
context: templateContext,
contextOpts: {
allowPartial: true,
legacyAllowPartial: true,
},
source: { yamlDoc, path: ["inputs"] },
})
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -280,7 +281,7 @@ async function renderConfigs({
const partiallyResolvedTemplateConfigs = resolveTemplateStrings({
value: templateConfigs,
context,
contextOpts: { allowPartial: true },
contextOpts: { allowPartial: true, legacyAllowPartial: true },
source,
})

Expand Down
1 change: 1 addition & 0 deletions core/src/config/workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 3 additions & 2 deletions core/src/graph/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
})
Expand All @@ -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,
})
Expand Down Expand Up @@ -844,6 +844,7 @@ export const preprocessActionConfig = profileAsync(async function preprocessActi
context: builtinFieldContext,
contextOpts: {
allowPartial: true,
legacyAllowPartial: true,
},
source: { yamlDoc, path: [] },
})
Expand Down
5 changes: 3 additions & 2 deletions core/src/resolve-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
})
Expand Down Expand Up @@ -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,
})
Expand Down Expand Up @@ -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,
Expand Down
36 changes: 36 additions & 0 deletions core/test/data/test-projects/config-templates-partial/garden.yml
Original file line number Diff line number Diff line change
@@ -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}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"type": "object",
"properties": {
"name": {
"type": "string"
}
}
}
33 changes: 33 additions & 0 deletions core/test/unit/src/garden.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down Expand Up @@ -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"))

Expand Down

0 comments on commit aabebbd

Please sign in to comment.