[kbn/optimizer] add support for --focus option (#80436)

Co-authored-by: spalger <spalger@users.noreply.github.com>
This commit is contained in:
Spencer 2020-10-14 08:16:27 -07:00 committed by GitHub
parent 3d6d4a62b9
commit bc4093a0cb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 158 additions and 6 deletions

View file

@ -95,6 +95,11 @@ run(
throw createFlagError('expected --filter to be one or more strings');
}
const focus = typeof flags.focus === 'string' ? [flags.focus] : flags.focus;
if (!Array.isArray(focus) || !focus.every((f) => typeof f === 'string')) {
throw createFlagError('expected --focus to be one or more strings');
}
const validateLimits = flags['validate-limits'] ?? false;
if (typeof validateLimits !== 'boolean') {
throw createFlagError('expected --validate-limits to have no value');
@ -118,6 +123,7 @@ run(
inspectWorkers,
includeCoreBundle,
filter,
focus,
});
if (validateLimits) {
@ -165,6 +171,7 @@ run(
cache: true,
'inspect-workers': true,
filter: [],
focus: [],
},
help: `
--watch run the optimizer in watch mode
@ -173,6 +180,7 @@ run(
--profile profile the webpack builds and write stats.json files to build outputs
--no-core disable generating the core bundle
--no-cache disable the cache
--focus just like --filter, except dependencies are automatically included, --filter applies to result
--filter comma-separated list of bundle id filters, results from multiple flags are merged, * and ! are supported
--no-examples don't build the example plugins
--dist create bundles that are suitable for inclusion in the Kibana distributable, enabled when running with --update-limits

View file

@ -0,0 +1,80 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import Path from 'path';
import { focusBundles } from './focus_bundles';
import { Bundle } from '../common';
function createBundle(id: string, deps: ReturnType<Bundle['readBundleDeps']>) {
const bundle = new Bundle({
type: id === 'core' ? 'entry' : 'plugin',
id,
contextDir: Path.resolve('/kibana/plugins', id),
outputDir: Path.resolve('/kibana/plugins', id, 'target/public'),
publicDirNames: ['public'],
sourceRoot: Path.resolve('/kibana'),
});
jest.spyOn(bundle, 'readBundleDeps').mockReturnValue(deps);
return bundle;
}
const BUNDLES = [
createBundle('core', {
implicit: [],
explicit: [],
}),
createBundle('foo', {
implicit: ['core'],
explicit: [],
}),
createBundle('bar', {
implicit: ['core'],
explicit: ['foo'],
}),
createBundle('baz', {
implicit: ['core'],
explicit: ['bar'],
}),
createBundle('box', {
implicit: ['core'],
explicit: ['foo'],
}),
];
function test(filters: string[]) {
return focusBundles(filters, BUNDLES)
.map((b) => b.id)
.sort((a, b) => a.localeCompare(b))
.join(', ');
}
it('returns all bundles when no focus filters are defined', () => {
expect(test([])).toMatchInlineSnapshot(`"bar, baz, box, core, foo"`);
});
it('includes a single instance of all implicit and explicit dependencies', () => {
expect(test(['core'])).toMatchInlineSnapshot(`"core"`);
expect(test(['foo'])).toMatchInlineSnapshot(`"core, foo"`);
expect(test(['bar'])).toMatchInlineSnapshot(`"bar, core, foo"`);
expect(test(['baz'])).toMatchInlineSnapshot(`"bar, baz, core, foo"`);
expect(test(['box'])).toMatchInlineSnapshot(`"box, core, foo"`);
});

View file

@ -0,0 +1,44 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { Bundle } from '../common';
import { filterById } from './filter_by_id';
export function focusBundles(filters: string[], bundles: Bundle[]) {
if (!filters.length) {
return [...bundles];
}
const queue = new Set<Bundle>(filterById(filters, bundles));
const focused: Bundle[] = [];
for (const bundle of queue) {
focused.push(bundle);
const { explicit, implicit } = bundle.readBundleDeps();
const depIds = [...explicit, ...implicit];
if (depIds.length) {
for (const dep of filterById(depIds, bundles)) {
queue.add(dep);
}
}
}
return focused;
}

View file

@ -22,6 +22,7 @@ jest.mock('./kibana_platform_plugins.ts');
jest.mock('./get_plugin_bundles.ts');
jest.mock('../common/theme_tags.ts');
jest.mock('./filter_by_id.ts');
jest.mock('./focus_bundles');
jest.mock('../limits.ts');
jest.mock('os', () => {
@ -121,6 +122,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"cache": true,
"dist": false,
"filters": Array [],
"focus": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
@ -149,6 +151,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"cache": false,
"dist": false,
"filters": Array [],
"focus": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
@ -177,6 +180,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"cache": true,
"dist": false,
"filters": Array [],
"focus": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
@ -207,6 +211,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"cache": true,
"dist": false,
"filters": Array [],
"focus": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
@ -234,6 +239,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"cache": true,
"dist": false,
"filters": Array [],
"focus": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
@ -261,6 +267,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"cache": true,
"dist": false,
"filters": Array [],
"focus": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
@ -285,6 +292,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"cache": false,
"dist": false,
"filters": Array [],
"focus": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
@ -309,6 +317,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"cache": false,
"dist": false,
"filters": Array [],
"focus": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
@ -334,6 +343,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"cache": false,
"dist": false,
"filters": Array [],
"focus": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
@ -359,6 +369,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"cache": true,
"dist": false,
"filters": Array [],
"focus": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
@ -386,6 +397,7 @@ describe('OptimizerConfig::create()', () => {
.findKibanaPlatformPlugins;
const getPluginBundles: jest.Mock = jest.requireMock('./get_plugin_bundles.ts').getPluginBundles;
const filterById: jest.Mock = jest.requireMock('./filter_by_id.ts').filterById;
const focusBundles: jest.Mock = jest.requireMock('./focus_bundles').focusBundles;
const readLimits: jest.Mock = jest.requireMock('../limits.ts').readLimits;
beforeEach(() => {
@ -400,6 +412,7 @@ describe('OptimizerConfig::create()', () => {
findKibanaPlatformPlugins.mockReturnValue(Symbol('new platform plugins'));
getPluginBundles.mockReturnValue([Symbol('bundle1'), Symbol('bundle2')]);
filterById.mockReturnValue(Symbol('filtered bundles'));
focusBundles.mockReturnValue(Symbol('focused bundles'));
readLimits.mockReturnValue(Symbol('limits'));
jest.spyOn(OptimizerConfig, 'parseOptions').mockImplementation((): {
@ -417,6 +430,7 @@ describe('OptimizerConfig::create()', () => {
inspectWorkers: Symbol('parsed inspect workers'),
profileWebpack: Symbol('parsed profile webpack'),
filters: [],
focus: [],
includeCoreBundle: false,
}));
});
@ -470,17 +484,14 @@ describe('OptimizerConfig::create()', () => {
"calls": Array [
Array [
Array [],
Array [
Symbol(bundle1),
Symbol(bundle2),
],
Symbol(focused bundles),
],
],
"instances": Array [
[Window],
],
"invocationCallOrder": Array [
23,
24,
],
"results": Array [
Object {

View file

@ -32,6 +32,7 @@ import {
import { findKibanaPlatformPlugins, KibanaPlatformPlugin } from './kibana_platform_plugins';
import { getPluginBundles } from './get_plugin_bundles';
import { filterById } from './filter_by_id';
import { focusBundles } from './focus_bundles';
import { readLimits } from '../limits';
export interface Limits {
@ -104,6 +105,11 @@ interface Options {
* --filter f*r # [foobar], excludes [foo, bar]
*/
filter?: string[];
/**
* behaves just like filter, but includes required bundles and plugins of the
* listed bundle ids. Filters only apply to bundles selected by focus
*/
focus?: string[];
/** flag that causes the core bundle to be built along with plugins */
includeCoreBundle?: boolean;
@ -132,6 +138,7 @@ export interface ParsedOptions {
pluginPaths: string[];
pluginScanDirs: string[];
filters: string[];
focus: string[];
inspectWorkers: boolean;
includeCoreBundle: boolean;
themeTags: ThemeTags;
@ -148,6 +155,7 @@ export class OptimizerConfig {
const cache = options.cache !== false && !process.env.KBN_OPTIMIZER_NO_CACHE;
const includeCoreBundle = !!options.includeCoreBundle;
const filters = options.filter || [];
const focus = options.focus || [];
const repoRoot = options.repoRoot;
if (!Path.isAbsolute(repoRoot)) {
@ -210,6 +218,7 @@ export class OptimizerConfig {
pluginScanDirs,
pluginPaths,
filters,
focus,
inspectWorkers,
includeCoreBundle,
themeTags,
@ -236,7 +245,7 @@ export class OptimizerConfig {
];
return new OptimizerConfig(
filterById(options.filters, bundles),
filterById(options.filters, focusBundles(options.focus, bundles)),
options.cache,
options.watch,
options.inspectWorkers,