Skip to content

Commit

Permalink
[kbn/optimizer] add support for --focus option (#80436)
Browse files Browse the repository at this point in the history
Co-authored-by: spalger <spalger@users.noreply.github.com>
  • Loading branch information
Spencer and spalger authored Oct 14, 2020
1 parent 3d6d4a6 commit bc4093a
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 6 deletions.
8 changes: 8 additions & 0 deletions packages/kbn-optimizer/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -118,6 +123,7 @@ run(
inspectWorkers,
includeCoreBundle,
filter,
focus,
});

if (validateLimits) {
Expand Down Expand Up @@ -165,6 +171,7 @@ run(
cache: true,
'inspect-workers': true,
filter: [],
focus: [],
},
help: `
--watch run the optimizer in watch mode
Expand All @@ -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
Expand Down
80 changes: 80 additions & 0 deletions packages/kbn-optimizer/src/optimizer/focus_bundles.test.ts
Original file line number Diff line number Diff line change
@@ -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"`);
});
44 changes: 44 additions & 0 deletions packages/kbn-optimizer/src/optimizer/focus_bundles.ts
Original file line number Diff line number Diff line change
@@ -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;
}
21 changes: 16 additions & 5 deletions packages/kbn-optimizer/src/optimizer/optimizer_config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down Expand Up @@ -121,6 +122,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"cache": true,
"dist": false,
"filters": Array [],
"focus": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
Expand Down Expand Up @@ -149,6 +151,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"cache": false,
"dist": false,
"filters": Array [],
"focus": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
Expand Down Expand Up @@ -177,6 +180,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"cache": true,
"dist": false,
"filters": Array [],
"focus": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
Expand Down Expand Up @@ -207,6 +211,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"cache": true,
"dist": false,
"filters": Array [],
"focus": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
Expand Down Expand Up @@ -234,6 +239,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"cache": true,
"dist": false,
"filters": Array [],
"focus": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
Expand Down Expand Up @@ -261,6 +267,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"cache": true,
"dist": false,
"filters": Array [],
"focus": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
Expand All @@ -285,6 +292,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"cache": false,
"dist": false,
"filters": Array [],
"focus": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
Expand All @@ -309,6 +317,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"cache": false,
"dist": false,
"filters": Array [],
"focus": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
Expand All @@ -334,6 +343,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"cache": false,
"dist": false,
"filters": Array [],
"focus": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
Expand All @@ -359,6 +369,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"cache": true,
"dist": false,
"filters": Array [],
"focus": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
Expand Down Expand Up @@ -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(() => {
Expand All @@ -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((): {
Expand All @@ -417,6 +430,7 @@ describe('OptimizerConfig::create()', () => {
inspectWorkers: Symbol('parsed inspect workers'),
profileWebpack: Symbol('parsed profile webpack'),
filters: [],
focus: [],
includeCoreBundle: false,
}));
});
Expand Down Expand Up @@ -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 {
Expand Down
11 changes: 10 additions & 1 deletion packages/kbn-optimizer/src/optimizer/optimizer_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -132,6 +138,7 @@ export interface ParsedOptions {
pluginPaths: string[];
pluginScanDirs: string[];
filters: string[];
focus: string[];
inspectWorkers: boolean;
includeCoreBundle: boolean;
themeTags: ThemeTags;
Expand All @@ -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)) {
Expand Down Expand Up @@ -210,6 +218,7 @@ export class OptimizerConfig {
pluginScanDirs,
pluginPaths,
filters,
focus,
inspectWorkers,
includeCoreBundle,
themeTags,
Expand All @@ -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,
Expand Down

0 comments on commit bc4093a

Please sign in to comment.