mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Enable custom builds (elastic/kibana-plugin-helpers#27)
* only modify root package.json file previously this was modifying every package.json from node_modules as well * refactor the build task export the build, define helpers outside of the task * allow custom kibana and build versions both can be passed via flags * allow custom build globs to be specified * move build into its own module * add simple option parsing tests * update readme * move dependency file appending into the action * put source and target into variables * move config file loading into a module * refactor test_server_action slightly be more explicit about the files option overwriting the plugin settings * move default build patterns to plugin config allows the setting to be overridden via the config file * fix dirname on relative includes trim any leading '../' off the path when moving it into the build target * move node_module dirs into plugin_config module, use existing promises * rename file_config => config_file Original commit: elastic/kibana-plugin-helpers@743e4a37c2
This commit is contained in:
parent
4cc81e2c89
commit
ceb52252be
8 changed files with 248 additions and 149 deletions
|
@ -16,11 +16,11 @@ $ plugin-helpers help
|
|||
|
||||
Commands:
|
||||
|
||||
start Start kibana and have it include this plugin
|
||||
build Build a distributable archive
|
||||
test Run the server and browser tests
|
||||
test:browser [options] Run the browser tests in a real web browser
|
||||
test:server [files...] Run the server tests using mocha
|
||||
start Start kibana and have it include this plugin
|
||||
build [options] [files...] Build a distributable archive
|
||||
test Run the server and browser tests
|
||||
test:browser [options] Run the browser tests in a real web browser
|
||||
test:server [files...] Run the server tests using mocha
|
||||
|
||||
Options:
|
||||
|
||||
|
|
|
@ -31,11 +31,17 @@ enableCollectingUnknownOptions(
|
|||
);
|
||||
|
||||
program
|
||||
.command('build')
|
||||
.command('build [files...]')
|
||||
.description('Build a distributable archive')
|
||||
.on('--help', docs('build'))
|
||||
.action(taskRunner(function () {
|
||||
run('build');
|
||||
.option('-b, --build-version <version>', 'Version for the build output')
|
||||
.option('-k, --kibana-version <version>', 'Kibana version for the build output')
|
||||
.action(taskRunner(function (command, files) {
|
||||
run('build', {
|
||||
buildVersion: command.buildVersion,
|
||||
kibanaVersion: command.kibanaVersion,
|
||||
files: files,
|
||||
});
|
||||
}));
|
||||
|
||||
program
|
||||
|
|
30
packages/kbn-plugin-helpers/lib/config_file.js
Normal file
30
packages/kbn-plugin-helpers/lib/config_file.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
var resolve = require('path').resolve;
|
||||
var readFileSync = require('fs').readFileSync;
|
||||
|
||||
var configFiles = [ '.kibana-plugin-helpers.json', '.kibana-plugin-helpers.dev.json' ];
|
||||
var configCache = {};
|
||||
|
||||
module.exports = function (root) {
|
||||
if (!root) root = process.cwd();
|
||||
|
||||
if (configCache[root]) {
|
||||
return configCache[root];
|
||||
}
|
||||
|
||||
// config files to read from, in the order they are merged together
|
||||
var config = configCache[root] = {};
|
||||
|
||||
configFiles.forEach(function (configFile) {
|
||||
try {
|
||||
var content = JSON.parse(readFileSync(resolve(root, configFile)));
|
||||
config = Object.assign(config, content);
|
||||
} catch (e) {
|
||||
// noop
|
||||
}
|
||||
});
|
||||
|
||||
// if the kibanaRoot is set, use resolve to ensure correct resolution
|
||||
if (config.kibanaRoot) config.kibanaRoot = resolve(root, config.kibanaRoot);
|
||||
|
||||
return config;
|
||||
};
|
|
@ -1,29 +1,32 @@
|
|||
var resolve = require('path').resolve;
|
||||
var readFileSync = require('fs').readFileSync;
|
||||
var configFile = require('./config_file');
|
||||
|
||||
module.exports = function (root) {
|
||||
if (!root) root = process.cwd();
|
||||
|
||||
var pkg = require(resolve(root, 'package.json'));
|
||||
// config files to read from, in the order they are merged together
|
||||
var configFiles = [ '.kibana-plugin-helpers.json', '.kibana-plugin-helpers.dev.json' ];
|
||||
var config = {};
|
||||
var config = configFile(root);
|
||||
|
||||
configFiles.forEach(function (configFile) {
|
||||
try {
|
||||
var content = JSON.parse(readFileSync(resolve(root, configFile)));
|
||||
config = Object.assign(config, content);
|
||||
} catch (e) {
|
||||
// noop
|
||||
}
|
||||
});
|
||||
var buildSourcePatterns = [
|
||||
'package.json',
|
||||
'index.js',
|
||||
'{lib,public,server,webpackShims}/**/*',
|
||||
];
|
||||
|
||||
// if the kibanaRoot is set, use resolve to ensure correct resolution
|
||||
if (config.kibanaRoot) config.kibanaRoot = resolve(root, config.kibanaRoot);
|
||||
// add dependency files
|
||||
var deps = Object.keys(pkg.dependencies || {});
|
||||
if (deps.length === 1) {
|
||||
buildSourcePatterns.push(`node_modules/${ deps[0] }/**/*`);
|
||||
} else if (deps.length) {
|
||||
buildSourcePatterns.push(`node_modules/{${ deps.join(',') }}/**/*`);
|
||||
}
|
||||
|
||||
return Object.assign({
|
||||
root: root,
|
||||
kibanaRoot: resolve(root, '../kibana'),
|
||||
serverTestPatterns: ['server/**/__tests__/**/*.js'],
|
||||
buildSourcePatterns: buildSourcePatterns,
|
||||
id: pkg.name,
|
||||
pkg: pkg,
|
||||
version: pkg.version,
|
||||
|
|
|
@ -1,122 +1,39 @@
|
|||
var vfs = require('vinyl-fs');
|
||||
var zip = require('gulp-zip');
|
||||
var map = require('through2-map').obj;
|
||||
var rename = require('gulp-rename');
|
||||
var join = require('path').join;
|
||||
var inquirer = require('inquirer');
|
||||
var execFileSync = require('child_process').execFileSync;
|
||||
|
||||
module.exports = function (plugin) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var createBuild = require('./create_build');
|
||||
|
||||
function main() {
|
||||
var kibanaVersion = (plugin.pkg.kibana && plugin.pkg.kibana.version) || plugin.pkg.version;
|
||||
var deps = Object.keys(plugin.pkg.dependencies || {});
|
||||
var buildId = `${plugin.id}-${plugin.version}`;
|
||||
module.exports = function (plugin, run, options) {
|
||||
options = options || {};
|
||||
var buildVersion = plugin.version;
|
||||
var kibanaVersion = (plugin.pkg.kibana && plugin.pkg.kibana.version) || plugin.pkg.version;
|
||||
var buildFiles = plugin.buildSourcePatterns;
|
||||
|
||||
if (kibanaVersion === 'kibana') {
|
||||
askForKibanaVersion(function (customKibanaVersion) {
|
||||
build(buildId, deps, customKibanaVersion);
|
||||
});
|
||||
} else {
|
||||
build(buildId, deps, kibanaVersion);
|
||||
}
|
||||
}
|
||||
// allow source files to be overridden
|
||||
if (options.files && options.files.length) {
|
||||
buildFiles = options.files;
|
||||
}
|
||||
|
||||
function askForKibanaVersion(cb) {
|
||||
inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'kibanaVersion',
|
||||
message: 'What version of Kibana are you building for?'
|
||||
}
|
||||
]).then(function (answers) {
|
||||
cb(answers.kibanaVersion);
|
||||
});
|
||||
}
|
||||
// allow options to override plugin info
|
||||
if (options.buildVersion) buildVersion = options.buildVersion;
|
||||
if (options.kibanaVersion) kibanaVersion = options.kibanaVersion;
|
||||
|
||||
function toBuffer(string) {
|
||||
if (typeof Buffer.from === 'function') {
|
||||
return Buffer.from(string, 'utf8');
|
||||
} else {
|
||||
// this was deprecated in node v5 in favor
|
||||
// of Buffer.from(string, encoding)
|
||||
return new Buffer(string, 'utf8');
|
||||
}
|
||||
}
|
||||
|
||||
function gitInfo() {
|
||||
try {
|
||||
var LOG_SEPARATOR = '||';
|
||||
var commitCount = execFileSync('git', ['rev-list', '--count', 'HEAD'], {
|
||||
cwd: plugin.root,
|
||||
stdio: ['ignore', 'pipe', 'ignore'],
|
||||
encoding: 'utf8',
|
||||
});
|
||||
var logLine = execFileSync('git', ['log', '--pretty=%h' + LOG_SEPARATOR + '%cD', '-n', '1'], {
|
||||
cwd: plugin.root,
|
||||
stdio: ['ignore', 'pipe', 'ignore'],
|
||||
encoding: 'utf8',
|
||||
}).split(LOG_SEPARATOR);
|
||||
|
||||
return {
|
||||
count: commitCount.trim(),
|
||||
sha: logLine[0].trim(),
|
||||
date: logLine[1].trim(),
|
||||
};
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function build(buildId, deps, kibanaVersion) {
|
||||
var files = [
|
||||
'package.json',
|
||||
'index.js',
|
||||
'{lib,public,server,webpackShims}/**/*'
|
||||
];
|
||||
|
||||
if (deps.length === 1) {
|
||||
files.push(`node_modules/${ deps[0] }/**/*`);
|
||||
} else if (deps.length) {
|
||||
files.push(`node_modules/{${ deps.join(',') }}/**/*`);
|
||||
}
|
||||
|
||||
vfs
|
||||
.src(files, { cwd: plugin.root, base: plugin.root })
|
||||
|
||||
// modify the package.json file
|
||||
.pipe(map(function (file) {
|
||||
if (file.basename === 'package.json') {
|
||||
var pkg = JSON.parse(file.contents.toString('utf8'));
|
||||
|
||||
// rewrite the target kibana version while the
|
||||
// file is on it's way to the archive
|
||||
if (!pkg.kibana) pkg.kibana = {};
|
||||
pkg.kibana.version = kibanaVersion;
|
||||
|
||||
// append build info
|
||||
pkg.build = {
|
||||
git: gitInfo(),
|
||||
date: new Date().toString()
|
||||
};
|
||||
|
||||
file.contents = toBuffer(JSON.stringify(pkg, null, 2));
|
||||
}
|
||||
|
||||
return file;
|
||||
}))
|
||||
|
||||
// put all files inside the correct directoried
|
||||
.pipe(rename(function nestFileInDir(path) {
|
||||
path.dirname = join('kibana', plugin.id, path.dirname);
|
||||
}))
|
||||
|
||||
.pipe(zip(`${buildId}.zip`))
|
||||
.pipe(vfs.dest(join(plugin.root, 'build')))
|
||||
.on('end', resolve);
|
||||
}
|
||||
|
||||
main();
|
||||
});
|
||||
if (kibanaVersion === 'kibana') {
|
||||
return askForKibanaVersion().then(function (customKibanaVersion) {
|
||||
return createBuild(plugin, buildVersion, customKibanaVersion, buildFiles);
|
||||
});
|
||||
} else {
|
||||
return createBuild(plugin, buildVersion, kibanaVersion, buildFiles);
|
||||
}
|
||||
};
|
||||
|
||||
function askForKibanaVersion(cb) {
|
||||
return inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'kibanaVersion',
|
||||
message: 'What version of Kibana are you building for?'
|
||||
}
|
||||
]).then(function (answers) {
|
||||
return answers.kibanaVersion;
|
||||
});
|
||||
}
|
|
@ -1,24 +1,78 @@
|
|||
/*eslint-env jest*/
|
||||
const resolve = require('path').resolve;
|
||||
const fs = require('fs');
|
||||
|
||||
const del = require('del');
|
||||
|
||||
const buildAction = require('./build_action');
|
||||
|
||||
const PLUGIN_FIXTURE = resolve(__dirname, '__fixtures__/test_plugin');
|
||||
const PLUGIN_BUILD_DIR = resolve(PLUGIN_FIXTURE, 'build');
|
||||
const PLUGIN = require('../../lib/plugin_config')(PLUGIN_FIXTURE);
|
||||
const noop = function () {};
|
||||
|
||||
describe('build_action', () => {
|
||||
beforeEach(() => del(PLUGIN_BUILD_DIR));
|
||||
afterEach(() => del(PLUGIN_BUILD_DIR));
|
||||
describe('creating build zip', function () {
|
||||
const buildAction = require('./build_action');
|
||||
|
||||
it('creates a zip in the build directory', () => {
|
||||
return buildAction(PLUGIN).then(() => {
|
||||
if (!fs.existsSync(resolve(PLUGIN_BUILD_DIR, PLUGIN.id + '-' + PLUGIN.version + '.zip'))) {
|
||||
throw new Error('expected the plugin to build a zip file');
|
||||
}
|
||||
beforeEach(() => del(PLUGIN_BUILD_DIR));
|
||||
afterEach(() => del(PLUGIN_BUILD_DIR));
|
||||
|
||||
it('creates a zip in the build directory', () => {
|
||||
return buildAction(PLUGIN).then(() => {
|
||||
var buildFile = resolve(PLUGIN_BUILD_DIR, PLUGIN.id + '-' + PLUGIN.version + '.zip');
|
||||
if (!fs.existsSync(buildFile)) {
|
||||
throw new Error('Build file not found: ' + buildFile);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('calling create_build', () => {
|
||||
let mockBuild;
|
||||
let buildAction;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
mockBuild = jest.fn(() => Promise.resolve());
|
||||
jest.mock('./create_build', () => mockBuild);
|
||||
buildAction = require('./build_action');
|
||||
});
|
||||
|
||||
it('takes optional build version', function () {
|
||||
const options = {
|
||||
buildVersion: '1.2.3',
|
||||
kibanaVersion: '4.5.6',
|
||||
};
|
||||
|
||||
return buildAction(PLUGIN, noop, options).then(() => {
|
||||
expect(mockBuild.mock.calls).toHaveLength(1);
|
||||
const [ plugin, buildVersion, kibanaVersion, files ] = mockBuild.mock.calls[0];
|
||||
expect(buildVersion).toBe('1.2.3');
|
||||
expect(kibanaVersion).toBe('4.5.6');
|
||||
});
|
||||
});
|
||||
|
||||
it('uses default file list without files option', function () {
|
||||
return buildAction(PLUGIN).then(() => {
|
||||
expect(mockBuild.mock.calls).toHaveLength(1);
|
||||
const [ plugin, buildVersion, kibanaVersion, files ] = mockBuild.mock.calls[0];
|
||||
PLUGIN.buildSourcePatterns.forEach(file => expect(files).toContain(file));
|
||||
});
|
||||
});
|
||||
|
||||
it('uses only files passed in', function () {
|
||||
const options = {
|
||||
files: [
|
||||
'index.js',
|
||||
'LICENSE.txt',
|
||||
'plugins/**/*',
|
||||
'{server,public}/**/*'
|
||||
]
|
||||
};
|
||||
|
||||
return buildAction(PLUGIN, noop, options).then(() => {
|
||||
expect(mockBuild.mock.calls).toHaveLength(1);
|
||||
const [ plugin, buildVersion, kibanaVersion, files ] = mockBuild.mock.calls[0];
|
||||
options.files.forEach(file => expect(files).toContain(file));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
84
packages/kbn-plugin-helpers/tasks/build/create_build.js
Normal file
84
packages/kbn-plugin-helpers/tasks/build/create_build.js
Normal file
|
@ -0,0 +1,84 @@
|
|||
var join = require('path').join;
|
||||
var execFileSync = require('child_process').execFileSync;
|
||||
var vfs = require('vinyl-fs');
|
||||
var zip = require('gulp-zip');
|
||||
var map = require('through2-map').obj;
|
||||
var rename = require('gulp-rename');
|
||||
|
||||
module.exports = function createBuild(plugin, buildVersion, kibanaVersion, files) {
|
||||
var buildId = `${plugin.id}-${buildVersion}`;
|
||||
var buildSource = plugin.root;
|
||||
var buildTarget = join(plugin.root, 'build');
|
||||
|
||||
return new Promise(function (resolve) {
|
||||
vfs
|
||||
.src(files, { cwd: buildSource, base: buildSource })
|
||||
|
||||
// modify the package.json file
|
||||
.pipe(map(function (file) {
|
||||
if (file.basename === 'package.json' && file.dirname === buildSource) {
|
||||
var pkg = JSON.parse(file.contents.toString('utf8'));
|
||||
|
||||
// rewrite the target kibana version while the
|
||||
// file is on it's way to the archive
|
||||
if (!pkg.kibana) pkg.kibana = {};
|
||||
pkg.kibana.version = kibanaVersion;
|
||||
pkg.version = buildVersion;
|
||||
|
||||
// append build info
|
||||
pkg.build = {
|
||||
git: gitInfo(buildSource),
|
||||
date: new Date().toString()
|
||||
};
|
||||
|
||||
file.contents = toBuffer(JSON.stringify(pkg, null, 2));
|
||||
}
|
||||
|
||||
return file;
|
||||
}))
|
||||
|
||||
// put all files inside the correct directories
|
||||
.pipe(rename(function nestFileInDir(path) {
|
||||
var nonRelativeDirname = path.dirname.replace(/^(\.\.\/?)+/g, '');
|
||||
path.dirname = join('kibana', plugin.id, nonRelativeDirname);
|
||||
}))
|
||||
|
||||
.pipe(zip(`${buildId}.zip`))
|
||||
.pipe(vfs.dest(buildTarget))
|
||||
.on('end', resolve);
|
||||
});
|
||||
};
|
||||
|
||||
function toBuffer(string) {
|
||||
if (typeof Buffer.from === 'function') {
|
||||
return Buffer.from(string, 'utf8');
|
||||
} else {
|
||||
// this was deprecated in node v5 in favor
|
||||
// of Buffer.from(string, encoding)
|
||||
return new Buffer(string, 'utf8');
|
||||
}
|
||||
}
|
||||
|
||||
function gitInfo(rootPath) {
|
||||
try {
|
||||
var LOG_SEPARATOR = '||';
|
||||
var commitCount = execFileSync('git', ['rev-list', '--count', 'HEAD'], {
|
||||
cwd: rootPath,
|
||||
stdio: ['ignore', 'pipe', 'ignore'],
|
||||
encoding: 'utf8',
|
||||
});
|
||||
var logLine = execFileSync('git', ['log', '--pretty=%h' + LOG_SEPARATOR + '%cD', '-n', '1'], {
|
||||
cwd: rootPath,
|
||||
stdio: ['ignore', 'pipe', 'ignore'],
|
||||
encoding: 'utf8',
|
||||
}).split(LOG_SEPARATOR);
|
||||
|
||||
return {
|
||||
count: commitCount.trim(),
|
||||
sha: logLine[0].trim(),
|
||||
date: logLine[1].trim(),
|
||||
};
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
}
|
|
@ -3,12 +3,17 @@ var delimiter = require('path').delimiter;
|
|||
var execFileSync = require('child_process').execFileSync;
|
||||
|
||||
module.exports = function (plugin, run, options) {
|
||||
options = options || {};
|
||||
var kibanaBins = resolve(plugin.kibanaRoot, 'node_modules/.bin');
|
||||
var mochaSetupJs = resolve(plugin.kibanaRoot, 'test/mocha_setup.js');
|
||||
options = options || {};
|
||||
var testPaths = plugin.serverTestPatterns;
|
||||
|
||||
// allow server test files to be overridden
|
||||
if (options.files && options.files.length) {
|
||||
testPaths = options.files;
|
||||
}
|
||||
|
||||
var cmd = 'mocha';
|
||||
var testPaths = (options.files && options.files.length) ? options.files : plugin.serverTestPatterns;
|
||||
var args = ['--require', mochaSetupJs].concat(testPaths);
|
||||
var path = `${kibanaBins}${delimiter}${process.env.PATH}`;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue