Skip to content

Commit

Permalink
[kbn/pm] add caching to bootstrap (#53622)
Browse files Browse the repository at this point in the history
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
Spencer and elasticmachine authored Jan 3, 2020
1 parent d4b1966 commit 7b4278d
Show file tree
Hide file tree
Showing 29 changed files with 67,789 additions and 32,977 deletions.
1 change: 1 addition & 0 deletions packages/kbn-dev-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"execa": "^3.2.0",
"exit-hook": "^2.2.0",
"getopts": "^2.2.5",
"load-json-file": "^6.2.0",
"moment": "^2.24.0",
"rxjs": "^6.5.3",
"tree-kill": "^1.2.1",
Expand Down
22 changes: 0 additions & 22 deletions packages/kbn-dev-utils/src/constants.ts

This file was deleted.

2 changes: 1 addition & 1 deletion packages/kbn-dev-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ export {
export { createAbsolutePathSerializer } from './serializers';
export { CA_CERT_PATH, ES_KEY_PATH, ES_CERT_PATH } from './certs';
export { run, createFailError, createFlagError, combineErrors, isFailError, Flags } from './run';
export { REPO_ROOT } from './constants';
export { REPO_ROOT } from './repo_root';
export { KbnClient } from './kbn_client';
export * from './axios';
59 changes: 59 additions & 0 deletions packages/kbn-dev-utils/src/repo_root.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* 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 Fs from 'fs';

import loadJsonFile from 'load-json-file';

const isKibanaDir = (dir: string) => {
try {
const path = Path.resolve(dir, 'package.json');
const json = loadJsonFile.sync(path);
if (json && typeof json === 'object' && 'name' in json && json.name === 'kibana') {
return true;
}
} catch (error) {
if (error && error.code === 'ENOENT') {
return false;
}

throw error;
}
};

// search for the kibana directory, since this file is moved around it might
// not be where we think but should always be a relatively close parent
// of this directory
const startDir = Fs.realpathSync(__dirname);
const { root: rootDir } = Path.parse(startDir);
let cursor = startDir;
while (true) {
if (isKibanaDir(cursor)) {
break;
}

const parent = Path.dirname(cursor);
if (parent === rootDir) {
throw new Error(`unable to find kibana directory from ${startDir}`);
}
cursor = parent;
}

export const REPO_ROOT = cursor;
99,976 changes: 67,067 additions & 32,909 deletions packages/kbn-pm/dist/index.js

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions packages/kbn-pm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
"@types/tempy": "^0.2.0",
"@types/wrap-ansi": "^2.0.15",
"@types/write-pkg": "^3.1.0",
"@kbn/dev-utils": "1.0.0",
"@yarnpkg/lockfile": "^1.1.0",
"babel-loader": "^8.0.6",
"chalk": "^2.4.2",
"cmd-shim": "^2.1.0",
Expand All @@ -48,6 +50,7 @@
"indent-string": "^3.2.0",
"lodash.clonedeepwith": "^4.5.0",
"log-symbols": "^2.2.0",
"multimatch": "^4.0.0",
"ncp": "^2.0.0",
"ora": "^1.4.0",
"prettier": "^1.19.1",
Expand Down
6 changes: 5 additions & 1 deletion packages/kbn-pm/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ function help() {
-i, --include Include only specified projects. If left unspecified, it defaults to including all projects.
--oss Do not include the x-pack when running command.
--skip-kibana-plugins Filter all plugins in ./plugins and ../kibana-extra when running command.
--no-cache Disable the bootstrap cache
`);
}

Expand All @@ -65,7 +66,10 @@ export async function run(argv: string[]) {
h: 'help',
i: 'include',
},
boolean: ['prefer-offline', 'frozen-lockfile'],
default: {
cache: true,
},
boolean: ['prefer-offline', 'frozen-lockfile', 'cache'],
});

const args = options._;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions packages/kbn-pm/src/commands/bootstrap.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { Project } from '../utils/project';
import { buildProjectGraph } from '../utils/projects';
import { installInDir, runScriptInPackageStreaming, yarnWorkspacesInfo } from '../utils/scripts';
import { BootstrapCommand } from './bootstrap';
import { Kibana } from '../utils/kibana';

const mockInstallInDir = installInDir as jest.Mock;
const mockRunScriptInPackageStreaming = runScriptInPackageStreaming as jest.Mock;
Expand Down Expand Up @@ -107,6 +108,7 @@ test('handles dependencies of dependencies', async () => {
['bar', bar],
['baz', baz],
]);
const kbn = new Kibana(projects);
const projectGraph = buildProjectGraph(projects);

const logMock = jest.spyOn(console, 'log').mockImplementation(noop);
Expand All @@ -115,6 +117,7 @@ test('handles dependencies of dependencies', async () => {
extraArgs: [],
options: {},
rootPath: '',
kbn,
});

expect(mockInstallInDir.mock.calls).toMatchSnapshot('install in dir');
Expand Down Expand Up @@ -142,6 +145,7 @@ test('does not run installer if no deps in package', async () => {
['kibana', kibana],
['bar', bar],
]);
const kbn = new Kibana(projects);
const projectGraph = buildProjectGraph(projects);

const logMock = jest.spyOn(console, 'log').mockImplementation(noop);
Expand All @@ -150,6 +154,7 @@ test('does not run installer if no deps in package', async () => {
extraArgs: [],
options: {},
rootPath: '',
kbn,
});

expect(mockInstallInDir.mock.calls).toMatchSnapshot('install in dir');
Expand All @@ -167,6 +172,7 @@ test('handles "frozen-lockfile"', async () => {
});

const projects = new Map([['kibana', kibana]]);
const kbn = new Kibana(projects);
const projectGraph = buildProjectGraph(projects);

jest.spyOn(console, 'log').mockImplementation(noop);
Expand All @@ -177,6 +183,7 @@ test('handles "frozen-lockfile"', async () => {
'frozen-lockfile': true,
},
rootPath: '',
kbn,
});

expect(mockInstallInDir.mock.calls).toMatchSnapshot('install in dir');
Expand Down Expand Up @@ -205,6 +212,7 @@ test('calls "kbn:bootstrap" scripts and links executables after installing deps'
['kibana', kibana],
['bar', bar],
]);
const kbn = new Kibana(projects);
const projectGraph = buildProjectGraph(projects);

jest.spyOn(console, 'log').mockImplementation(noop);
Expand All @@ -213,6 +221,7 @@ test('calls "kbn:bootstrap" scripts and links executables after installing deps'
extraArgs: [],
options: {},
rootPath: '',
kbn,
});

expect(mockLinkProjectExecutables.mock.calls).toMatchSnapshot('link bins');
Expand Down
19 changes: 15 additions & 4 deletions packages/kbn-pm/src/commands/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ import { log } from '../utils/log';
import { parallelizeBatches } from '../utils/parallelize';
import { topologicallyBatchProjects } from '../utils/projects';
import { ICommand } from './';
import { getAllChecksums } from '../utils/project_checksums';
import { BootstrapCacheFile } from '../utils/bootstrap_cache_file';

export const BootstrapCommand: ICommand = {
description: 'Install dependencies and crosslink projects',
name: 'bootstrap',

async run(projects, projectGraph, { options }) {
async run(projects, projectGraph, { options, kbn }) {
const batchedProjectsByWorkspace = topologicallyBatchProjects(projects, projectGraph, {
batchByWorkspace: true,
});
Expand Down Expand Up @@ -65,9 +67,18 @@ export const BootstrapCommand: ICommand = {
* have to, as it will slow down the bootstrapping process.
*/
log.write(chalk.bold('\nLinking executables completed, running `kbn:bootstrap` scripts\n'));
await parallelizeBatches(batchedProjects, async pkg => {
if (pkg.hasScript('kbn:bootstrap')) {
await pkg.runScriptStreaming('kbn:bootstrap');

const checksums = options.cache ? await getAllChecksums(kbn, log) : false;
await parallelizeBatches(batchedProjects, async project => {
if (project.hasScript('kbn:bootstrap')) {
const cacheFile = new BootstrapCacheFile(kbn, project, checksums);
if (cacheFile.isValid()) {
log.success(`[${project.name}] cache up to date`);
} else {
cacheFile.delete();
await project.runScriptStreaming('kbn:bootstrap');
cacheFile.write();
}
}
});

Expand Down
2 changes: 2 additions & 0 deletions packages/kbn-pm/src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface ICommandConfig {
extraArgs: string[];
options: { [key: string]: any };
rootPath: string;
kbn: Kibana;
}

export interface ICommand {
Expand All @@ -36,6 +37,7 @@ import { BootstrapCommand } from './bootstrap';
import { CleanCommand } from './clean';
import { RunCommand } from './run';
import { WatchCommand } from './watch';
import { Kibana } from '../utils/kibana';

export const commands: { [key: string]: ICommand } = {
bootstrap: BootstrapCommand,
Expand Down
12 changes: 5 additions & 7 deletions packages/kbn-pm/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,16 @@

import { resolve } from 'path';

export interface IProjectPathOptions {
'skip-kibana-plugins'?: boolean;
oss?: boolean;
interface Options {
rootPath: string;
skipKibanaPlugins?: boolean;
ossOnly?: boolean;
}

/**
* Returns all the paths where plugins are located
*/
export function getProjectPaths(rootPath: string, options: IProjectPathOptions = {}) {
const skipKibanaPlugins = Boolean(options['skip-kibana-plugins']);
const ossOnly = Boolean(options.oss);

export function getProjectPaths({ rootPath, ossOnly, skipKibanaPlugins }: Options) {
const projectPaths = [rootPath, resolve(rootPath, 'packages/*')];

// This is needed in order to install the dependencies for the declared
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export async function buildProductionProjects({
* is supplied, we omit projects with build.oss in their package.json set to false.
*/
async function getProductionProjects(rootPath: string, onlyOSS?: boolean) {
const projectPaths = getProjectPaths(rootPath, {});
const projectPaths = getProjectPaths({ rootPath });
const projects = await getProjects(rootPath, projectPaths);
const projectsSubset = [projects.get('kibana')!];

Expand Down
2 changes: 1 addition & 1 deletion packages/kbn-pm/src/run.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function getExpectedProjectsAndGraph(runMock: any) {
}

let command: ICommand;
let config: ICommandConfig;
let config: Omit<ICommandConfig, 'kbn'>;
beforeEach(() => {
command = {
description: 'test description',
Expand Down
18 changes: 11 additions & 7 deletions packages/kbn-pm/src/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,24 @@ import indentString from 'indent-string';
import wrapAnsi from 'wrap-ansi';

import { ICommand, ICommandConfig } from './commands';
import { getProjectPaths, IProjectPathOptions } from './config';
import { CliError } from './utils/errors';
import { log } from './utils/log';
import { buildProjectGraph, getProjects } from './utils/projects';
import { buildProjectGraph } from './utils/projects';
import { renderProjectsTree } from './utils/projects_tree';
import { Kibana } from './utils/kibana';

export async function runCommand(command: ICommand, config: ICommandConfig) {
export async function runCommand(command: ICommand, config: Omit<ICommandConfig, 'kbn'>) {
try {
log.write(
chalk.bold(
`Running [${chalk.green(command.name)}] command from [${chalk.yellow(config.rootPath)}]:\n`
)
);

const projectPaths = getProjectPaths(config.rootPath, config.options as IProjectPathOptions);

const projects = await getProjects(config.rootPath, projectPaths, {
const kbn = await Kibana.loadFrom(config.rootPath);
const projects = kbn.getFilteredProjects({
skipKibanaPlugins: Boolean(config.options['skip-kibana-plugins']),
ossOnly: Boolean(config.options.oss),
exclude: toArray(config.options.exclude),
include: toArray(config.options.include),
});
Expand All @@ -57,7 +58,10 @@ export async function runCommand(command: ICommand, config: ICommandConfig) {
log.write(chalk.bold(`Found [${chalk.green(projects.size.toString())}] projects:\n`));
log.write(renderProjectsTree(config.rootPath, projects));

await command.run(projects, projectGraph, config);
await command.run(projects, projectGraph, {
...config,
kbn,
});
} catch (e) {
log.write(chalk.bold.red(`\n[${command.name}] failed:\n`));

Expand Down
Loading

0 comments on commit 7b4278d

Please sign in to comment.