Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Draft
wants to merge 122 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
122 commits
Select commit Hold shift + click to select a range
35fa5ab
perf: improve preprocess action perf by capturing context instead of
stefreak Dec 30, 2024
e2e9470
perf: use layered context and capture context instead of eager variab…
stefreak Dec 30, 2024
25e2715
chore: fix some issues
stefreak Dec 30, 2024
cec6fc9
fix: layered context implementation and serialisation of partially
stefreak Jan 2, 2025
8115217
perf: make sure it resolves and improve performance further
stefreak Jan 3, 2025
4e2a985
chore: remove yaml highlighting
stefreak Jan 3, 2025
35dbc4d
perf: do not call `resolveTemplateString` anymore, use `deepEvaluate`…
stefreak Jan 3, 2025
5fa739f
chore: do not validate providers if not fully resolved yet.
stefreak Jan 3, 2025
81e6819
chore: remove `resolveTemplateStrings` and make sure that the templat…
stefreak Jan 3, 2025
7719c18
chore: fix docs generation
stefreak Jan 3, 2025
9a209a4
chore: fix build by not ignoring parser.d.ts
stefreak Jan 3, 2025
8ad9cdd
chore: fix vote example
stefreak Jan 7, 2025
cb0081c
chore: fix bunch of tests
stefreak Jan 7, 2025
5e07353
fix: print correct wrapped error stack in tests
stefreak Jan 8, 2025
4a7fa79
chore: detect invalid keyed access of unresolved template values
stefreak Jan 8, 2025
391f08c
chore: change structural operator implementation to allow partial
stefreak Jan 10, 2025
cfa7eba
chore: also detect unpermitted write access to unresolved template value
stefreak Jan 11, 2025
49635df
fix: fix early provider resolution when resolving Garden params
vvagaytsev Jan 15, 2025
ee9c214
refactor: introduce type `UnresolvedProviderConfig`
vvagaytsev Jan 15, 2025
93d4fb9
chore: fix provider config
stefreak Jan 15, 2025
0ab6353
chore(template): primitives for partial resolution needed for module …
stefreak Jan 16, 2025
54b1bdf
chore: first step making module resolver work
stefreak Jan 16, 2025
dcf7c00
test: add extra test cases for template string access protection
vvagaytsev Jan 16, 2025
b90551d
chore: fix lint errors
vvagaytsev Jan 20, 2025
236aced
chore: enhance error handling
vvagaytsev Jan 20, 2025
bb4c33b
chore: add `toString()` for unresolved template values
vvagaytsev Jan 20, 2025
c834b8a
fix: fix the processing order in the context resolution loop
vvagaytsev Jan 20, 2025
4b11d8e
chore: helper function to serialise unresolved template values in tests
vvagaytsev Jan 20, 2025
3216512
test: fix one test failure
vvagaytsev Jan 20, 2025
c814c52
chore: fix more bugs
vvagaytsev Jan 20, 2025
2c06515
refactor: introduce named type for symbol `CONTEXT_RESOLVE_KEY_NOT_FO…
vvagaytsev Jan 20, 2025
50e6d90
test: fix assertions in provider configuration tests
vvagaytsev Jan 20, 2025
087472c
chore: rewrite ConfigContext.resolve
stefreak Jan 20, 2025
3c2f4d6
chore: do not pass unresolved action variables to configure handler (…
stefreak Jan 20, 2025
6672a6c
Merge branch 'preprocess-perf' of github.com:garden-io/garden into pr…
stefreak Jan 20, 2025
b48bcad
chore: fix more tests and reintroduce nodePath
stefreak Jan 21, 2025
54f7cd5
chore: fix all ConfigContext tests
stefreak Jan 21, 2025
20e703c
chore: fix BuildCommand tests
stefreak Jan 21, 2025
b333801
chore: fix a symlink test
stefreak Jan 21, 2025
d829b2c
chore: fix CustomCommandWrapper tests
stefreak Jan 21, 2025
04a5169
chore: fix e2e test templated-k8s-container
stefreak Jan 21, 2025
d4937f3
chore: make sure to forward crashes in prepareModuleResource
stefreak Jan 21, 2025
7e0817f
Merge branch 'main' into preprocess-perf
vvagaytsev Jan 21, 2025
2869aaf
chore: fix lint errors
vvagaytsev Jan 21, 2025
a584997
chore: fix templated-k8s-container-modules by skipping early prepareB…
stefreak Jan 21, 2025
8f3c238
chore: uncomment object freeze in parseTemplateCollection to fix some…
stefreak Jan 21, 2025
9aa6877
chore: fix "should correctly parse" test
stefreak Jan 21, 2025
8801d09
test: fix tests in RunWorkflowCommand
vvagaytsev Jan 21, 2025
f281af5
chore: fix command error handling tests
stefreak Jan 21, 2025
b4af168
chore: fix further tests
stefreak Jan 21, 2025
9b55bbe
chore: fix output test
stefreak Jan 21, 2025
4fd8e04
refactor(test): parse whole workflow configs as template values
vvagaytsev Jan 21, 2025
388018f
chore: fix lint issues
vvagaytsev Jan 21, 2025
027e97e
docs: re-generate docs
vvagaytsev Jan 21, 2025
7994d6d
test: fix test crashes
vvagaytsev Jan 21, 2025
90afdb7
test: fix assertions
vvagaytsev Jan 21, 2025
e44d195
chore: fix some tests by not cloning actions
stefreak Jan 21, 2025
c3a4813
test: fix crash in pickEnvironment tests
vvagaytsev Jan 21, 2025
00b4e22
chore: fix lint issues
vvagaytsev Jan 22, 2025
628bbf5
test: fix some test crashes in `scanAndAddConfigs`
vvagaytsev Jan 22, 2025
8fcbec3
test: fix some test crashes in `getConfigGraph`
vvagaytsev Jan 22, 2025
253ffee
test: fix template string assertion
vvagaytsev Jan 22, 2025
4b642d0
test: fix assertions for variables
vvagaytsev Jan 22, 2025
032a058
test: fix some assertions in template-string.ts
vvagaytsev Jan 22, 2025
b10cbb0
test: fix some assertions in template-string.ts
vvagaytsev Jan 22, 2025
eae3791
fix: process `$concat` correctly in `$forEach`
vvagaytsev Jan 22, 2025
331fe0b
fix: add work-around for nodejs exit 0 crash
stefreak Jan 22, 2025
2f2bdca
fix: parse template strings in project config tests
stefreak Jan 22, 2025
5e095f4
fix: resolveProjectConfig test
stefreak Jan 22, 2025
e2cecae
fix: throw on missing secret keys
vvagaytsev Jan 22, 2025
6f14b1c
test: fix tests for `getActionTemplateReferences`
vvagaytsev Jan 22, 2025
4b1a557
fix: more informative message if no keys are available in the context
vvagaytsev Jan 22, 2025
b2750b1
test: fix assertions for "should handle keys with dots and unresolvab…
vvagaytsev Jan 22, 2025
08b9404
fix: update plugin context schema
vvagaytsev Jan 22, 2025
e3fc6c2
test: fix variable assertions in "pickEnvironment"
vvagaytsev Jan 22, 2025
130e664
fix: evaluate all values that do not have essential runtime reference…
stefreak Jan 22, 2025
a4007e4
test: make ResolveActionTask pass
stefreak Jan 22, 2025
bf29505
test: fix default providers definition in test helpers
vvagaytsev Jan 22, 2025
d41105d
chore: fix resolveWorkflowConfig tests
stefreak Jan 22, 2025
c926b1a
fix: partiallyEvaluateModule accidentally compared the wrong thing
stefreak Jan 22, 2025
b42e6f4
fix: further test cases "ModuleResolver"
stefreak Jan 22, 2025
10cc264
test: trivial assertion corrections in "DefaultEnvironmentContext"
vvagaytsev Jan 23, 2025
61dce6b
test: fix assertions in provider configuration tests
vvagaytsev Jan 23, 2025
5e10469
fix: set provider path before calling `configureProvider` handler
vvagaytsev Jan 23, 2025
1c1b8b2
Revert "fix: set provider path before calling `configureProvider` han…
vvagaytsev Jan 23, 2025
fb14cad
test: fix assertion in "resolveProviders.should call a configureProvi…
vvagaytsev Jan 23, 2025
3247a3c
fix: remove unnecessary hack in `action.disable` flag resolution
vvagaytsev Jan 23, 2025
ef3e6bb
chore: extract defaults from input schema (best-effort) so we can app…
stefreak Jan 23, 2025
ad06084
fix: build
stefreak Jan 23, 2025
05e2045
fix: do not use capture in `renderModules`
vvagaytsev Jan 23, 2025
6545c55
Merge branch 'main' into preprocess-perf
vvagaytsev Jan 23, 2025
7f79b9d
fix: partial module resolution dependency detection / BuildCommand tests
stefreak Jan 23, 2025
8eb5b66
test: remove test "should normalize build dependencies" - prepareModu…
stefreak Jan 23, 2025
28a0711
test: serialise unresolved templates before using expect
stefreak Jan 23, 2025
d83bc04
fix: test "should remove null values in provider configs"
stefreak Jan 23, 2025
a430cca
fix: resolveConfigTemplate tests
stefreak Jan 23, 2025
a372534
fix: make a couple of renderConfigTemplate tests work
stefreak Jan 23, 2025
d9cf05c
fix: ensure right-to-left the order of precedence in `LayeredContext`
vvagaytsev Jan 23, 2025
0d75ee8
Merge branch 'main' into preprocess-perf
vvagaytsev Jan 23, 2025
e862080
fix: renderConfigTemplate tests
stefreak Jan 23, 2025
2ab7fd4
Revert "fix: remove unnecessary hack in `action.disable` flag resolut…
stefreak Jan 24, 2025
0ecbe5b
fix: test "should resolve template strings in project source definiti…
stefreak Jan 24, 2025
9bd74bf
fix: test "should return a different version for a module when a vari…
stefreak Jan 24, 2025
b5726ae
chore: update assertions in test "should resolve modules from config …
stefreak Jan 24, 2025
7d43437
fix: test "sets variables for the action"
stefreak Jan 24, 2025
b06d49a
fix: test "should respect the action variables < action varfile < CLI…
stefreak Jan 24, 2025
a9011b0
fix: test "should resolve disabled flag in actions and allow two acti…
stefreak Jan 24, 2025
69efd65
fix: test should resolve actions from config templates
stefreak Jan 24, 2025
8b0cba4
chore: remove unused and misleading internal flag
stefreak Jan 24, 2025
9a750ac
fix: "preprocessActionConfig" tests
stefreak Jan 24, 2025
36c11ad
fix: rehydrate template strings after converting modules to actions
stefreak Jan 24, 2025
41920bc
fix: do not parse template on already parsed module
stefreak Jan 24, 2025
57d968e
fix: do early module spec validation only if inputs are resolved
vvagaytsev Jan 24, 2025
9ad50e1
Merge branch 'main' into preprocess-perf
vvagaytsev Jan 24, 2025
437b3ab
fix: do early module spec validation only if inputs are resolved
vvagaytsev Jan 24, 2025
6842286
fix: perform toJSON serialization only for unresolved template values
vvagaytsev Jan 24, 2025
85a71cb
test: fix tests in "resolveProjectOutputs"
vvagaytsev Jan 24, 2025
73e26d3
chore: fix lint errors
vvagaytsev Jan 24, 2025
7aa19b6
fix: enforce correct variable precedence centrally and make sure vers…
stefreak Jan 24, 2025
e549151
fix: do not validate BaseAction instances in joi augmentGraph schema
stefreak Jan 24, 2025
26116b7
fix: additional test fixes
stefreak Jan 24, 2025
b161b80
refactor: use @ts-expect-error todo comments instead of as unknown c…
stefreak Jan 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
9 changes: 4 additions & 5 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,11 +250,11 @@
"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",
Expand Down
40 changes: 31 additions & 9 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 { ConfigContext } from "../config/template-contexts/base.js"
import type { ResolvedTemplate } from "../template/types.js"
import type { WorkflowConfig } from "../config/workflow.js"
import type { VariablesContext } from "../config/template-contexts/variables.js"

// TODO: split this file

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 @@ -583,7 +586,7 @@ export abstract class BaseAction<
}
}

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

Expand All @@ -598,7 +601,7 @@ 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)
return key ? this._config[key] : this._config
}

/**
Expand Down Expand Up @@ -735,7 +738,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 +811,7 @@ 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)
return key ? this._config.spec[key] : this._config.spec
}

getOutput<K extends keyof StaticOutputs>(key: K): GetOutputValueType<K, StaticOutputs, RuntimeOutputs> {
Expand All @@ -816,6 +821,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 +907,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 +956,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
17 changes: 15 additions & 2 deletions core/src/commands/util/fetch-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ import { PluginTool } from "../../util/ext-tools.js"
import { fromPairs, omit, uniqBy } from "lodash-es"
import { printHeader, printFooter } from "../../logger/util.js"
import { BooleanParameter } from "../../cli/params.js"
import type { BaseProviderConfig, Provider } from "../../config/provider.js"

interface PluginConfigWithToolVersion extends BaseProviderConfig {
version?: string
}
const fetchToolsOpts = {
"all": new BooleanParameter({
help: "Fetch all tools for registered plugins, instead of just ones in the current env/project.",
Expand Down Expand Up @@ -93,12 +97,21 @@ export class FetchToolsCommand extends Command<{}, FetchToolsOpts> {
// No need to fetch the same tools multiple times, if they're used in multiple providers
const deduplicated = uniqBy(tools, ({ tool }) => tool["versionPath"])

const versionedConfigs = garden.getRawProviderConfigs({ names: ["pulumi", "terraform"], allowMissing: true })
const configuredProviders = garden
.getUnresolvedProviderConfigs({ names: ["pulumi", "terraform"], allowMissing: true })
.map((c) => c.name)

const resolvedProviderConfigs: Provider<PluginConfigWithToolVersion>[] = []
for (const providerName of configuredProviders) {
resolvedProviderConfigs.push(
await garden.resolveProvider<PluginConfigWithToolVersion>({ name: providerName, log })
)
}

// If the version of the tool is configured on the provider,
// download only that version of the tool.
const toolsNeeded = deduplicated.filter((tool) => {
const pluginToolVersion = versionedConfigs.find((p) => p.name === tool.plugin.name)?.version
const pluginToolVersion = resolvedProviderConfigs.find((p) => p.name === tool.plugin.name)?.config.version
const pluginHasVersionConfigured = !!pluginToolVersion
if (!pluginHasVersionConfigured) {
return true
Expand Down
Loading