From 26f38c78672dc41029ae954542f44acb201b5676 Mon Sep 17 00:00:00 2001 From: Jon Edvald Date: Sun, 22 Apr 2018 21:35:46 +0200 Subject: [PATCH] feat: plugins can now add modules to a project --- src/garden.ts | 57 +++++++++++++++++++++++++++++-------------- src/plugin-context.ts | 2 ++ src/types/module.ts | 9 ++++++- src/types/plugin.ts | 3 +++ 4 files changed, 52 insertions(+), 19 deletions(-) diff --git a/src/garden.ts b/src/garden.ts index a25ac1a43b..cee827f19b 100644 --- a/src/garden.ts +++ b/src/garden.ts @@ -149,7 +149,6 @@ export class Garden { private readonly environment: string, private readonly namespace: string, public readonly config: EnvironmentConfig, - plugins: RegisterPluginParam[], logger?: RootLogNode, ) { this.modulesScanned = false @@ -173,21 +172,6 @@ export class Garden { this.pluginContext = createPluginContext(this) this.taskGraph = new TaskGraph(this.pluginContext) - - // Register plugins - for (const plugin of builtinPlugins.concat(plugins)) { - this.registerPlugin(plugin) - } - - for (const plugin of fixedPlugins) { - this.loadPlugin(plugin, {}) - } - - // Load configured plugins - // Validate configuration - for (const [providerName, provider] of Object.entries(config.providers)) { - this.loadPlugin(providerName, provider) - } } static async factory(projectRoot: string, { env, config, logger, plugins = [] }: ContextOpts = {}) { @@ -254,7 +238,24 @@ export class Garden { // Resolve the project configuration based on selected environment const projectConfig = merge({}, globalConfig, envConfig) - return new Garden(projectRoot, projectName, environment, namespace, projectConfig, plugins, logger) + const garden = new Garden(projectRoot, projectName, environment, namespace, projectConfig, logger) + + // Register plugins + for (const plugin of builtinPlugins.concat(plugins)) { + garden.registerPlugin(plugin) + } + + for (const plugin of fixedPlugins) { + await garden.loadPlugin(plugin, {}) + } + + // Load configured plugins + // Validate configuration + for (const [providerName, provider] of Object.entries(projectConfig.providers)) { + await garden.loadPlugin(providerName, provider) + } + + return garden } getEnvironment(): Environment { @@ -336,7 +337,7 @@ export class Garden { this.registeredPlugins[name] = factory } - private loadPlugin(pluginName: string, config: object) { + private async loadPlugin(pluginName: string, config: object) { const factory = this.registeredPlugins[pluginName] if (!factory) { @@ -369,6 +370,19 @@ export class Garden { this.config.providers[pluginName] = plugin.config } + for (const modulePath of plugin.modules || []) { + const module = await this.resolveModule(modulePath) + if (!module) { + throw new PluginError(`Could not load module "${modulePath}" specified in plugin "${pluginName}"`, { + pluginName, + modulePath, + }) + } + module.name = `${pluginName}.${module.name}` + module.updateConfig("name", module.name) + await this.addModule(module) + } + const actions = plugin.actions || {} for (const actionType of pluginActionNames) { @@ -472,6 +486,13 @@ export class Garden { return output } + /** + * Returns the module with the specified name. Throws error if it doesn't exist. + */ + async getModule(name: string, noScan?: boolean): Promise> { + return (await this.getModules([name], noScan))[name] + } + /* Returns all services that are registered in this context. Scans for modules and services in the project root if it hasn't already been done. diff --git a/src/plugin-context.ts b/src/plugin-context.ts index b92e36c9b6..efb1865004 100644 --- a/src/plugin-context.ts +++ b/src/plugin-context.ts @@ -72,6 +72,7 @@ export type WrappedFromGarden = Pick { return config } + updateConfig(key: string, value: any) { + set(this.config, key, value) + } + async getVersion(): Promise { const treeVersion = await this.ctx.vcs.getTreeVersion([this.path]) diff --git a/src/types/plugin.ts b/src/types/plugin.ts index ed047c41f3..d96f3518f8 100644 --- a/src/types/plugin.ts +++ b/src/types/plugin.ts @@ -270,6 +270,8 @@ export interface GardenPlugin { config?: object configKeys?: string[] + modules?: string[] + actions?: Partial moduleActions?: { [moduleType: string]: Partial> } } @@ -282,6 +284,7 @@ export type RegisterPluginParam = string | PluginFactory export const pluginSchema = Joi.object().keys({ config: Joi.object(), + modules: Joi.array().items(Joi.string()), actions: Joi.object().keys(mapValues(pluginActionDescriptions, () => Joi.func())), moduleActions: joiIdentifierMap( Joi.object().keys(mapValues(moduleActionDescriptions, () => Joi.func())),