├── .node-version ├── circle.yml ├── .gitignore ├── tasks ├── build │ ├── index.js │ ├── __fixtures__ │ │ └── test_plugin │ │ │ ├── public │ │ │ └── hack.js │ │ │ ├── index.js │ │ │ ├── translations │ │ │ └── es.json │ │ │ └── package.json │ ├── __snapshots__ │ │ └── build_action.spec.js.snap │ ├── README.md │ ├── git_info.js │ ├── create_package.js │ ├── rewrite_package_json.js │ ├── create_package.spec.js │ ├── build_action.js │ ├── create_build.spec.js │ ├── create_build.js │ └── build_action.spec.js ├── start │ ├── index.js │ ├── README.md │ └── start_action.js └── test │ ├── all │ ├── index.js │ ├── test_all_action.js │ └── README.md │ ├── browser │ ├── index.js │ ├── test_browser_action.js │ └── README.md │ └── server │ ├── index.js │ ├── README.md │ └── test_server_action.js ├── .eslintrc ├── .backportrc.json ├── lib ├── win_cmd.js ├── run.js ├── enable_collecting_unknown_options.js ├── index.js ├── tasks.js ├── docs.js ├── commander_action.js ├── __snapshots__ │ └── commander_action.spec.js.snap ├── run.spec.js ├── plugin_config.js ├── utils.js ├── config_file.js └── commander_action.spec.js ├── bin └── plugin-helpers.js ├── LICENSE ├── package.json ├── cli.js └── README.md /.node-version: -------------------------------------------------------------------------------- 1 | ^6.0.0 -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | node: 3 | version: 6 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | *.log 4 | yarn.lock 5 | -------------------------------------------------------------------------------- /tasks/build/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./build_action'); 2 | -------------------------------------------------------------------------------- /tasks/start/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./start_action'); 2 | -------------------------------------------------------------------------------- /tasks/test/all/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./test_all_action'); 2 | -------------------------------------------------------------------------------- /tasks/build/__fixtures__/test_plugin/public/hack.js: -------------------------------------------------------------------------------- 1 | console.log('this is my hack'); -------------------------------------------------------------------------------- /tasks/test/browser/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./test_browser_action'); 2 | -------------------------------------------------------------------------------- /tasks/test/server/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./test_server_action'); 2 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | --- 2 | extends: "@elastic/kibana" 3 | 4 | plugins: 5 | - jest 6 | 7 | rules: 8 | prefer-object-spread/prefer-object-spread: 0 9 | -------------------------------------------------------------------------------- /tasks/test/all/test_all_action.js: -------------------------------------------------------------------------------- 1 | module.exports = function testAllAction(plugin, run) { 2 | run('testServer'); 3 | run('testBrowser'); 4 | }; 5 | -------------------------------------------------------------------------------- /.backportrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "upstream": "elastic/kibana-plugin-helpers", 3 | "own": false, 4 | "multipleCommits": false, 5 | "labels": ["backport"] 6 | } -------------------------------------------------------------------------------- /tasks/test/all/README.md: -------------------------------------------------------------------------------- 1 | Runs both the server and browser tests, in that order. 2 | 3 | This is just a simple caller to both `test/server` and `test/browser` -------------------------------------------------------------------------------- /lib/win_cmd.js: -------------------------------------------------------------------------------- 1 | const platform = require('os').platform(); 2 | 3 | module.exports = function winCmd(cmd) { 4 | return /^win/.test(platform) ? cmd + '.cmd' : cmd; 5 | }; 6 | -------------------------------------------------------------------------------- /tasks/build/__fixtures__/test_plugin/index.js: -------------------------------------------------------------------------------- 1 | module.exports = kibana => new kibana.Plugin({ 2 | uiExports: { 3 | hacks: [ 4 | 'plugins/test_plugin/hack.js' 5 | ] 6 | } 7 | }); -------------------------------------------------------------------------------- /tasks/build/__snapshots__/build_action.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`build_action calling create_build rejects returned promise when build fails 1`] = `"foo bar"`; 4 | -------------------------------------------------------------------------------- /tasks/build/__fixtures__/test_plugin/translations/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "UI-WELCOME_MESSAGE": "Cargando Kibana", 3 | "UI-WELCOME_ERROR": "Kibana no se cargó correctamente. Heck la salida del servidor para obtener más información." 4 | } -------------------------------------------------------------------------------- /tasks/start/README.md: -------------------------------------------------------------------------------- 1 | Starts the kibana server with this plugin included. In essence this is the same as running the 2 | following from the root of the kibana install: 3 | 4 | ```sh 5 | ./bin/kibana --dev --plugin-path=../path/to/plugin 6 | ``` 7 | -------------------------------------------------------------------------------- /bin/plugin-helpers.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const nodeMajorVersion = parseFloat(process.version.replace(/^v(\d+)\..+/, '$1')); 4 | if (nodeMajorVersion < 6) { 5 | console.error('FATAL: kibana-plugin-helpers requires node 6+'); 6 | process.exit(1); 7 | } 8 | 9 | require('../cli'); 10 | -------------------------------------------------------------------------------- /tasks/build/__fixtures__/test_plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test_plugin", 3 | "version": "0.0.1", 4 | "kibana": { 5 | "version": "6.0.0" 6 | }, 7 | "dependencies": { 8 | 9 | }, 10 | "devDependencies": { 11 | 12 | }, 13 | "scripts": { 14 | "start": "node index.js" 15 | } 16 | } -------------------------------------------------------------------------------- /lib/run.js: -------------------------------------------------------------------------------- 1 | const pluginConfig = require('./plugin_config'); 2 | const tasks = require('./tasks'); 3 | 4 | module.exports = function run(name, options) { 5 | const action = tasks[name]; 6 | if (!action) { 7 | throw new Error('Invalid task: "' + name + '"'); 8 | } 9 | 10 | const plugin = pluginConfig(); 11 | return action(plugin, run, options); 12 | }; 13 | -------------------------------------------------------------------------------- /lib/enable_collecting_unknown_options.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = function enableCollectingUnknownOptions(command) { 3 | const origParse = command.parseOptions; 4 | command.allowUnknownOption(); 5 | command.parseOptions = function (argv) { 6 | const opts = origParse.call(this, argv); 7 | this.unknownOptions = opts.unknown; 8 | return opts; 9 | }; 10 | }; 11 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | const run = require('./run'); 2 | const utils = require('./utils'); 3 | 4 | module.exports = function () { 5 | console.error( 6 | 'running tasks with the default export of @elastic/plugin-helpers is deprecated.' + 7 | 'use `require(\'@elastic/plugin-helpers\').run()` instead' 8 | ); 9 | 10 | return run.apply(this, arguments); 11 | }; 12 | 13 | Object.assign(module.exports, { run: run }, utils); -------------------------------------------------------------------------------- /lib/tasks.js: -------------------------------------------------------------------------------- 1 | const buildTask = require('../tasks/build'); 2 | const startTask = require('../tasks/start'); 3 | const testAllTask = require('../tasks/test/all'); 4 | const testBrowserTask = require('../tasks/test/browser'); 5 | const testServerTask = require('../tasks/test/server'); 6 | 7 | module.exports = { 8 | build: buildTask, 9 | start: startTask, 10 | testAll: testAllTask, 11 | testBrowser: testBrowserTask, 12 | testServer: testServerTask, 13 | }; -------------------------------------------------------------------------------- /lib/docs.js: -------------------------------------------------------------------------------- 1 | const resolve = require('path').resolve; 2 | const readFileSync = require('fs').readFileSync; 3 | 4 | function indent(txt, n) { 5 | const space = (new Array(n + 1)).join(' '); 6 | return space + txt.split('\n').join('\n' + space); 7 | } 8 | 9 | module.exports = function docs(name) { 10 | const md = readFileSync(resolve(__dirname, '../tasks', name, 'README.md'), 'utf8'); 11 | 12 | return function () { 13 | console.log('\n Docs:'); 14 | console.log(''); 15 | console.log(indent(md, 4)); 16 | console.log(''); 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2016 Elasticsearch BV 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you 4 | may not use this file except in compliance with the License. You may 5 | obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | implied. See the License for the specific language governing 13 | permissions and limitations under the License. 14 | -------------------------------------------------------------------------------- /lib/commander_action.js: -------------------------------------------------------------------------------- 1 | const run = require('./run'); 2 | 3 | module.exports = function createCommanderAction(taskName, getOptions = () => {}) { 4 | return (...args) => { 5 | // command is the last arg passed by commander, but we move it to the front of the list 6 | const command = args.pop(); 7 | 8 | return Promise 9 | .resolve() 10 | .then(() => run(taskName, getOptions(command, ...args))) 11 | .catch((error) => { 12 | process.stderr.write(`Task "${taskName}" failed:\n\n${error.stack || error.message}\n`); 13 | process.exit(1); 14 | }); 15 | }; 16 | }; 17 | -------------------------------------------------------------------------------- /tasks/build/README.md: -------------------------------------------------------------------------------- 1 | Copies files from the source into a zip archive that can be distributed for 2 | installation into production kibana installs. The archive includes the non- 3 | development npm dependencies and builds itself using raw files in the source 4 | directory so make sure they are clean/up to date. The resulting archive can 5 | be found at: 6 | 7 | ``` 8 | build/{pkg.name}-{pkg.version}.zip 9 | ``` 10 | 11 | If you use the `--build-destination` flag, the resulting build will be found 12 | in that directory. 13 | 14 | ``` 15 | plugin-helpers build --build-destination build/some/child/path 16 | 17 | # This will place the resulting build at: 18 | build/some/child/path/{pkg.name}-{pkg.version}.zip 19 | ``` -------------------------------------------------------------------------------- /tasks/start/start_action.js: -------------------------------------------------------------------------------- 1 | const execFileSync = require('child_process').execFileSync; 2 | 3 | module.exports = function (plugin, run, options) { 4 | options = options || {}; 5 | 6 | const cmd = (process.platform === 'win32') ? 'bin\\kibana.bat' : 'bin/kibana'; 7 | let args = ['--dev', '--plugin-path', plugin.root]; 8 | 9 | if (Array.isArray(plugin.includePlugins)) { 10 | plugin.includePlugins.forEach((path) => { 11 | args = args.concat(['--plugin-path', path]); 12 | }); 13 | } 14 | 15 | if (options.flags) { 16 | args = args.concat(options.flags); 17 | } 18 | 19 | execFileSync(cmd, args, { 20 | cwd: plugin.kibanaRoot, 21 | stdio: ['ignore', 1, 2] 22 | }); 23 | }; 24 | -------------------------------------------------------------------------------- /tasks/build/git_info.js: -------------------------------------------------------------------------------- 1 | const execFileSync = require('child_process').execFileSync; 2 | 3 | module.exports = function gitInfo(rootPath) { 4 | try { 5 | const LOG_SEPARATOR = '||'; 6 | const commitCount = execFileSync('git', ['rev-list', '--count', 'HEAD'], { 7 | cwd: rootPath, 8 | stdio: ['ignore', 'pipe', 'ignore'], 9 | encoding: 'utf8', 10 | }); 11 | const logLine = execFileSync('git', ['log', '--pretty=%h' + LOG_SEPARATOR + '%cD', '-n', '1'], { 12 | cwd: rootPath, 13 | stdio: ['ignore', 'pipe', 'ignore'], 14 | encoding: 'utf8', 15 | }).split(LOG_SEPARATOR); 16 | 17 | return { 18 | count: commitCount.trim(), 19 | sha: logLine[0].trim(), 20 | date: logLine[1].trim(), 21 | }; 22 | } catch (e) { 23 | return {}; 24 | } 25 | }; -------------------------------------------------------------------------------- /tasks/test/browser/test_browser_action.js: -------------------------------------------------------------------------------- 1 | const execFileSync = require('child_process').execFileSync; 2 | const winCmd = require('../../../lib/win_cmd'); 3 | 4 | module.exports = function testBrowserAction(plugin, run, options) { 5 | options = options || {}; 6 | 7 | const kbnServerArgs = [ 8 | '--kbnServer.plugin-path=' + plugin.root 9 | ]; 10 | 11 | if (options.plugins) { 12 | kbnServerArgs.push('--kbnServer.tests_bundle.pluginId=' + options.plugins); 13 | } else { 14 | kbnServerArgs.push('--kbnServer.tests_bundle.pluginId=' + plugin.id); 15 | } 16 | 17 | const task = (options.dev) ? 'test:dev' : 'test:browser'; 18 | const args = ['run', task, '--'].concat(kbnServerArgs); 19 | execFileSync(winCmd('npm'), args, { 20 | cwd: plugin.kibanaRoot, 21 | stdio: ['ignore', 1, 2] 22 | }); 23 | 24 | }; 25 | -------------------------------------------------------------------------------- /tasks/build/create_package.js: -------------------------------------------------------------------------------- 1 | const join = require('path').join; 2 | const relative = require('path').relative; 3 | const del = require('del'); 4 | const vfs = require('vinyl-fs'); 5 | const zip = require('gulp-zip'); 6 | 7 | module.exports = function createPackage(plugin, buildTarget, buildVersion) { 8 | const buildId = `${plugin.id}-${buildVersion}`; 9 | const buildRoot = join(buildTarget, 'kibana', plugin.id); 10 | 11 | // zip up the package 12 | return new Promise(function (resolve, reject) { 13 | const buildFiles = [relative(buildTarget, buildRoot) + '/**/*']; 14 | 15 | vfs.src(buildFiles, { cwd: buildTarget, base: buildTarget }) 16 | .pipe(zip(`${buildId}.zip`)) 17 | .pipe(vfs.dest(buildTarget)) 18 | .on('end', resolve) 19 | .on('error', reject); 20 | }) 21 | .then(function () { 22 | // clean up the build path 23 | return del(join(buildTarget, 'kibana')); 24 | }); 25 | }; -------------------------------------------------------------------------------- /lib/__snapshots__/commander_action.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`commander action exits with status 1 when task throws error asynchronously 1`] = ` 4 | Array [ 5 | Array [ 6 | "Task \\"mockTask\\" failed: 7 | 8 | Error: async error thrown 9 | ...stack trace... 10 | ", 11 | ], 12 | ] 13 | `; 14 | 15 | exports[`commander action exits with status 1 when task throws synchronously 1`] = ` 16 | Array [ 17 | Array [ 18 | "Task \\"mockTask\\" failed: 19 | 20 | Error: sync error thrown 21 | ...stack trace... 22 | ", 23 | ], 24 | ] 25 | `; 26 | 27 | exports[`commander action passes args to getOptions, calls run() with taskName and options 1`] = ` 28 | Array [ 29 | Array [ 30 | "taskName", 31 | Object { 32 | "args": Array [ 33 | "f", 34 | "a", 35 | "b", 36 | "c", 37 | "d", 38 | "e", 39 | ], 40 | }, 41 | ], 42 | ] 43 | `; 44 | -------------------------------------------------------------------------------- /lib/run.spec.js: -------------------------------------------------------------------------------- 1 | /*eslint-env jest*/ 2 | 3 | jest.mock('./plugin_config', () => () => ( 4 | { id: 'testPlugin' } 5 | )); 6 | 7 | jest.mock('./tasks', () => { 8 | return { testTask: jest.fn() }; 9 | }); 10 | 11 | const run = require('./run'); 12 | 13 | describe('lib/run', () => { 14 | beforeEach(() => jest.resetAllMocks()); 15 | 16 | it('throw given an invalid task', function () { 17 | const invalidTaskName = 'thisisnotavalidtasknameandneverwillbe'; 18 | const runner = () => run(invalidTaskName); 19 | 20 | expect(runner).toThrow(/invalid task/i); 21 | }); 22 | 23 | it('runs specified task with plugin and runner', function () { 24 | run('testTask'); 25 | 26 | const { testTask } = require('./tasks'); 27 | const plugin = require('./plugin_config')(); 28 | const args = testTask.mock.calls[0]; 29 | expect(testTask.mock.calls).toHaveLength(1); 30 | expect(args[0]).toEqual(plugin); 31 | expect(args[1]).toBe(run); 32 | }); 33 | 34 | it('returns value returned by task', function () { 35 | const { testTask } = require('./tasks'); 36 | 37 | const symbol = Symbol('foo'); 38 | testTask.mockReturnValue(symbol); 39 | expect(run('testTask')).toBe(symbol); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /lib/plugin_config.js: -------------------------------------------------------------------------------- 1 | const resolve = require('path').resolve; 2 | const statSync = require('fs').statSync; 3 | const readFileSync = require('fs').readFileSync; 4 | const configFile = require('./config_file'); 5 | 6 | module.exports = function (root) { 7 | if (!root) root = process.cwd(); 8 | 9 | const pkg = JSON.parse(readFileSync(resolve(root, 'package.json'))); 10 | const config = configFile(root); 11 | 12 | const buildSourcePatterns = [ 13 | 'package.json', 14 | 'index.js', 15 | '{lib,public,server,webpackShims,translations}/**/*', 16 | ]; 17 | 18 | // add shrinkwrap and lock files, if they exist 19 | ['npm-shrinkwrap.json', 'yarn.lock'] 20 | .forEach(function (file) { 21 | if (fileExists(resolve(root, file))) { 22 | buildSourcePatterns.push(file); 23 | } 24 | }); 25 | 26 | return Object.assign({ 27 | root: root, 28 | kibanaRoot: resolve(root, '../kibana'), 29 | serverTestPatterns: ['server/**/__tests__/**/*.js'], 30 | buildSourcePatterns: buildSourcePatterns, 31 | id: pkg.name, 32 | pkg: pkg, 33 | version: pkg.version, 34 | }, config); 35 | }; 36 | 37 | function fileExists(path) { 38 | try { 39 | const stat = statSync(path); 40 | return stat.isFile(); 41 | } catch (e) { 42 | return false; 43 | } 44 | } -------------------------------------------------------------------------------- /tasks/build/rewrite_package_json.js: -------------------------------------------------------------------------------- 1 | const map = require('through2-map').obj; 2 | const gitInfo = require('./git_info'); 3 | 4 | module.exports = function rewritePackage(buildSource, buildVersion, kibanaVersion) { 5 | return map(function (file) { 6 | if (file.basename === 'package.json' && file.dirname === buildSource) { 7 | const pkg = JSON.parse(file.contents.toString('utf8')); 8 | 9 | // rewrite the target kibana version while the 10 | // file is on it's way to the archive 11 | if (!pkg.kibana) pkg.kibana = {}; 12 | pkg.kibana.version = kibanaVersion; 13 | pkg.version = buildVersion; 14 | 15 | // append build info 16 | pkg.build = { 17 | git: gitInfo(buildSource), 18 | date: new Date().toString() 19 | }; 20 | 21 | // remove development properties from the package file 22 | delete pkg.scripts; 23 | delete pkg.devDependencies; 24 | 25 | file.contents = toBuffer(JSON.stringify(pkg, null, 2)); 26 | } 27 | 28 | return file; 29 | }); 30 | }; 31 | 32 | function toBuffer(string) { 33 | if (typeof Buffer.from === 'function') { 34 | return Buffer.from(string, 'utf8'); 35 | } else { 36 | // this was deprecated in node v5 in favor 37 | // of Buffer.from(string, encoding) 38 | return new Buffer(string, 'utf8'); 39 | } 40 | } -------------------------------------------------------------------------------- /tasks/build/create_package.spec.js: -------------------------------------------------------------------------------- 1 | /*eslint-env jest*/ 2 | const { resolve } = require('path'); 3 | const { statSync } = require('fs'); 4 | const del = require('del'); 5 | const createBuild = require('./create_build'); 6 | const createPackage = require('./create_package'); 7 | 8 | const PLUGIN_FIXTURE = resolve(__dirname, '__fixtures__/test_plugin'); 9 | const PLUGIN = require('../../lib/plugin_config')(PLUGIN_FIXTURE); 10 | const PLUGIN_BUILD_DIR = resolve(PLUGIN_FIXTURE, 'build-custom'); 11 | 12 | describe('create_build', () => { 13 | const buildVersion = PLUGIN.version; 14 | const kibanaVersion = PLUGIN.version; 15 | const buildFiles = PLUGIN.buildSourcePatterns; 16 | const packageFile = `${PLUGIN.id}-${buildVersion}.zip`; 17 | const doBuild = () => createBuild(PLUGIN, PLUGIN_BUILD_DIR, buildVersion, kibanaVersion, buildFiles); 18 | 19 | beforeAll(() => del(PLUGIN_BUILD_DIR).then(doBuild)); 20 | afterAll(() => del(PLUGIN_BUILD_DIR)); 21 | 22 | describe('creating the package', function () { 23 | it('creates zip file in build target path', function () { 24 | return createPackage(PLUGIN, PLUGIN_BUILD_DIR, buildVersion) 25 | .then(() => { 26 | const zipFile = resolve(PLUGIN_BUILD_DIR, packageFile); 27 | const stats = statSync(zipFile); 28 | expect(stats.isFile()).toBeTruthy(); 29 | }); 30 | }); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | const resolve = require('path').resolve; 2 | 3 | const pluginConfig = require('./plugin_config'); 4 | 5 | function babelRegister() { 6 | const plugin = pluginConfig(); 7 | 8 | try { 9 | // add support for moved babel-register source: https://github.com/elastic/kibana/pull/13973 10 | require(resolve(plugin.kibanaRoot, 'src/babel-register')); 11 | } catch (error) { 12 | if (error.code === 'MODULE_NOT_FOUND') { 13 | require(resolve(plugin.kibanaRoot, 'src/optimize/babel/register')); 14 | } else { 15 | throw error; 16 | } 17 | } 18 | } 19 | 20 | function resolveKibanaPath(path) { 21 | const plugin = pluginConfig(); 22 | return resolve(plugin.kibanaRoot, path); 23 | } 24 | 25 | function createToolingLog(level) { 26 | // The tooling log location changed in 6.1.0, see https://github.com/elastic/kibana/pull/14890 27 | const utils = require(resolveKibanaPath('src/utils')); 28 | if (utils.createToolingLog) return utils.createToolingLog(level); 29 | return require(resolveKibanaPath('src/dev')).createToolingLog(level); 30 | } 31 | 32 | function readFtrConfigFile(log, path, settingOverrides) { 33 | return require(resolveKibanaPath('src/functional_test_runner')).readConfigFile(log, path, settingOverrides); 34 | } 35 | 36 | module.exports = { 37 | babelRegister: babelRegister, 38 | resolveKibanaPath: resolveKibanaPath, 39 | createToolingLog: createToolingLog, 40 | readFtrConfigFile: readFtrConfigFile, 41 | }; -------------------------------------------------------------------------------- /lib/config_file.js: -------------------------------------------------------------------------------- 1 | const resolve = require('path').resolve; 2 | const readFileSync = require('fs').readFileSync; 3 | 4 | const configFiles = [ '.kibana-plugin-helpers.json', '.kibana-plugin-helpers.dev.json' ]; 5 | const configCache = {}; 6 | const KIBANA_ROOT_OVERRIDE = process.env.KIBANA_ROOT ? resolve(process.env.KIBANA_ROOT) : null; 7 | 8 | module.exports = function (root) { 9 | if (!root) root = process.cwd(); 10 | 11 | if (configCache[root]) { 12 | return configCache[root]; 13 | } 14 | 15 | // config files to read from, in the order they are merged together 16 | let config = configCache[root] = {}; 17 | 18 | configFiles.forEach(function (configFile) { 19 | try { 20 | const content = JSON.parse(readFileSync(resolve(root, configFile))); 21 | config = Object.assign(config, content); 22 | } catch (e) { 23 | // rethrow error unless it's complaining about file not existing 24 | if (e.code !== 'ENOENT') { 25 | throw e; 26 | } 27 | } 28 | }); 29 | 30 | // use resolve to ensure correct resolution of paths 31 | const { kibanaRoot, includePlugins } = config; 32 | if (kibanaRoot) config.kibanaRoot = resolve(root, kibanaRoot); 33 | if (includePlugins) config.includePlugins = includePlugins.map(path => resolve(root, path)); 34 | 35 | // allow env setting to override kibana root from config 36 | if (KIBANA_ROOT_OVERRIDE) config.kibanaRoot = KIBANA_ROOT_OVERRIDE; 37 | 38 | return config; 39 | }; 40 | -------------------------------------------------------------------------------- /tasks/test/server/README.md: -------------------------------------------------------------------------------- 1 | writing tests 2 | ============= 3 | 4 | Server tests are written just like browser tests, they are just executed differently. 5 | 6 | - place tests near the code they test, in `__tests__` directories throughout 7 | the server directory 8 | - Use the same bdd-style `describe()` and `it()` api to define the suites 9 | and cases of your tests. 10 | 11 | ```js 12 | describe('some portion of your code', function () { 13 | it('should do this thing', function () { 14 | expect(true).to.be(false); 15 | }); 16 | }); 17 | ``` 18 | 19 | 20 | running the tests 21 | ================= 22 | 23 | Running the server tests is simple, just execute `npm run test:server` in your terminal 24 | and all of the tests in your server will be run. 25 | 26 | By default, the runner will look for tests in `server/**/__tests__/**/*.js`. If you'd prefer to 27 | use a different collection of globs and files, you can specify them after the `npm run test:server` 28 | task, like so: 29 | 30 | `npm run test:server 'plugins/myplugins/server/__tests__/**/*.js'` 31 | 32 | NOTE: quoting the glob pattern is not required, but helps to avoid issues with globbing expansion 33 | in your shell. 34 | 35 | 36 | focus on the task at hand 37 | ========================= 38 | 39 | To limit the tests that run add `.only` to your `describe()` or `it()` calls: 40 | 41 | ```js 42 | describe.only('suite name', function () { 43 | // ... 44 | }); 45 | ``` 46 | -------------------------------------------------------------------------------- /tasks/test/server/test_server_action.js: -------------------------------------------------------------------------------- 1 | const resolve = require('path').resolve; 2 | const delimiter = require('path').delimiter; 3 | const execFileSync = require('child_process').execFileSync; 4 | const winCmd = require('../../../lib/win_cmd'); 5 | 6 | function canRequire(path) { 7 | try { 8 | require.resolve(path); 9 | return true; 10 | } catch (error) { 11 | if (error.code !== 'MODULE_NOT_FOUND') { 12 | throw error; 13 | } 14 | return false; 15 | } 16 | } 17 | 18 | module.exports = function (plugin, run, options) { 19 | options = options || {}; 20 | const kibanaBins = resolve(plugin.kibanaRoot, 'node_modules/.bin'); 21 | const mochaSetupScript = resolve(plugin.kibanaRoot, 'test/mocha_setup.js'); 22 | const babelRegisterScript = resolve(plugin.kibanaRoot, 'src/optimize/babel/register'); 23 | let testPaths = plugin.serverTestPatterns; 24 | 25 | // allow server test files to be overridden 26 | if (options.files && options.files.length) { 27 | testPaths = options.files; 28 | } 29 | 30 | const fullCmd = resolve(plugin.kibanaRoot, 'node_modules', '.bin', 'mocha'); 31 | const cmd = winCmd(fullCmd); 32 | const args = ['--require', canRequire(mochaSetupScript) ? mochaSetupScript : babelRegisterScript].concat(testPaths); 33 | const path = `${kibanaBins}${delimiter}${process.env.PATH}`; 34 | 35 | execFileSync(cmd, args, { 36 | cwd: plugin.root, 37 | stdio: ['ignore', 1, 2], 38 | env: Object.assign({}, process.env, { 39 | PATH: path 40 | }) 41 | }); 42 | }; 43 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@elastic/plugin-helpers", 3 | "version": "7.1.8", 4 | "description": "Just some helpers for kibana plugin devs.", 5 | "main": "lib/index.js", 6 | "bin": { 7 | "plugin-helpers": "bin/plugin-helpers.js" 8 | }, 9 | "keywords": [ 10 | "kibana", 11 | "kibana-plugin" 12 | ], 13 | "author": "Spencer Alger ", 14 | "license": "Apache-2.0", 15 | "scripts": { 16 | "test": "npm run lint && jest", 17 | "test:only": "jest", 18 | "test:dev": "jest --watch", 19 | "lint": "eslint bin/ help/ tasks/" 20 | }, 21 | "dependencies": { 22 | "commander": "^2.9.0", 23 | "del": "^2.2.2", 24 | "gulp-rename": "1.2.2", 25 | "gulp-zip": "^4.1.0", 26 | "inquirer": "^1.2.2", 27 | "through2-map": "^3.0.0", 28 | "vinyl-fs": "2.3.1" 29 | }, 30 | "devDependencies": { 31 | "@elastic/eslint-config-kibana": "^0.15.0", 32 | "babel-eslint": "^8.0.0", 33 | "eslint": "^4.1.0", 34 | "eslint-plugin-babel": "^4.1.1", 35 | "eslint-plugin-import": "^2.6.0", 36 | "eslint-plugin-jest": "^21.15.0", 37 | "eslint-plugin-mocha": "^4.9.0", 38 | "eslint-plugin-prefer-object-spread": "^1.2.1", 39 | "eslint-plugin-react": "^7.1.0", 40 | "jest": "^22.4.3" 41 | }, 42 | "engines": { 43 | "node": "^6.11.5 || ^8.8.0" 44 | }, 45 | "directories": { 46 | "doc": "docs" 47 | }, 48 | "jest": { 49 | "modulePathIgnorePatterns": [ 50 | "__fixtures__" 51 | ] 52 | }, 53 | "repository": { 54 | "type": "git", 55 | "url": "git+https://github.com/elastic/kibana-plugin-helpers.git" 56 | }, 57 | "bugs": { 58 | "url": "https://github.com/elastic/kibana-plugin-helpers/issues" 59 | }, 60 | "homepage": "https://github.com/elastic/kibana-plugin-helpers#readme" 61 | } 62 | -------------------------------------------------------------------------------- /tasks/build/build_action.js: -------------------------------------------------------------------------------- 1 | const join = require('path').join; 2 | const resolve = require('path').resolve; 3 | const inquirer = require('inquirer'); 4 | 5 | const createBuild = require('./create_build'); 6 | const createPackage = require('./create_package'); 7 | 8 | module.exports = function (plugin, run, options) { 9 | options = options || {}; 10 | let buildVersion = plugin.version; 11 | let kibanaVersion = (plugin.pkg.kibana && plugin.pkg.kibana.version) || plugin.pkg.version; 12 | let buildFiles = plugin.buildSourcePatterns; 13 | let buildTarget = join(plugin.root, 'build'); 14 | 15 | // allow source files to be overridden 16 | if (options.files && options.files.length) { 17 | buildFiles = options.files; 18 | } 19 | 20 | // allow options to override plugin info 21 | if (options.buildDestination) buildTarget = resolve(plugin.root, options.buildDestination); 22 | if (options.buildVersion) buildVersion = options.buildVersion; 23 | if (options.kibanaVersion) kibanaVersion = options.kibanaVersion; 24 | 25 | let buildStep; 26 | if (kibanaVersion === 'kibana') { 27 | buildStep = askForKibanaVersion().then(function (customKibanaVersion) { 28 | return createBuild(plugin, buildTarget, buildVersion, customKibanaVersion, buildFiles); 29 | }); 30 | } else { 31 | buildStep = createBuild(plugin, buildTarget, buildVersion, kibanaVersion, buildFiles); 32 | } 33 | 34 | return buildStep 35 | .then(function () { 36 | if (options.skipArchive) return; 37 | return createPackage(plugin, buildTarget, buildVersion); 38 | }); 39 | }; 40 | 41 | function askForKibanaVersion() { 42 | return inquirer.prompt([ 43 | { 44 | type: 'input', 45 | name: 'kibanaVersion', 46 | message: 'What version of Kibana are you building for?' 47 | } 48 | ]).then(function (answers) { 49 | return answers.kibanaVersion; 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /tasks/build/create_build.spec.js: -------------------------------------------------------------------------------- 1 | /*eslint-env jest*/ 2 | const { resolve } = require('path'); 3 | const del = require('del'); 4 | const createBuild = require('./create_build'); 5 | 6 | const PLUGIN_FIXTURE = resolve(__dirname, '__fixtures__/test_plugin'); 7 | const PLUGIN = require('../../lib/plugin_config')(PLUGIN_FIXTURE); 8 | const PLUGIN_BUILD_DIR = resolve(PLUGIN_FIXTURE, 'build'); 9 | const PLUGIN_BUILD_TARGET = resolve(PLUGIN_BUILD_DIR, 'kibana', PLUGIN.id); 10 | 11 | describe('create_build', () => { 12 | beforeEach(() => del(PLUGIN_BUILD_DIR)); 13 | afterEach(() => del(PLUGIN_BUILD_DIR)); 14 | 15 | describe('creating the build', function () { 16 | const buildTarget = resolve(PLUGIN.root, 'build'); 17 | const buildVersion = PLUGIN.version; 18 | const kibanaVersion = PLUGIN.version; 19 | const buildFiles = PLUGIN.buildSourcePatterns; 20 | 21 | it('removes development properties from package.json', function () { 22 | expect(PLUGIN.pkg.scripts).not.toBeUndefined(); 23 | expect(PLUGIN.pkg.devDependencies).not.toBeUndefined(); 24 | 25 | return createBuild(PLUGIN, buildTarget, buildVersion, kibanaVersion, buildFiles) 26 | .then(() => { 27 | const pkg = require(resolve(PLUGIN_BUILD_TARGET, 'package.json')); 28 | expect(pkg.scripts).toBeUndefined(); 29 | expect(pkg.devDependencies).toBeUndefined(); 30 | }); 31 | }); 32 | 33 | it('adds build metadata to package.json', function () { 34 | expect(PLUGIN.pkg.build).toBeUndefined(); 35 | 36 | return createBuild(PLUGIN, buildTarget, buildVersion, kibanaVersion, buildFiles) 37 | .then(() => { 38 | const pkg = require(resolve(PLUGIN_BUILD_TARGET, 'package.json')); 39 | expect(pkg.build).not.toBeUndefined(); 40 | expect(pkg.build.git).not.toBeUndefined(); 41 | expect(pkg.build.date).not.toBeUndefined(); 42 | }); 43 | }); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /tasks/build/create_build.js: -------------------------------------------------------------------------------- 1 | const join = require('path').join; 2 | const relative = require('path').relative; 3 | const statSync = require('fs').statSync; 4 | const execFileSync = require('child_process').execFileSync; 5 | const del = require('del'); 6 | const vfs = require('vinyl-fs'); 7 | const rename = require('gulp-rename'); 8 | 9 | const rewritePackageJson = require('./rewrite_package_json'); 10 | const winCmd = require('../../lib/win_cmd'); 11 | 12 | module.exports = function createBuild(plugin, buildTarget, buildVersion, kibanaVersion, files) { 13 | const buildSource = plugin.root; 14 | const buildRoot = join(buildTarget, 'kibana', plugin.id); 15 | 16 | return del(buildTarget) 17 | .then(function () { 18 | return new Promise(function (resolve, reject) { 19 | vfs 20 | .src(files, { cwd: buildSource, base: buildSource }) 21 | // modify the package.json file 22 | .pipe(rewritePackageJson(buildSource, buildVersion, kibanaVersion)) 23 | 24 | // put all files inside the correct directories 25 | .pipe(rename(function nestFileInDir(path) { 26 | const nonRelativeDirname = path.dirname.replace(/^(\.\.\/?)+/g, ''); 27 | path.dirname = join(relative(buildTarget, buildRoot), nonRelativeDirname); 28 | })) 29 | 30 | .pipe(vfs.dest(buildTarget)) 31 | .on('end', resolve) 32 | .on('error', reject); 33 | }); 34 | }) 35 | .then(function () { 36 | // install packages in build 37 | const options = { 38 | cwd: buildRoot, 39 | stdio: ['ignore', 'ignore', 'pipe'], 40 | }; 41 | 42 | try { 43 | // use yarn if yarn lockfile is found in the build 44 | statSync(join(buildRoot, 'yarn.lock')); 45 | execFileSync(winCmd('yarn'), ['install', '--production'], options); 46 | } catch (e) { 47 | // use npm if there is no yarn lockfile in the build 48 | execFileSync(winCmd('npm'), ['install', '--production', '--no-bin-links'], options); 49 | } 50 | }); 51 | }; 52 | -------------------------------------------------------------------------------- /tasks/test/browser/README.md: -------------------------------------------------------------------------------- 1 | writing tests 2 | ============= 3 | 4 | Browser tests are written just like server tests, they are just executed differently. 5 | 6 | - place tests near the code they test, in `__tests__` directories throughout 7 | the public directory 8 | 9 | - Use the same bdd-style `describe()` and `it()` 10 | api to define the suites and cases of your tests. 11 | 12 | ```js 13 | describe('some portion of your code', function () { 14 | it('should do this thing', function () { 15 | expect(true).to.be(false); 16 | }); 17 | }); 18 | ``` 19 | 20 | 21 | starting the test runner 22 | ======================== 23 | 24 | Under the covers this command uses the `test:browser` task from kibana. This will execute 25 | your tasks once and exit when complete. 26 | 27 | When run with the `--dev` option, the command uses the `test:dev` task from kibana. 28 | This task sets-up a test runner that will watch your code for changes and rebuild your 29 | tests when necessary. You access the test runner through a browser that it starts itself 30 | (via Karma). 31 | 32 | If your plugin consists of a number of internal plugins, you may wish to keep the tests 33 | isolated to a specific plugin or plugins, instead of executing all of the tests. To do this, 34 | use `--plugins` and passing the plugins you would like to test. Muliple plugins can be 35 | specified by separating them with commas. 36 | 37 | 38 | running the tests 39 | ================= 40 | 41 | Once the test runner has started you a new browser window should be opened and you should 42 | see a message saying "connected". Next to that is a "DEBUG" button. This button will open 43 | an interactive version of your tests that you can refresh, inspects, and otherwise debug 44 | while you write your tests. 45 | 46 | 47 | focus on the task at hand 48 | ========================= 49 | 50 | To limit the tests that run you can either: 51 | 52 | 1. use the ?grep= query string to filter the test cases/suites by name 53 | 2. Click the suite title or (play) button next to test output 54 | 3. Add `.only` to your `describe()` or `it()` calls: 55 | 56 | ```js 57 | describe.only('suite name', function () { 58 | // ... 59 | }); 60 | ``` 61 | -------------------------------------------------------------------------------- /cli.js: -------------------------------------------------------------------------------- 1 | const program = require('commander'); 2 | 3 | const pkg = require('./package.json'); 4 | const createCommanderAction = require('./lib/commander_action'); 5 | const docs = require('./lib/docs'); 6 | const enableCollectingUnknownOptions = require('./lib/enable_collecting_unknown_options'); 7 | 8 | program 9 | .version(pkg.version); 10 | 11 | enableCollectingUnknownOptions( 12 | program 13 | .command('start') 14 | .description('Start kibana and have it include this plugin') 15 | .on('--help', docs('start')) 16 | .action(createCommanderAction('start', (command) => ({ 17 | flags: command.unknownOptions 18 | }))) 19 | ); 20 | 21 | program 22 | .command('build [files...]') 23 | .description('Build a distributable archive') 24 | .on('--help', docs('build')) 25 | .option('--skip-archive', 'Don\'t create the zip file, leave the build path alone') 26 | .option('-d, --build-destination ', 'Target path for the build output, absolute or relative to the plugin root') 27 | .option('-b, --build-version ', 'Version for the build output') 28 | .option('-k, --kibana-version ', 'Kibana version for the build output') 29 | .action(createCommanderAction('build', (command, files) => ({ 30 | buildDestination: command.buildDestination, 31 | buildVersion: command.buildVersion, 32 | kibanaVersion: command.kibanaVersion, 33 | skipArchive: Boolean(command.skipArchive), 34 | files: files, 35 | }))); 36 | 37 | program 38 | .command('test') 39 | .description('Run the server and browser tests') 40 | .on('--help', docs('test/all')) 41 | .action(createCommanderAction('testAll')); 42 | 43 | program 44 | .command('test:browser') 45 | .description('Run the browser tests in a real web browser') 46 | .option('--dev', 'Enable dev mode, keeps the test server running') 47 | .option('-p, --plugins ', 'Manually specify which plugins\' test bundles to run') 48 | .on('--help', docs('test/browser')) 49 | .action(createCommanderAction('testBrowser', (command) => ({ 50 | dev: Boolean(command.dev), 51 | plugins: command.plugins, 52 | }))); 53 | 54 | program 55 | .command('test:server [files...]') 56 | .description('Run the server tests using mocha') 57 | .on('--help', docs('test/server')) 58 | .action(createCommanderAction('testServer', (command, files) => ({ 59 | files: files 60 | }))); 61 | 62 | program 63 | .parse(process.argv); 64 | -------------------------------------------------------------------------------- /lib/commander_action.spec.js: -------------------------------------------------------------------------------- 1 | /*eslint-env jest*/ 2 | 3 | const createCommanderAction = require('./commander_action'); 4 | const run = require('./run'); 5 | 6 | jest.mock('./run', () => jest.fn()); 7 | 8 | const STACK_TRACE_RE = /\n(?:\s+at .+(?:\n|$))+/g; 9 | expect.addSnapshotSerializer({ 10 | print(val, serialize) { 11 | return serialize(val.replace(STACK_TRACE_RE, '\n ...stack trace...\n')); 12 | }, 13 | 14 | test(val) { 15 | return typeof val === 'string' && STACK_TRACE_RE.test(val); 16 | }, 17 | }); 18 | 19 | beforeAll(() => { 20 | jest.spyOn(process.stderr, 'write').mockImplementation(() => {}); 21 | jest.spyOn(process, 'exit').mockImplementation(() => {}); 22 | }); 23 | 24 | beforeEach(() => { 25 | run.mockReset(); 26 | jest.clearAllMocks(); 27 | }); 28 | 29 | afterAll(() => { 30 | jest.restoreAllMocks(); 31 | }); 32 | 33 | describe('commander action', () => { 34 | it('creates a function', () => { 35 | expect(typeof createCommanderAction()).toBe('function'); 36 | }); 37 | 38 | it('passes args to getOptions, calls run() with taskName and options', () => { 39 | const action = createCommanderAction('taskName', (...args) => ({ args })); 40 | return action('a', 'b', 'c', 'd', 'e', 'f').then(() => { 41 | expect(run).toHaveBeenCalledTimes(1); 42 | expect(run.mock.calls).toMatchSnapshot(); 43 | }); 44 | }); 45 | 46 | it('exits with status 1 when task throws synchronously', () => { 47 | run.mockImplementation(() => { 48 | throw new Error('sync error thrown'); 49 | }); 50 | 51 | return createCommanderAction('mockTask')().then(() => { 52 | expect(process.stderr.write).toHaveBeenCalledTimes(1); 53 | expect(process.stderr.write.mock.calls).toMatchSnapshot(); 54 | expect(process.exit).toHaveBeenCalledTimes(1); 55 | expect(process.exit).toHaveBeenCalledWith(1); 56 | }); 57 | }); 58 | 59 | it('exits with status 1 when task throws error asynchronously', () => { 60 | run.mockImplementation(() => { 61 | return Promise.reject(new Error('async error thrown')); 62 | }); 63 | 64 | return createCommanderAction('mockTask')().then(() => { 65 | expect(process.stderr.write).toHaveBeenCalledTimes(1); 66 | expect(process.stderr.write.mock.calls).toMatchSnapshot(); 67 | expect(process.exit).toHaveBeenCalledTimes(1); 68 | expect(process.exit).toHaveBeenCalledWith(1); 69 | }); 70 | }); 71 | }); 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kibana-plugin-helpers 2 | 3 | ## Note: the default branch on this repo is 7.x since the changes in master have moved to the kibana project 4 | 5 | > **NOTE:** Kibana now includes [its own plugin helpers](https://github.com/elastic/kibana/tree/master/packages/kbn-plugin-helpers). You should use these if you are targeting Kibana 6.3+. See https://github.com/elastic/kibana/tree/master/packages/kbn-plugin-helpers for installation info. 6 | 7 | [![Apache License](https://img.shields.io/badge/license-apache_2.0-a9215a.svg)](https://raw.githubusercontent.com/elastic/kibana-plugin-helpers/master/LICENSE) 8 | [![CircleCI](https://img.shields.io/circleci/project/github/elastic/kibana-plugin-helpers.svg)](https://circleci.com/gh/elastic/kibana-plugin-helpers/tree/master) 9 | 10 | Just some helpers for kibana plugin devs. 11 | 12 | This simple CLI has several tasks that plugin devs can run from to easily debug, test, or package kibana plugins. 13 | 14 | ```sh 15 | $ plugin-helpers help 16 | 17 | Usage: plugin-helpers [options] [command] 18 | 19 | Commands: 20 | 21 | start Start kibana and have it include this plugin 22 | build [options] [files...] Build a distributable archive 23 | test Run the server and browser tests 24 | test:browser [options] Run the browser tests in a real web browser 25 | test:server [files...] Run the server tests using mocha 26 | 27 | Options: 28 | 29 | -h, --help output usage information 30 | -V, --version output the version number 31 | 32 | ``` 33 | 34 | ## Versions 35 | 36 | Plugin Helpers | Kibana 37 | -------------- | ------ 38 | [bundled plugin helpers](https://github.com/elastic/kibana/tree/master/packages/kbn-plugin-helpers) | 6.3+ 39 | 7.x | 4.6.x to 6.2 (node 6+ only) 40 | 6.x | 4.6.x to 6.2 41 | 5.x | 4.x 42 | 43 | ## Configuration 44 | 45 | `plugin-helpers` accepts a number of settings, which can be specified at runtime, or included in a `.kibana-plugin-helpers.json` file if you'd like to bundle those settings with your project. 46 | 47 | It will also observe a `.kibana-plugin-helpers.dev.json`, much like Kibana does, which we encourage you to add to your `.gitignore` file and use for local settings that you don't intend to share. These "dev" settings will override any settings in the normal json config. 48 | 49 | All configuration setting listed below can simply can be included in the json config files. If you intend to inline the command, you will need to convert the setting to snake case (ie. `skipArchive` becomes `--skip-archive`). 50 | 51 | ## Global settings 52 | 53 | Setting | Description 54 | ------- | ----------- 55 | `kibanaRoot` | Path to your checkout of Kibana, relative paths are ok 56 | 57 | ### Settings for `start` 58 | 59 | Setting | Description 60 | ------- | ----------- 61 | `includePlugins` | Intended to be used in a config file, an array of additional plugin paths to include, absolute or relative to the plugin root 62 | `*` | Any options/flags included will be passed unmodified to the Kibana binary 63 | 64 | ### Settings for `build` 65 | 66 | Setting | Description 67 | ------- | ----------- 68 | `skipArchive` | Don't create the zip file, leave the build path alone 69 | `buildDestination` | Target path for the build output, absolute or relative to the plugin root 70 | `buildVersion` | Version for the build output 71 | `kibanaVersion` | Kibana version for the build output (added to package.json) 72 | -------------------------------------------------------------------------------- /tasks/build/build_action.spec.js: -------------------------------------------------------------------------------- 1 | /*eslint-env jest*/ 2 | const resolve = require('path').resolve; 3 | const fs = require('fs'); 4 | const del = require('del'); 5 | 6 | const PLUGIN_FIXTURE = resolve(__dirname, '__fixtures__/test_plugin'); 7 | const PLUGIN_BUILD_DIR = resolve(PLUGIN_FIXTURE, 'build'); 8 | const PLUGIN = require('../../lib/plugin_config')(PLUGIN_FIXTURE); 9 | const noop = function () {}; 10 | 11 | describe('build_action', () => { 12 | describe('creating build zip', function () { 13 | const buildAction = require('./build_action'); 14 | 15 | beforeEach(() => del(PLUGIN_BUILD_DIR)); 16 | afterEach(() => del(PLUGIN_BUILD_DIR)); 17 | 18 | it('creates a zip in the build directory', () => { 19 | return buildAction(PLUGIN).then(() => { 20 | const buildFile = resolve(PLUGIN_BUILD_DIR, PLUGIN.id + '-' + PLUGIN.version + '.zip'); 21 | if (!fs.existsSync(buildFile)) { 22 | throw new Error('Build file not found: ' + buildFile); 23 | } 24 | }); 25 | }); 26 | 27 | it('skips zip creation based on flag', function () { 28 | return buildAction(PLUGIN, noop, { skipArchive: true }).then(() => { 29 | const buildFile = resolve(PLUGIN_BUILD_DIR, PLUGIN.id + '-' + PLUGIN.version + '.zip'); 30 | if (fs.existsSync(buildFile)) { 31 | throw new Error('Build file not found: ' + buildFile); 32 | } 33 | }); 34 | }); 35 | }); 36 | 37 | describe('calling create_build', () => { 38 | let mockBuild; 39 | let buildAction; 40 | 41 | beforeEach(() => { 42 | jest.resetModules(); 43 | mockBuild = jest.fn(() => Promise.resolve()); 44 | jest.mock('./create_build', () => mockBuild); 45 | buildAction = require('./build_action'); 46 | }); 47 | 48 | it('takes optional build version', function () { 49 | const options = { 50 | buildVersion: '1.2.3', 51 | kibanaVersion: '4.5.6', 52 | }; 53 | 54 | return buildAction(PLUGIN, noop, options).then(() => { 55 | expect(mockBuild.mock.calls).toHaveLength(1); 56 | // eslint-disable-next-line no-unused-vars 57 | const [ plugin, buildTarget, buildVersion, kibanaVersion, files ] = mockBuild.mock.calls[0]; 58 | expect(buildVersion).toBe('1.2.3'); 59 | expect(kibanaVersion).toBe('4.5.6'); 60 | }); 61 | }); 62 | 63 | it('uses default file list without files option', function () { 64 | return buildAction(PLUGIN).then(() => { 65 | expect(mockBuild.mock.calls).toHaveLength(1); 66 | // eslint-disable-next-line no-unused-vars 67 | const [ plugin, buildTarget, buildVersion, kibanaVersion, files ] = mockBuild.mock.calls[0]; 68 | PLUGIN.buildSourcePatterns.forEach(file => expect(files).toContain(file)); 69 | }); 70 | }); 71 | 72 | it('uses only files passed in', function () { 73 | const options = { 74 | files: [ 75 | 'index.js', 76 | 'LICENSE.txt', 77 | 'plugins/**/*', 78 | '{server,public}/**/*' 79 | ] 80 | }; 81 | 82 | return buildAction(PLUGIN, noop, options).then(() => { 83 | expect(mockBuild.mock.calls).toHaveLength(1); 84 | // eslint-disable-next-line no-unused-vars 85 | const [ plugin, buildTarget, buildVersion, kibanaVersion, files ] = mockBuild.mock.calls[0]; 86 | options.files.forEach(file => expect(files).toContain(file)); 87 | }); 88 | }); 89 | 90 | it('rejects returned promise when build fails', () => { 91 | mockBuild.mockImplementation(() => { 92 | return Promise.reject(new Error('foo bar')); 93 | }); 94 | 95 | return expect(buildAction(PLUGIN, noop)).rejects.toThrowErrorMatchingSnapshot(); 96 | }); 97 | }); 98 | }); 99 | --------------------------------------------------------------------------------