Skip to content

Commit

Permalink
perf: improve preprocess action perf by only resolving template strin…
Browse files Browse the repository at this point in the history
…gs when absolutely needed (#6745)

* perf: improve preprocess action perf by capturing context instead of
partially resolving template strings

* perf: use layered context and capture context instead of eager variable merging

* chore: fix some issues

* fix: layered context implementation and serialisation of partially
resolved values

* perf: make sure it resolves and improve performance further

* chore: remove yaml highlighting

The yaml highlighting did not work in production builds anyway and removing this functionality made it easier to compare performance between production builds and the dev build for commands like `get graph`.

* perf: do not call `resolveTemplateString` anymore, use `deepEvaluate` instead.

* chore: do not validate providers if not fully resolved yet.

* chore: remove `resolveTemplateStrings` and make sure that the template tests pass

* chore: fix docs generation

* chore: fix build by not ignoring parser.d.ts

* chore: fix vote example

* chore: fix bunch of tests

* fix: print correct wrapped error stack in tests

* chore: detect invalid keyed access of unresolved template values

fail early if we access an unresolved template value

* chore: change structural operator implementation to allow partial
evaluation

* chore: also detect unpermitted write access to unresolved template value

* fix: fix early provider resolution when resolving Garden params

* refactor: introduce type `UnresolvedProviderConfig`

* chore: fix provider config

Co-authored-by: Vladimir Vagaytsev <vvagaytsev@users.noreply.github.com>

* chore(template): primitives for partial resolution needed for module resolution

* chore: first step making module resolver work

* test: add extra test cases for template string access protection

* chore: fix lint errors

* chore: enhance error handling

* chore: add `toString()` for unresolved template values

* fix: fix the processing order in the context resolution loop

* chore: helper function to serialise unresolved template values in tests

Co-authored-by: Steffen Neubauer <steffen@garden.io>

* test: fix one test failure

* chore: fix more bugs

* refactor: introduce named type for symbol `CONTEXT_RESOLVE_KEY_NOT_FOUND`

* test: fix assertions in provider configuration tests

* chore: rewrite ConfigContext.resolve

* chore: do not pass unresolved action variables to configure handler (to avoid problems joi validation issues)

* chore: fix more tests and reintroduce nodePath

* chore: fix all ConfigContext tests

* chore: fix BuildCommand tests

* chore: fix a symlink test

* chore: fix CustomCommandWrapper tests

* chore: fix e2e test templated-k8s-container

* chore: make sure to forward crashes in prepareModuleResource

* chore: fix lint errors

* chore: fix templated-k8s-container-modules by skipping early prepareBuildDependencies

* chore: uncomment object freeze in parseTemplateCollection to fix some tests

* chore: fix "should correctly parse" test

* test: fix tests in RunWorkflowCommand

* chore: fix command error handling tests

* chore: fix further tests

* chore: fix output test

* refactor(test): parse whole workflow configs as template values

* chore: fix lint issues

* docs: re-generate docs

* test: fix test crashes

* test: fix assertions

* chore: fix some tests by not cloning actions

* test: fix crash in pickEnvironment tests

* chore: fix lint issues

* test: fix some test crashes in `scanAndAddConfigs`

* test: fix some test crashes in `getConfigGraph`

* test: fix template string assertion

* test: fix assertions for variables

* test: fix some assertions in template-string.ts

* test: fix some assertions in template-string.ts

* fix: process `$concat` correctly in `$forEach`

* fix: add work-around for nodejs exit 0 crash

* fix: parse template strings in project config tests

* fix: resolveProjectConfig test

* fix: throw on missing secret keys

* test: fix tests for `getActionTemplateReferences`

* fix: more informative message if no keys are available in the context

* test: fix assertions for "should handle keys with dots and unresolvable member expressions correctly"

* fix: update plugin context schema

* test: fix variable assertions in "pickEnvironment"

* fix: evaluate all values that do not have essential runtime references in partiallyEvaluateModule

(The comparison was inverted before)

* test: make ResolveActionTask pass

* test: fix default providers definition in test helpers

* chore: fix resolveWorkflowConfig tests

* fix: partiallyEvaluateModule accidentally compared the wrong thing

* fix: further test cases "ModuleResolver"

* test: trivial assertion corrections in "DefaultEnvironmentContext"

* test: fix assertions in provider configuration tests

Reverts wrong assertion changes made in 50e6d90.

* fix: set provider path before calling `configureProvider` handler

This fixes the test failure in "Garden.'resolveProviders.should call a configureProvider handler if applicable'"

* Revert "fix: set provider path before calling `configureProvider` handler"

This reverts commit 5e10469.

* test: fix assertion in "resolveProviders.should call a configureProvider handler if applicable"

* fix: remove unnecessary hack in `action.disable` flag resolution

* chore: extract defaults from input schema (best-effort) so we can apply the schema during action resolution

* fix: build

* fix: do not use capture in `renderModules`

* fix: partial module resolution dependency detection / BuildCommand tests

* test: remove test "should normalize build dependencies" - prepareModuleResource does not normalise build deps anymore.

* test: serialise unresolved templates before using expect

* fix: test "should remove null values in provider configs"

* fix: resolveConfigTemplate tests

* fix: make a couple of renderConfigTemplate tests work

* fix: ensure right-to-left the order of precedence in `LayeredContext`

* fix: renderConfigTemplate tests

* Revert "fix: remove unnecessary hack in `action.disable` flag resolution"

This reverts commit 3247a3c.

* fix: test "should resolve template strings in project source definitions"

* fix: test "should return a different version for a module when a variable used by it changes"

* chore: update assertions in test "should resolve modules from config templates and any modules referencing them"

* fix: test "sets variables for the action"

* fix: test "should respect the action variables < action varfile < CLI var precedence order"

* fix: test "should resolve disabled flag in actions and allow two actions with same key if one is disabled"

* fix: test should resolve actions from config templates

* chore: remove unused and misleading internal flag

* fix: "preprocessActionConfig" tests

* fix: rehydrate template strings after converting modules to actions

* fix: do not parse template on already parsed module

* fix: do early module spec validation only if inputs are resolved

* fix: do early module spec validation only if inputs are resolved

Follow-up fix for 57d968e.

* fix: perform toJSON serialization only for unresolved template values

* test: fix tests in "resolveProjectOutputs"

* chore: fix lint errors

* fix: enforce correct variable precedence centrally and make sure version calculation is only affected if the variable is used. fixes #3473

* fix: do not validate BaseAction instances in joi augmentGraph schema

Otherwise joi

* fix: additional test fixes

* refactor: use  @ts-expect-error todo comments instead of as unknown casts

* chore: (experiment) remove hack with `then` field that was referenced by js engine

* chore: fix lint issues

* chore: wrap config error into template string error for better ux

To be able to locate the problematic piece of the configuration.

* chore(test): lowercase actual err message only once

* test: fix error message assertions

Template string errors are rendered differently and include snippets of the original config.

* test: follow-up fix for test assertion

* test: restore secrets value in test data

The value was accidentally removed in 7aa19b6.

* refactor: declare context properties as readonly if possible

* test: parse template collection in exec plugin tests

Fixes "actions should be able to access exec provider script result"

* test: fix setup and assertions in k8s and helm integ tests

* chore: fix lint error

* chore: fix kubernetes-type handlers integ tests

* fix: throwOnMissingSecretKeys should not throw an error if secrets are optional in an expression

* test: restore original k8s resource state after each test

* test: separate context for tests w/o artifacts + avoid unnecessary tmp dir creation

* test: use standalone lightweight project to test PodRunner

We do not need to resolve graph for the heavy project defined in `test-project/container`

* chore(test): extract helper to create empty project with local-kubernetes provider

* test: simpler and faster test setup for ingress-controller.ts

* test: simpler and faster test setup for ingress.ts

* fix: integ test "should resolve fine with null values for manifests in
spec.files"

* refactor: extract local var

* test: prevent unsafe config modifications

Some actions are used by multiple tests and should not be modified to avoid dirty shared data state.

* test: fix test action spec definition

Follow-up for the prev commit

* test: prevent unsafe config modifications in "should only show logs returned from failed containers"

Some actions are used by multiple tests and should not be modified to avoid dirty shared data state.

* test: prevent unsafe config modifications in "should return events and Pod logs if the Pod can't start"

Some actions are used by multiple tests and should not be modified to avoid dirty shared data state.

* test: wrap logs- and events-test in a context

* chore: split tests to 2 semantic contexts

* test: avoid dirty state if the shared helm configs and resources

* test: add todo-comment

* chore: fix lint issues

* test: correct deploy action type + removed obsolete delete statement

* test: declare "getWorkloadPods" as top-level spec

* test: simplify test setup for "getWorkloadPods"

* chore: check if this helps with the timeouts

* chore: gather more information about nature of the hang

* Revert "chore: check if this helps with the timeouts"

This reverts commit a43d75c.

* test: run helm tests in different namespaces

Avoid interference by running helm tests in different namespaces.

* chore: check if this helps with the timeouts

* test: don't cache garden instances

* test: fix helm project setup in AEC test

* chore(test): simplify `getContainerTestGarden` helper

* chore: change the type of `var` field in some var contexts

* chore(test): clear diagnostic interval in `afterAll` global hook

* Revert "test: run helm tests in different namespaces"

This reverts commit 56847c4

* Revert "test: fix helm project setup in AEC test"

This reverts commit 4b46b45.

* chore: fix lint errors

* fix: correct rendering of available keys when key is missing in the context

* docs: update config-resolution.md

* test: restore allowPartial tests and refactor escaping code

* fix: do not use legacyAllowPartial in module resolution

It's very difficult to support the complexity of legacyAllowPartial combined with structural template operators. The code will be easier to maintain this way. The benefit is only marginal, and the old code also struggled with ForEach expressions in the module resolution.

* fix: use simpler context in caprturing

Co-authored-by: Steffen Neubauer <steffen@garden.io>

* chore: actualise todo-comment

* chore: fix lint issues

* chore: typos and spacing

* fix: restore key highlighting in template error messages

---------

Co-authored-by: Vladimir Vagaytsev <10628074+vvagaytsev@users.noreply.github.com>
Co-authored-by: Vladimir Vagaytsev <vvagaytsev@users.noreply.github.com>
  • Loading branch information
3 people authored Jan 31, 2025
1 parent 576c1c1 commit c968c61
Show file tree
Hide file tree
Showing 160 changed files with 7,878 additions and 6,213 deletions.
1 change: 0 additions & 1 deletion core/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ dist/
src/**/*.js
src/**/*.map
src/**/*.d.ts
!src/template-string/parser.d.ts
support/**/*.js
support/**/*.map
support/**/*.d.ts
Expand Down
13 changes: 6 additions & 7 deletions core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@
"@opentelemetry/sdk-node": "^0.57.0",
"@opentelemetry/sdk-trace-base": "^1.27.0",
"@opentelemetry/semantic-conventions": "^1.21.0",
"@trpc/client": "^11.0.0-next-beta.308",
"@trpc/server": "^11.0.0-next-beta.308",
"@scg82/exit-hook": "^3.4.1",
"@segment/analytics-node": "^2.2.0",
"@trpc/client": "^11.0.0-next-beta.308",
"@trpc/server": "^11.0.0-next-beta.308",
"@types/ws": "^8.5.10",
"ajv": "^8.17.1",
"ajv-formats": "^3.0.1",
Expand All @@ -52,7 +52,6 @@
"chalk": "^5.3.0",
"chokidar": "^3.6.0",
"ci-info": "^4.1.0",
"cli-highlight": "^2.1.11",
"cli-table3": "^0.6.5",
"cli-truncate": "^4.0.0",
"cpy": "^11.1.0",
Expand Down Expand Up @@ -251,15 +250,15 @@
"utility-types": "^3.11.0"
},
"scripts": {
"build": "mkdir -p build/src/template-string && peggy src/template-string/parser.pegjs --output build/src/template-string/parser.js --format es",
"build": "mkdir -p build/src/template && peggy src/template/parser.pegjs --output build/src/template/parser.js --format es",
"check-package-lock": "git diff-index --quiet HEAD -- package-lock.json || (echo 'package-lock.json is dirty!' && exit 1)",
"check-types": "tsc -p . --noEmit",
"clean": "shx rm -rf build",
"dev": "nodemon --watch src/template-string/*.pegjs --exec npm run build",
"dev": "nodemon --watch src/template/*.pegjs --exec npm run build",
"fix-format": "npm run lint -- --fix --quiet",
"lint": "eslint --ignore-pattern 'src/lib/**' --ext .ts,.tsx src/ test/",
"migration:generate": "typeorm migration:generate --config ormconfig.js -n",
"_integ": "mocha --config .mocharc.integ.yml",
"_integ": "GARDEN_TESTS_LOG_LEVEL=${GARDEN_TESTS_LOG_LEVEL:-verbose} GARDEN_TESTS_SHOW_LOGS=${GARDEN_TESTS_LOG_LEVEL:-1} mocha --config .mocharc.integ.yml",
"integ-kind": "GARDEN_INTEG_TEST_MODE=local GARDEN_SKIP_TESTS=\"cluster-buildkit cluster-buildkit-rootless kaniko remote-only\" npm run _integ --",
"integ-local": "GARDEN_INTEG_TEST_MODE=local GARDEN_SKIP_TESTS=\"remote-only\" npm run _integ --",
"integ-minikube": "GARDEN_INTEG_TEST_MODE=local GARDEN_SKIP_TESTS=\"remote-only\" npm run _integ --",
Expand All @@ -277,4 +276,4 @@
"fsevents": "^2.3.3"
},
"gitHead": "b0647221a4d2ff06952bae58000b104215aed922"
}
}
52 changes: 39 additions & 13 deletions core/src/actions/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import titleize from "titleize"
import type { ConfigGraph, GetActionOpts, PickTypeByKind, ResolvedConfigGraph } from "../graph/config-graph.js"
import type { ActionReference, DeepPrimitiveMap } from "../config/common.js"
import type { ActionReference } from "../config/common.js"
import {
createSchema,
includeGuideLink,
Expand All @@ -34,7 +34,6 @@ import { actionOutputsSchema } from "../plugin/handlers/base/base.js"
import type { GraphResult, GraphResults } from "../graph/results.js"
import type { RunResult } from "../plugin/base.js"
import { Memoize } from "typescript-memoize"
import cloneDeep from "fast-copy"
import { flatten, fromPairs, isString, memoize, omit, sortBy } from "lodash-es"
import { ActionConfigContext, ActionSpecContext } from "../config/template-contexts/actions.js"
import { relative } from "path"
Expand Down Expand Up @@ -67,6 +66,10 @@ import type { LinkedSource } from "../config-store/local.js"
import type { BaseActionTaskParams, ExecuteTask } from "../tasks/base.js"
import { styles } from "../logger/styles.js"
import { dirname } from "node:path"
import type { ResolvedTemplate } from "../template/types.js"
import type { WorkflowConfig } from "../config/workflow.js"
import type { VariablesContext } from "../config/template-contexts/variables.js"
import { deepMap } from "../util/objects.js"

// TODO: split this file

Expand Down Expand Up @@ -114,7 +117,7 @@ const actionSourceSpecSchema = createSchema({
meta: { name: "action-source", advanced: true, templateContext: ActionConfigContext },
})

export const includeExcludeSchema = memoize(() => joi.array().items(joi.posixPath().allowGlobs().subPathOnly()))
export const includeExcludeSchema = memoize(() => joi.sparseArray().items(joi.posixPath().allowGlobs().subPathOnly()))

const varfileName = "my-action.${environment.name}.env"

Expand Down Expand Up @@ -370,7 +373,7 @@ export abstract class BaseAction<
protected readonly projectRoot: string
protected readonly _supportedModes: ActionModes
protected readonly _treeVersion: TreeVersion
protected readonly variables: DeepPrimitiveMap
protected readonly variables: VariablesContext

constructor(protected readonly params: ActionWrapperParams<C>) {
this.kind = params.config.kind
Expand Down Expand Up @@ -545,12 +548,12 @@ export abstract class BaseAction<
const dependencyVersions = fromPairs(depPairs)

const configVersion = this.configVersion()
const versionString =
versionStringPrefix + hashStrings([configVersion, this._treeVersion.contentHash, ...flatten(sortedDeps)])
const sourceVersion = this._treeVersion.contentHash
const versionString = versionStringPrefix + hashStrings([configVersion, sourceVersion, ...flatten(sortedDeps)])

return {
configVersion,
sourceVersion: this._treeVersion.contentHash,
sourceVersion,
versionString,
dependencyVersions,
files: this._treeVersion.files,
Expand Down Expand Up @@ -583,7 +586,7 @@ export abstract class BaseAction<
}
}

getVariables(): DeepPrimitiveMap {
getVariablesContext(): VariablesContext {
return this.variables
}

Expand All @@ -598,7 +601,9 @@ export abstract class BaseAction<
getConfig(): C
getConfig<K extends keyof C>(key: K): C[K]
getConfig(key?: keyof C["spec"]) {
return cloneDeep(key ? this._config[key] : this._config)
const res = key ? this._config[key] : this._config
// basically a clone that leaves unresolved template values intact as-is, as they are immutable.
return deepMap(res, (v) => v) as typeof res
}

/**
Expand Down Expand Up @@ -735,7 +740,9 @@ export interface ResolvedActionExtension<

getOutputs(): StaticOutputs

getVariables(): DeepPrimitiveMap
getVariablesContext(): VariablesContext

getResolvedVariables(): Record<string, ResolvedTemplate>
}

// TODO: see if we can avoid the duplication here with ResolvedBuildAction
Expand Down Expand Up @@ -806,7 +813,9 @@ export abstract class ResolvedRuntimeAction<
getSpec(): Config["spec"]
getSpec<K extends keyof Config["spec"]>(key: K): Config["spec"][K]
getSpec(key?: keyof Config["spec"]) {
return cloneDeep(key ? this._config.spec[key] : this._config.spec)
const res = key ? this._config.spec[key] : this._config.spec
// basically a clone that leaves unresolved template values intact as-is, as they are immutable.
return deepMap(res, (v) => v) as typeof res
}

getOutput<K extends keyof StaticOutputs>(key: K): GetOutputValueType<K, StaticOutputs, RuntimeOutputs> {
Expand All @@ -816,6 +825,10 @@ export abstract class ResolvedRuntimeAction<
getOutputs() {
return this._staticOutputs
}

getResolvedVariables(): Record<string, ResolvedTemplate> {
return this.params.resolvedVariables
}
}

export interface ExecutedActionExtension<
Expand Down Expand Up @@ -898,7 +911,10 @@ export function getSourceAbsPath(basePath: string, sourceRelPath: string) {
return joinWithPosix(basePath, sourceRelPath)
}

export function describeActionConfig(config: ActionConfig) {
export function describeActionConfig(config: ActionConfig | WorkflowConfig) {
if (config.kind === "Workflow") {
return `${config.kind} ${config.name}`
}
const d = `${config.type} ${config.kind} ${config.name}`
if (config.internal?.moduleName) {
return d + ` (from module ${config.internal?.moduleName})`
Expand Down Expand Up @@ -944,8 +960,18 @@ export function actionIsDisabled(config: ActionConfig, environmentName: string):
* see {@link VcsHandler.getTreeVersion} and {@link VcsHandler.getFiles}.
* - The description field is just informational, shouldn't affect execution.
* - The disabled flag is not relevant to the config version, since it only affects execution.
* - The variables and varfiles are only relevant if they have an effect on a relevant piece of configuration and thus can be omitted.
*/
const nonVersionedActionConfigKeys = ["internal", "source", "include", "exclude", "description", "disabled"] as const
const nonVersionedActionConfigKeys = [
"internal",
"source",
"include",
"exclude",
"description",
"disabled",
"variables",
"varfiles",
] as const
export type NonVersionedActionConfigKey = keyof Pick<BaseActionConfig, (typeof nonVersionedActionConfigKeys)[number]>

export function getActionConfigVersion<C extends BaseActionConfig>(config: C) {
Expand Down
5 changes: 5 additions & 0 deletions core/src/actions/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { DEFAULT_BUILD_TIMEOUT_SEC } from "../constants.js"
import { createBuildTask } from "../tasks/build.js"
import type { BaseActionTaskParams, ExecuteTask } from "../tasks/base.js"
import { ResolveActionTask } from "../tasks/resolve-action.js"
import type { ResolvedTemplate } from "../template/types.js"

export interface BuildCopyFrom {
build: string
Expand Down Expand Up @@ -247,6 +248,10 @@ export class ResolvedBuildAction<
getOutputs() {
return this._staticOutputs
}

getResolvedVariables(): Record<string, ResolvedTemplate> {
return this.params.resolvedVariables
}
}

export class ExecutedBuildAction<
Expand Down
8 changes: 5 additions & 3 deletions core/src/actions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import type { ValidResultType } from "../tasks/base.js"
import type { BaseGardenResource, GardenResourceInternalFields } from "../config/base.js"
import type { LinkedSource } from "../config-store/local.js"
import type { GardenApiVersion } from "../constants.js"
import type { ResolvedTemplate } from "../template/types.js"
import type { VariablesContext } from "../config/template-contexts/variables.js"

// TODO: split this file

Expand Down Expand Up @@ -63,7 +65,6 @@ export interface BaseActionConfig<K extends ActionKind = ActionKind, T = string,
// -> No templating is allowed on these.
internal: GardenResourceInternalFields & {
groupName?: string
resolved?: boolean // Set to true if no resolution is required, e.g. set for actions converted from modules
treeVersion?: TreeVersion // Set during module resolution to avoid duplicate scanning for Build actions
// For forwards-compatibility, applied on actions returned from module conversion handlers
remoteClonePath?: string
Expand Down Expand Up @@ -170,7 +171,7 @@ export interface ActionWrapperParams<C extends BaseActionConfig> {
remoteSourcePath: string | null
supportedModes: ActionModes
treeVersion: TreeVersion
variables: DeepPrimitiveMap
variables: VariablesContext
}

export interface ResolveActionParams<C extends BaseActionConfig, StaticOutputs extends Record<string, unknown> = any> {
Expand All @@ -181,7 +182,8 @@ export interface ResolveActionParams<C extends BaseActionConfig, StaticOutputs e
spec: C["spec"]
staticOutputs: StaticOutputs
inputs: DeepPrimitiveMap
variables: DeepPrimitiveMap
variables: VariablesContext
resolvedVariables: Record<string, ResolvedTemplate>
}

export type ResolvedActionWrapperParams<
Expand Down
34 changes: 15 additions & 19 deletions core/src/commands/custom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
*/

import { execa } from "execa"
import { apply as jsonMerge } from "json-merge-patch"
import cloneDeep from "fast-copy"
import { keyBy, mapValues, flatten } from "lodash-es"
import { parseCliArgs, prepareMinimistOpts } from "../cli/helpers.js"
import type { Parameter, ParameterObject } from "../cli/params.js"
Expand All @@ -21,7 +19,6 @@ import { CustomCommandContext } from "../config/template-contexts/custom-command
import { validateWithPath } from "../config/validation.js"
import type { GardenError } from "../exceptions.js"
import { ConfigurationError, RuntimeError, InternalError, toGardenError } from "../exceptions.js"
import { resolveTemplateStrings } from "../template-string/template-string.js"
import { listDirectory, isConfigFilename } from "../util/fs.js"
import type { CommandParams, CommandResult, PrintHeaderParams } from "./base.js"
import { Command } from "./base.js"
Expand All @@ -32,6 +29,8 @@ import { getBuiltinCommands } from "./commands.js"
import type { Log } from "../logger/log-entry.js"
import { getTracePropagationEnvVars } from "../util/open-telemetry/propagation.js"
import { styles } from "../logger/styles.js"
import { deepEvaluate } from "../template/evaluate.js"
import { VariablesContext } from "../config/template-contexts/variables.js"

function convertArgSpec(spec: CustomCommandOption) {
const params = {
Expand Down Expand Up @@ -112,19 +111,18 @@ export class CustomCommandWrapper extends Command {
// Strip the command name and any specified arguments off the $rest variable
const rest = removeSlice(parsed._unknown, this.getPath()).slice(Object.keys(this.arguments || {}).length)

const yamlDoc = this.spec.internal.yamlDoc

// Render the command variables
const variablesContext = new CustomCommandContext({ ...garden, args, opts, rest })
const commandVariables = resolveTemplateStrings({
value: this.spec.variables,
context: variablesContext,
source: { yamlDoc, path: ["variables"] },
})
const variables: any = jsonMerge(cloneDeep(garden.variables), commandVariables)

const variableContext = new CustomCommandContext({ ...garden, args, opts, variables: garden.variables, rest })

// Make a new template context with the resolved variables
const commandContext = new CustomCommandContext({ ...garden, args, opts, variables, rest })
const commandContext = new CustomCommandContext({
...garden,
args,
opts,
variables: VariablesContext.forCustomCommand(garden, this.spec, variableContext),
rest,
})

const result: CustomCommandResult = {}
const errors: GardenError[] = []
Expand All @@ -134,10 +132,9 @@ export class CustomCommandWrapper extends Command {
const startedAt = new Date()

const exec = validateWithPath<CommandResource["exec"]>({
config: resolveTemplateStrings({
value: this.spec.exec,
config: deepEvaluate(this.spec.exec, {
context: commandContext,
source: { yamlDoc, path: ["exec"] },
opts: {},
}),
schema: customCommandExecSchema(),
path: this.spec.internal.basePath,
Expand Down Expand Up @@ -186,10 +183,9 @@ export class CustomCommandWrapper extends Command {
const startedAt = new Date()

let gardenCommand = validateWithPath<CommandResource["gardenCommand"]>({
config: resolveTemplateStrings({
value: this.spec.gardenCommand,
config: deepEvaluate(this.spec.gardenCommand, {
context: commandContext,
source: { yamlDoc, path: ["gardenCommand"] },
opts: {},
}),
schema: customCommandGardenCommandSchema(),
path: this.spec.internal.basePath,
Expand Down
3 changes: 3 additions & 0 deletions core/src/commands/get/get-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ export class GetConfigCommand extends Command<{}, Opts, ConfigDump> {
override outputsSchema = () =>
joi.object().keys({
allEnvironmentNames: joiArray(environmentNameSchema()).required(),
allAvailablePlugins: joiArray(joi.string())
.description("A list of all plugins available to be used in the provider configuration.")
.required(),
environmentName: environmentNameSchema().required(),
namespace: joiIdentifier().description("The namespace of the current environment (if applicable)."),
providers: joiArray(joi.alternatives(providerSchema(), providerConfigBaseSchema())).description(
Expand Down
4 changes: 2 additions & 2 deletions core/src/commands/get/get-modules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { renderTable, dedent, deline } from "../../util/string.js"
import { relative, sep } from "path"
import type { Garden } from "../../index.js"
import type { Log } from "../../logger/log-entry.js"
import { highlightYaml, safeDumpYaml } from "../../util/serialization.js"
import { safeDumpYaml } from "../../util/serialization.js"
import { deepMap } from "../../util/objects.js"
import { styles } from "../../logger/styles.js"

Expand Down Expand Up @@ -137,7 +137,7 @@ function logFull(garden: Garden, modules: GardenModule[], log: Log) {
${printEmoji("🌱", log)} Module: ${styles.success(module.name)}
${divider}\n
`)
log.info(highlightYaml(yaml))
log.info(yaml)
}
}

Expand Down
6 changes: 3 additions & 3 deletions core/src/commands/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import { max, fromPairs, zip } from "lodash-es"
import { findByName, getNames } from "../util/util.js"
import { findByName } from "../util/util.js"
import { dedent, naturalList, renderTable, tablePresets } from "../util/string.js"
import { ParameterError, toGardenError } from "../exceptions.js"
import type { Log } from "../logger/log-entry.js"
Expand All @@ -25,7 +25,7 @@ const pluginArgs = {
help: "The name of the plugin, whose command you wish to run.",
required: false,
getSuggestions: ({ configDump }) => {
return getNames(configDump.providers)
return configDump.allAvailablePlugins
},
}),
command: new StringOption({
Expand Down Expand Up @@ -65,7 +65,7 @@ export class PluginsCommand extends Command<Args> {
}

async action({ garden, log, args }: CommandParams<Args>): Promise<CommandResult> {
const providerConfigs = garden.getRawProviderConfigs()
const providerConfigs = garden.getUnresolvedProviderConfigs()
const configuredPlugins = providerConfigs.map((p) => p.name)

if (!args.command || !args.plugin) {
Expand Down
Loading

0 comments on commit c968c61

Please sign in to comment.