Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[src/dev/build] build Kibana Platform bundles from source #73591

Merged
merged 5 commits into from
Aug 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@

import { REPO_ROOT } from '../repo_root';

export function createAbsolutePathSerializer(rootPath: string = REPO_ROOT) {
export function createAbsolutePathSerializer(
rootPath: string = REPO_ROOT,
replacement = '<absolute path>'
) {
return {
test: (value: any) => typeof value === 'string' && value.startsWith(rootPath),
serialize: (value: string) => value.replace(rootPath, '<absolute path>').replace(/\\/g, '/'),
serialize: (value: string) => value.replace(rootPath, replacement).replace(/\\/g, '/'),
};
}
14 changes: 14 additions & 0 deletions packages/kbn-optimizer/src/common/bundle_cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,18 @@ export class BundleCache {
public getOptimizerCacheKey() {
return this.get().optimizerCacheKey;
}

public clear() {
this.state = undefined;

if (this.path) {
try {
Fs.unlinkSync(this.path);
} catch (error) {
if (error.code !== 'ENOENT') {
throw error;
}
}
}
}
}
31 changes: 17 additions & 14 deletions packages/kbn-optimizer/src/optimizer/get_plugin_bundles.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ import { createAbsolutePathSerializer } from '@kbn/dev-utils';

import { getPluginBundles } from './get_plugin_bundles';

expect.addSnapshotSerializer(createAbsolutePathSerializer('/repo'));
expect.addSnapshotSerializer(createAbsolutePathSerializer('/repo', '<repoRoot>'));
expect.addSnapshotSerializer(createAbsolutePathSerializer('/output', '<outputRoot>'));
expect.addSnapshotSerializer(createAbsolutePathSerializer('/outside/of/repo', '<outsideOfRepo>'));

it('returns a bundle for core and each plugin', () => {
expect(
Expand Down Expand Up @@ -56,46 +58,47 @@ it('returns a bundle for core and each plugin', () => {
manifestPath: '/repo/x-pack/plugins/box/kibana.json',
},
],
'/repo'
'/repo',
'/output'
).map((b) => b.toSpec())
).toMatchInlineSnapshot(`
Array [
Object {
"banner": undefined,
"contextDir": <absolute path>/plugins/foo,
"contextDir": <repoRoot>/plugins/foo,
"id": "foo",
"manifestPath": <absolute path>/plugins/foo/kibana.json,
"outputDir": <absolute path>/plugins/foo/target/public,
"manifestPath": <repoRoot>/plugins/foo/kibana.json,
"outputDir": <outputRoot>/plugins/foo/target/public,
"publicDirNames": Array [
"public",
],
"sourceRoot": <absolute path>,
"sourceRoot": <repoRoot>,
"type": "plugin",
},
Object {
"banner": undefined,
"contextDir": "/outside/of/repo/plugins/baz",
"contextDir": <outsideOfRepo>/plugins/baz,
"id": "baz",
"manifestPath": "/outside/of/repo/plugins/baz/kibana.json",
"outputDir": "/outside/of/repo/plugins/baz/target/public",
"manifestPath": <outsideOfRepo>/plugins/baz/kibana.json,
"outputDir": <outsideOfRepo>/plugins/baz/target/public,
"publicDirNames": Array [
"public",
],
"sourceRoot": <absolute path>,
"sourceRoot": <repoRoot>,
"type": "plugin",
},
Object {
"banner": "/*! Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one or more contributor license agreements.
* Licensed under the Elastic License; you may not use this file except in compliance with the Elastic License. */
",
"contextDir": <absolute path>/x-pack/plugins/box,
"contextDir": <repoRoot>/x-pack/plugins/box,
"id": "box",
"manifestPath": <absolute path>/x-pack/plugins/box/kibana.json,
"outputDir": <absolute path>/x-pack/plugins/box/target/public,
"manifestPath": <repoRoot>/x-pack/plugins/box/kibana.json,
"outputDir": <outputRoot>/x-pack/plugins/box/target/public,
"publicDirNames": Array [
"public",
],
"sourceRoot": <absolute path>,
"sourceRoot": <repoRoot>,
"type": "plugin",
},
]
Expand Down
12 changes: 10 additions & 2 deletions packages/kbn-optimizer/src/optimizer/get_plugin_bundles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ import { Bundle } from '../common';

import { KibanaPlatformPlugin } from './kibana_platform_plugins';

export function getPluginBundles(plugins: KibanaPlatformPlugin[], repoRoot: string) {
export function getPluginBundles(
plugins: KibanaPlatformPlugin[],
repoRoot: string,
outputRoot: string
) {
const xpackDirSlash = Path.resolve(repoRoot, 'x-pack') + Path.sep;

return plugins
Expand All @@ -36,7 +40,11 @@ export function getPluginBundles(plugins: KibanaPlatformPlugin[], repoRoot: stri
publicDirNames: ['public', ...p.extraPublicDirs],
sourceRoot: repoRoot,
contextDir: p.directory,
outputDir: Path.resolve(p.directory, 'target/public'),
outputDir: Path.resolve(
outputRoot,
Path.relative(repoRoot, p.directory),
'target/public'
),
manifestPath: p.manifestPath,
banner: p.directory.startsWith(xpackDirSlash)
? `/*! Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one or more contributor license agreements.\n` +
Expand Down
31 changes: 25 additions & 6 deletions packages/kbn-optimizer/src/optimizer/optimizer_config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,20 @@ jest.mock('./get_plugin_bundles.ts');
jest.mock('../common/theme_tags.ts');
jest.mock('./filter_by_id.ts');

import Path from 'path';
import Os from 'os';
jest.mock('os', () => {
const realOs = jest.requireActual('os');
jest.spyOn(realOs, 'cpus').mockImplementation(() => {
return ['foo'] as any;
});
return realOs;
});

import Path from 'path';
import { REPO_ROOT, createAbsolutePathSerializer } from '@kbn/dev-utils';

import { OptimizerConfig } from './optimizer_config';
import { OptimizerConfig, ParsedOptions } from './optimizer_config';
import { parseThemeTags } from '../common';

jest.spyOn(Os, 'cpus').mockReturnValue(['foo'] as any);

expect.addSnapshotSerializer(createAbsolutePathSerializer());

beforeEach(() => {
Expand Down Expand Up @@ -118,6 +122,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
"outputRoot": <absolute path>,
"pluginPaths": Array [],
"pluginScanDirs": Array [
<absolute path>/src/plugins,
Expand Down Expand Up @@ -145,6 +150,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
"outputRoot": <absolute path>,
"pluginPaths": Array [],
"pluginScanDirs": Array [
<absolute path>/src/plugins,
Expand Down Expand Up @@ -172,6 +178,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
"outputRoot": <absolute path>,
"pluginPaths": Array [],
"pluginScanDirs": Array [
<absolute path>/src/plugins,
Expand Down Expand Up @@ -201,6 +208,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
"outputRoot": <absolute path>,
"pluginPaths": Array [],
"pluginScanDirs": Array [
<absolute path>/src/plugins,
Expand All @@ -227,6 +235,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
"outputRoot": <absolute path>,
"pluginPaths": Array [],
"pluginScanDirs": Array [
<absolute path>/x/y/z,
Expand All @@ -253,6 +262,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
"outputRoot": <absolute path>,
"pluginPaths": Array [],
"pluginScanDirs": Array [],
"profileWebpack": false,
Expand All @@ -276,6 +286,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
"outputRoot": <absolute path>,
"pluginPaths": Array [],
"pluginScanDirs": Array [],
"profileWebpack": false,
Expand All @@ -299,6 +310,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
"outputRoot": <absolute path>,
"pluginPaths": Array [],
"pluginScanDirs": Array [],
"profileWebpack": false,
Expand All @@ -323,6 +335,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
"outputRoot": <absolute path>,
"pluginPaths": Array [],
"pluginScanDirs": Array [],
"profileWebpack": false,
Expand All @@ -347,6 +360,7 @@ describe('OptimizerConfig::parseOptions()', () => {
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
"outputRoot": <absolute path>,
"pluginPaths": Array [],
"pluginScanDirs": Array [],
"profileWebpack": false,
Expand Down Expand Up @@ -384,18 +398,22 @@ describe('OptimizerConfig::create()', () => {
getPluginBundles.mockReturnValue([Symbol('bundle1'), Symbol('bundle2')]);
filterById.mockReturnValue(Symbol('filtered bundles'));

jest.spyOn(OptimizerConfig, 'parseOptions').mockImplementation((): any => ({
jest.spyOn(OptimizerConfig, 'parseOptions').mockImplementation((): {
[key in keyof ParsedOptions]: any;
} => ({
cache: Symbol('parsed cache'),
dist: Symbol('parsed dist'),
maxWorkerCount: Symbol('parsed max worker count'),
pluginPaths: Symbol('parsed plugin paths'),
pluginScanDirs: Symbol('parsed plugin scan dirs'),
repoRoot: Symbol('parsed repo root'),
outputRoot: Symbol('parsed output root'),
watch: Symbol('parsed watch'),
themeTags: Symbol('theme tags'),
inspectWorkers: Symbol('parsed inspect workers'),
profileWebpack: Symbol('parsed profile webpack'),
filters: [],
includeCoreBundle: false,
}));
});

Expand Down Expand Up @@ -474,6 +492,7 @@ describe('OptimizerConfig::create()', () => {
Array [
Symbol(new platform plugins),
Symbol(parsed repo root),
Symbol(parsed output root),
],
],
"instances": Array [
Expand Down
20 changes: 17 additions & 3 deletions packages/kbn-optimizer/src/optimizer/optimizer_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ function omit<T, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> {
interface Options {
/** absolute path to root of the repo/build */
repoRoot: string;
/**
* absolute path to the root directory where output should be written to. This
* defaults to the repoRoot but can be customized to write output somewhere else.
*
* This is how we write output to the build directory in the Kibana build tasks.
*/
outputRoot?: string;
/** enable to run the optimizer in watch mode */
watch?: boolean;
/** the maximum number of workers that will be created */
Expand Down Expand Up @@ -107,8 +114,9 @@ interface Options {
themes?: ThemeTag | '*' | ThemeTag[];
}

interface ParsedOptions {
export interface ParsedOptions {
repoRoot: string;
outputRoot: string;
watch: boolean;
maxWorkerCount: number;
profileWebpack: boolean;
Expand Down Expand Up @@ -139,6 +147,11 @@ export class OptimizerConfig {
throw new TypeError('repoRoot must be an absolute path');
}

const outputRoot = options.outputRoot ?? repoRoot;
if (!Path.isAbsolute(outputRoot)) {
throw new TypeError('outputRoot must be an absolute path');
}

/**
* BEWARE: this needs to stay roughly synchronized with
* `src/core/server/config/env.ts` which determines which paths
Expand Down Expand Up @@ -182,6 +195,7 @@ export class OptimizerConfig {
watch,
dist,
repoRoot,
outputRoot,
maxWorkerCount,
profileWebpack,
cache,
Expand All @@ -206,11 +220,11 @@ export class OptimizerConfig {
publicDirNames: ['public', 'public/utils'],
sourceRoot: options.repoRoot,
contextDir: Path.resolve(options.repoRoot, 'src/core'),
outputDir: Path.resolve(options.repoRoot, 'src/core/target/public'),
outputDir: Path.resolve(options.outputRoot, 'src/core/target/public'),
}),
]
: []),
...getPluginBundles(plugins, options.repoRoot),
...getPluginBundles(plugins, options.repoRoot, options.outputRoot),
];

return new OptimizerConfig(
Expand Down
18 changes: 9 additions & 9 deletions src/dev/build/tasks/build_kibana_platform_plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* under the License.
*/

import { CiStatsReporter } from '@kbn/dev-utils';
import { CiStatsReporter, REPO_ROOT } from '@kbn/dev-utils';
import {
runOptimizer,
OptimizerConfig,
Expand All @@ -29,9 +29,10 @@ import { Task } from '../lib';

export const BuildKibanaPlatformPlugins: Task = {
description: 'Building distributable versions of Kibana platform plugins',
async run(config, log, build) {
const optimizerConfig = OptimizerConfig.create({
repoRoot: build.resolvePath(),
async run(_, log, build) {
const config = OptimizerConfig.create({
repoRoot: REPO_ROOT,
outputRoot: build.resolvePath(),
cache: false,
oss: build.isOss(),
examples: false,
Expand All @@ -42,11 +43,10 @@ export const BuildKibanaPlatformPlugins: Task = {

const reporter = CiStatsReporter.fromEnv(log);

await runOptimizer(optimizerConfig)
.pipe(
reportOptimizerStats(reporter, optimizerConfig, log),
logOptimizerState(log, optimizerConfig)
)
await runOptimizer(config)
.pipe(reportOptimizerStats(reporter, config, log), logOptimizerState(log, config))
.toPromise();

await Promise.all(config.bundles.map((b) => b.cache.clear()));
},
};
2 changes: 1 addition & 1 deletion src/dev/build/tasks/copy_source_task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const CopySource: Task = {
'src/**',
'!src/**/*.{test,test.mocks,mock}.{js,ts,tsx}',
'!src/**/mocks.ts', // special file who imports .mock files
'!src/**/{__tests__,__snapshots__,__mocks__}/**',
'!src/**/{target,__tests__,__snapshots__,__mocks__}/**',
'!src/test_utils/**',
'!src/fixtures/**',
'!src/legacy/core_plugins/console/public/tests/**',
Expand Down
1 change: 1 addition & 0 deletions vars/kibanaPipeline.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ def uploadCoverageArtifacts(prefix, pattern) {
def withGcsArtifactUpload(workerName, closure) {
def uploadPrefix = "kibana-ci-artifacts/jobs/${env.JOB_NAME}/${BUILD_NUMBER}/${workerName}"
def ARTIFACT_PATTERNS = [
'**/target/public/.kbn-optimizer-cache',
'target/kibana-*',
'target/kibana-security-solution/**/*.png',
'target/junit/**/*',
Expand Down