diff --git a/src/cli/index.js b/src/cli/index.js index b1ce151f4c..cad46b4609 100644 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -173,11 +173,16 @@ program }); program - .command('install') - .description('Launch the NodeBB web installer for configuration setup') - .action(() => { - require('./setup').webInstall(); + .command('install [plugin]') + .description('Launch the NodeBB web installer for configuration setup or install a plugin') + .action((plugin) => { + if (plugin) { + require('./manage').install(plugin); + } else { + require('./setup').webInstall(); + } }); + program .command('build [targets...]') .description(`Compile static assets ${chalk.red('(JS, CSS, templates, languages)')}`) diff --git a/src/cli/manage.js b/src/cli/manage.js index 24052e21f6..45480e735f 100644 --- a/src/cli/manage.js +++ b/src/cli/manage.js @@ -12,7 +12,36 @@ const plugins = require('../plugins'); const events = require('../events'); const analytics = require('../analytics'); const reset = require('./reset'); -const { pluginNamePattern, themeNamePattern } = require('../constants'); +const { pluginNamePattern, themeNamePattern, paths } = require('../constants'); + +async function install(plugin) { + try { + await db.init(); + if (!pluginNamePattern.test(plugin)) { + // Allow omission of `nodebb-plugin-` + plugin = `nodebb-plugin-${plugin}`; + } + + plugin = await plugins.autocomplete(plugin); + + const isInstalled = await plugins.isInstalled(plugin); + if (isInstalled) { + throw new Error('plugin already installed'); + } + const nbbVersion = require(paths.currentPackage).version; + const suggested = await plugins.suggest(plugin, nbbVersion); + if (!suggested.version) { + throw new Error(suggested.message); + } + winston.info('Installing Plugin `%s@%s`', plugin, suggested.version); + await plugins.toggleInstall(plugin, suggested.version); + + process.exit(0); + } catch (err) { + winston.error(`An error occurred during plugin installation\n${err.stack}`); + process.exit(1); + } +} async function activate(plugin) { if (themeNamePattern.test(plugin)) { @@ -166,6 +195,7 @@ async function buildWrapper(targets, options) { } exports.build = buildWrapper; +exports.install = install; exports.activate = activate; exports.listPlugins = listPlugins; exports.listEvents = listEvents; diff --git a/src/plugins/install.js b/src/plugins/install.js index 3784df09a0..d358c917a5 100644 --- a/src/plugins/install.js +++ b/src/plugins/install.js @@ -87,6 +87,15 @@ module.exports = function (Plugins) { throw new Error('[[error:plugin-not-whitelisted]]'); }; + Plugins.suggest = async function (pluginId, nbbVersion) { + const body = await request({ + method: 'GET', + url: `https://packages.nodebb.org/api/v1/suggest?package=${encodeURIComponent(pluginId)}&version=${encodeURIComponent(nbbVersion)}`, + json: true, + }); + return body; + }; + Plugins.toggleInstall = async function (id, version) { pubsub.publish('plugins:toggleInstall', { hostname: os.hostname(), id: id, version: version }); return await toggleInstall(id, version);