-
Notifications
You must be signed in to change notification settings - Fork 266
/
resolve-module.ts
136 lines (117 loc) · 4.35 KB
/
resolve-module.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
* Copyright (C) 2018-2020 Garden Technologies, Inc. <info@garden.io>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
import { cloneDeep } from "lodash"
import { validateWithPath } from "./config/validation"
import { resolveTemplateStrings } from "./template-string"
import { ContextResolveOpts, ModuleConfigContext } from "./config/config-context"
import { relative } from "path"
import { Garden } from "./garden"
import { ConfigurationError } from "./exceptions"
import { deline } from "./util/string"
import { getModuleKey } from "./types/module"
import { getModuleTypeBases } from "./plugins"
import { ModuleConfig, moduleConfigSchema } from "./config/module"
import { profileAsync } from "./util/profiling"
import { getLinkedSources } from "./util/ext-source-util"
export interface ModuleConfigResolveOpts extends ContextResolveOpts {
configContext: ModuleConfigContext
}
export const resolveModuleConfig = profileAsync(async function $resolveModuleConfig(
garden: Garden,
config: ModuleConfig,
opts: ModuleConfigResolveOpts
): Promise<ModuleConfig> {
// Allowing partial resolution here, to defer runtime remplate resolution
config = resolveTemplateStrings(cloneDeep(config), opts.configContext, { allowPartial: true, ...opts })
const moduleTypeDefinitions = await garden.getModuleTypes()
const description = moduleTypeDefinitions[config.type]
if (!description) {
const configPath = relative(garden.projectRoot, config.configPath || config.path)
throw new ConfigurationError(
deline`
Unrecognized module type '${config.type}' (defined at ${configPath}).
Are you missing a provider configuration?
`,
{ config, configuredModuleTypes: Object.keys(moduleTypeDefinitions) }
)
}
// Validate the module-type specific spec
if (description.schema) {
config.spec = validateWithPath({
config: config.spec,
schema: description.schema,
name: config.name,
path: config.path,
projectRoot: garden.projectRoot,
})
}
/*
We allow specifying modules by name only as a shorthand:
dependencies:
- foo-module
- name: foo-module // same as the above
*/
if (config.build && config.build.dependencies) {
config.build.dependencies = config.build.dependencies.map((dep) =>
typeof dep === "string" ? { name: dep, copy: [] } : dep
)
}
// Validate the base config schema
config = validateWithPath({
config,
schema: moduleConfigSchema(),
configType: "module",
name: config.name,
path: config.path,
projectRoot: garden.projectRoot,
})
if (config.repositoryUrl) {
const linkedSources = await getLinkedSources(garden, "module")
config.path = await garden.loadExtSourcePath({
name: config.name,
linkedSources,
repositoryUrl: config.repositoryUrl,
sourceType: "module",
})
}
const actions = await garden.getActionRouter()
const configureResult = await actions.configureModule({
moduleConfig: config,
log: garden.log,
})
config = configureResult.moduleConfig
// Validate the configure handler output against the module type's bases
const bases = getModuleTypeBases(moduleTypeDefinitions[config.type], moduleTypeDefinitions)
for (const base of bases) {
if (base.schema) {
garden.log.silly(`Validating '${config.name}' config against '${base.name}' schema`)
config.spec = <ModuleConfig>validateWithPath({
config: config.spec,
schema: base.schema.unknown(true),
path: garden.projectRoot,
projectRoot: garden.projectRoot,
configType: `configuration for module '${config.name}' (base schema from '${base.name}' plugin)`,
ErrorClass: ConfigurationError,
})
}
}
// FIXME: We should be able to avoid this
config.name = getModuleKey(config.name, config.plugin)
if (config.plugin) {
for (const serviceConfig of config.serviceConfigs) {
serviceConfig.name = getModuleKey(serviceConfig.name, config.plugin)
}
for (const taskConfig of config.taskConfigs) {
taskConfig.name = getModuleKey(taskConfig.name, config.plugin)
}
for (const testConfig of config.testConfigs) {
testConfig.name = getModuleKey(testConfig.name, config.plugin)
}
}
return config
})