mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
add script to update VSCode config with proper excludes (#110161)
Co-authored-by: spalger <spalger@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
8a6cf06f15
commit
1500534a51
13 changed files with 725 additions and 68 deletions
|
@ -429,6 +429,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "^7.12.10",
|
"@babel/cli": "^7.12.10",
|
||||||
"@babel/core": "^7.12.10",
|
"@babel/core": "^7.12.10",
|
||||||
|
"@babel/generator": "^7.12.11",
|
||||||
"@babel/parser": "^7.12.11",
|
"@babel/parser": "^7.12.11",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
||||||
"@babel/plugin-proposal-export-namespace-from": "^7.12.1",
|
"@babel/plugin-proposal-export-namespace-from": "^7.12.1",
|
||||||
|
|
|
@ -57,6 +57,7 @@ RUNTIME_DEPS = [
|
||||||
"@npm//load-json-file",
|
"@npm//load-json-file",
|
||||||
"@npm//markdown-it",
|
"@npm//markdown-it",
|
||||||
"@npm//normalize-path",
|
"@npm//normalize-path",
|
||||||
|
"@npm//prettier",
|
||||||
"@npm//rxjs",
|
"@npm//rxjs",
|
||||||
"@npm//tar",
|
"@npm//tar",
|
||||||
"@npm//tree-kill",
|
"@npm//tree-kill",
|
||||||
|
@ -81,6 +82,7 @@ TYPES_DEPS = [
|
||||||
"@npm//@types/markdown-it",
|
"@npm//@types/markdown-it",
|
||||||
"@npm//@types/node",
|
"@npm//@types/node",
|
||||||
"@npm//@types/normalize-path",
|
"@npm//@types/normalize-path",
|
||||||
|
"@npm//@types/prettier",
|
||||||
"@npm//@types/react",
|
"@npm//@types/react",
|
||||||
"@npm//@types/tar",
|
"@npm//@types/tar",
|
||||||
"@npm//@types/testing-library__jest-dom",
|
"@npm//@types/testing-library__jest-dom",
|
||||||
|
|
|
@ -32,3 +32,4 @@ export * from './plugins';
|
||||||
export * from './streams';
|
export * from './streams';
|
||||||
export * from './babel';
|
export * from './babel';
|
||||||
export * from './extract';
|
export * from './extract';
|
||||||
|
export * from './vscode_config';
|
||||||
|
|
9
packages/kbn-dev-utils/src/vscode_config/index.ts
Normal file
9
packages/kbn-dev-utils/src/vscode_config/index.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './update_vscode_config_cli';
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface ManagedConfigKey {
|
||||||
|
key: string;
|
||||||
|
value: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the keys which we overrite in user's vscode config for the workspace. We currently
|
||||||
|
* only support object values because that's all we needed to support, but support for non object
|
||||||
|
* values should be easy to add.
|
||||||
|
*/
|
||||||
|
export const MANAGED_CONFIG_KEYS: ManagedConfigKey[] = [
|
||||||
|
{
|
||||||
|
key: 'files.watcherExclude',
|
||||||
|
value: {
|
||||||
|
['**/.eslintcache']: true,
|
||||||
|
['**/.es']: true,
|
||||||
|
['**/.yarn-local-mirror']: true,
|
||||||
|
['**/.chromium']: true,
|
||||||
|
['**/packages/kbn-pm/dist/index.js']: true,
|
||||||
|
['**/bazel-*']: true,
|
||||||
|
['**/node_modules']: true,
|
||||||
|
['**/target']: true,
|
||||||
|
['**/*.log']: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'search.exclude',
|
||||||
|
value: {
|
||||||
|
['**/packages/kbn-pm/dist/index.js']: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
|
@ -0,0 +1,340 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import dedent from 'dedent';
|
||||||
|
|
||||||
|
import { updateVscodeConfig } from './update_vscode_config';
|
||||||
|
import { ManagedConfigKey } from './managed_config_keys';
|
||||||
|
|
||||||
|
// avoid excessive escaping in snapshots
|
||||||
|
expect.addSnapshotSerializer({ test: (v) => typeof v === 'string', print: (v) => `${v}` });
|
||||||
|
|
||||||
|
const TEST_KEYS: ManagedConfigKey[] = [
|
||||||
|
{
|
||||||
|
key: 'key',
|
||||||
|
value: {
|
||||||
|
hello: true,
|
||||||
|
world: [1, 2, 3],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const run = (json?: string) => updateVscodeConfig(TEST_KEYS, '', json);
|
||||||
|
|
||||||
|
it('updates the passed JSON with the managed settings', () => {
|
||||||
|
expect(run(`{}`)).toMatchInlineSnapshot(`
|
||||||
|
// @managed
|
||||||
|
{
|
||||||
|
"key": {
|
||||||
|
// @managed
|
||||||
|
"hello": true,
|
||||||
|
// @managed
|
||||||
|
"world": [1, 2, 3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('initialized empty or undefined json values', () => {
|
||||||
|
expect(run('')).toMatchInlineSnapshot(`
|
||||||
|
// @managed
|
||||||
|
{
|
||||||
|
"key": {
|
||||||
|
// @managed
|
||||||
|
"hello": true,
|
||||||
|
// @managed
|
||||||
|
"world": [1, 2, 3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
`);
|
||||||
|
|
||||||
|
expect(run()).toMatchInlineSnapshot(`
|
||||||
|
// @managed
|
||||||
|
{
|
||||||
|
"key": {
|
||||||
|
// @managed
|
||||||
|
"hello": true,
|
||||||
|
// @managed
|
||||||
|
"world": [1, 2, 3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('replaces conflicting managed keys which do not have object values', () => {
|
||||||
|
expect(run(`{ "key": false }`)).toMatchInlineSnapshot(`
|
||||||
|
// @managed
|
||||||
|
{
|
||||||
|
"key": {
|
||||||
|
// @managed
|
||||||
|
"hello": true,
|
||||||
|
// @managed
|
||||||
|
"world": [1, 2, 3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`throws if the JSON file doesn't contain an object`, () => {
|
||||||
|
expect(() => run('[]')).toThrowErrorMatchingInlineSnapshot(
|
||||||
|
`expected VSCode config to contain a JSON object`
|
||||||
|
);
|
||||||
|
expect(() => run('1')).toThrowErrorMatchingInlineSnapshot(
|
||||||
|
`expected VSCode config to contain a JSON object`
|
||||||
|
);
|
||||||
|
expect(() => run('"foo"')).toThrowErrorMatchingInlineSnapshot(
|
||||||
|
`expected VSCode config to contain a JSON object`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('persists comments in the original file', () => {
|
||||||
|
const newJson = run(`
|
||||||
|
/**
|
||||||
|
* This is a top level comment
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
"a": "bar",
|
||||||
|
// this is just test data
|
||||||
|
"b": "box"
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(newJson).toMatchInlineSnapshot(`
|
||||||
|
// @managed
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a top level comment
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
"a": "bar",
|
||||||
|
// this is just test data
|
||||||
|
"b": "box",
|
||||||
|
"key": {
|
||||||
|
// @managed
|
||||||
|
"hello": true,
|
||||||
|
// @managed
|
||||||
|
"world": [1, 2, 3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('overrides old values for managed keys', () => {
|
||||||
|
const newJson = run(`
|
||||||
|
{
|
||||||
|
"foo": 0,
|
||||||
|
"bar": "some other config",
|
||||||
|
"complex": "some other config",
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
expect(newJson).toMatchInlineSnapshot(`
|
||||||
|
// @managed
|
||||||
|
{
|
||||||
|
"foo": 0,
|
||||||
|
"bar": "some other config",
|
||||||
|
"complex": "some other config",
|
||||||
|
"key": {
|
||||||
|
// @managed
|
||||||
|
"hello": true,
|
||||||
|
// @managed
|
||||||
|
"world": [1, 2, 3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not modify files starting with // SELF MANAGED', () => {
|
||||||
|
const newJson = run(dedent`
|
||||||
|
// self managed
|
||||||
|
{
|
||||||
|
"invalid": "I know what I am doing",
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
expect(newJson).toMatchInlineSnapshot(`
|
||||||
|
// self managed
|
||||||
|
{
|
||||||
|
"invalid": "I know what I am doing",
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not modify properties with leading `// self managed` comment', () => {
|
||||||
|
const newJson = run(dedent`
|
||||||
|
{
|
||||||
|
// self managed
|
||||||
|
"key": {
|
||||||
|
"world": [5]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
expect(newJson).toMatchInlineSnapshot(`
|
||||||
|
// @managed
|
||||||
|
{
|
||||||
|
// self managed
|
||||||
|
"key": {
|
||||||
|
"world": [5]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not modify child properties with leading `// self managed` comment', () => {
|
||||||
|
const newJson = run(dedent`
|
||||||
|
{
|
||||||
|
"key": {
|
||||||
|
// self managed
|
||||||
|
"world": [5]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
expect(newJson).toMatchInlineSnapshot(`
|
||||||
|
// @managed
|
||||||
|
{
|
||||||
|
"key": {
|
||||||
|
// self managed
|
||||||
|
"world": [5],
|
||||||
|
// @managed
|
||||||
|
"hello": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not modify unknown child properties', () => {
|
||||||
|
const newJson = run(dedent`
|
||||||
|
{
|
||||||
|
"key": {
|
||||||
|
"foo": "bar",
|
||||||
|
// self managed
|
||||||
|
"world": [5],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
expect(newJson).toMatchInlineSnapshot(`
|
||||||
|
// @managed
|
||||||
|
{
|
||||||
|
"key": {
|
||||||
|
"foo": "bar",
|
||||||
|
// self managed
|
||||||
|
"world": [5],
|
||||||
|
// @managed
|
||||||
|
"hello": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('removes managed properties which are no longer managed', () => {
|
||||||
|
const newJson = run(dedent`
|
||||||
|
{
|
||||||
|
"key": {
|
||||||
|
// @managed
|
||||||
|
"foo": "bar",
|
||||||
|
// self managed
|
||||||
|
"world": [5],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
expect(newJson).toMatchInlineSnapshot(`
|
||||||
|
// @managed
|
||||||
|
{
|
||||||
|
"key": {
|
||||||
|
// self managed
|
||||||
|
"world": [5],
|
||||||
|
// @managed
|
||||||
|
"hello": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('wipes out child keys which conflict with newly managed child keys', () => {
|
||||||
|
const newJson = run(dedent`
|
||||||
|
{
|
||||||
|
"key": {
|
||||||
|
// some user specified comment
|
||||||
|
"world": [5],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
expect(newJson).toMatchInlineSnapshot(`
|
||||||
|
// @managed
|
||||||
|
{
|
||||||
|
"key": {
|
||||||
|
// @managed
|
||||||
|
"hello": true,
|
||||||
|
// @managed
|
||||||
|
"world": [1, 2, 3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('correctly formats info text when specified', () => {
|
||||||
|
const newJson = updateVscodeConfig(TEST_KEYS, 'info users\nshould know', `{}`);
|
||||||
|
|
||||||
|
expect(newJson).toMatchInlineSnapshot(`
|
||||||
|
/**
|
||||||
|
* @managed
|
||||||
|
*
|
||||||
|
* info users
|
||||||
|
* should know
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
"key": {
|
||||||
|
// @managed
|
||||||
|
"hello": true,
|
||||||
|
// @managed
|
||||||
|
"world": [1, 2, 3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allows "// self managed" comments conflicting with "// @managed" comments to win', () => {
|
||||||
|
const newJson = run(dedent`
|
||||||
|
{
|
||||||
|
"key": {
|
||||||
|
// @managed
|
||||||
|
// self managed
|
||||||
|
"hello": ["world"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
expect(newJson).toMatchInlineSnapshot(`
|
||||||
|
// @managed
|
||||||
|
{
|
||||||
|
"key": {
|
||||||
|
// self managed
|
||||||
|
"hello": ["world"],
|
||||||
|
// @managed
|
||||||
|
"world": [1, 2, 3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
`);
|
||||||
|
});
|
210
packages/kbn-dev-utils/src/vscode_config/update_vscode_config.ts
Normal file
210
packages/kbn-dev-utils/src/vscode_config/update_vscode_config.ts
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { parseExpression } from '@babel/parser';
|
||||||
|
import * as t from '@babel/types';
|
||||||
|
import generate from '@babel/generator';
|
||||||
|
import Prettier from 'prettier';
|
||||||
|
|
||||||
|
import { ManagedConfigKey } from './managed_config_keys';
|
||||||
|
|
||||||
|
type BasicObjectProp = t.ObjectProperty & {
|
||||||
|
key: t.StringLiteral;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isBasicObjectProp = (n: t.Node): n is BasicObjectProp =>
|
||||||
|
n.type === 'ObjectProperty' && n.key.type === 'StringLiteral';
|
||||||
|
|
||||||
|
const isManaged = (node?: t.Node) =>
|
||||||
|
!!node?.leadingComments?.some(
|
||||||
|
(c) => c.type === 'CommentLine' && c.value.trim().toLocaleLowerCase() === '@managed'
|
||||||
|
);
|
||||||
|
|
||||||
|
const isSelfManaged = (node?: t.Node) =>
|
||||||
|
!!node?.leadingComments?.some(
|
||||||
|
(c) => c.type === 'CommentLine' && c.value.trim().toLocaleLowerCase() === 'self managed'
|
||||||
|
);
|
||||||
|
|
||||||
|
const remove = <T>(arr: T[], value: T) => {
|
||||||
|
const index = arr.indexOf(value);
|
||||||
|
if (index > -1) {
|
||||||
|
arr.splice(index, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const createManagedChildProp = (key: string, value: any) => {
|
||||||
|
const childProp = t.objectProperty(t.stringLiteral(key), parseExpression(JSON.stringify(value)));
|
||||||
|
t.addComment(childProp, 'leading', ' @managed', true);
|
||||||
|
return childProp;
|
||||||
|
};
|
||||||
|
|
||||||
|
const createManagedProp = (key: string, value: Record<string, any>) => {
|
||||||
|
return t.objectProperty(
|
||||||
|
t.stringLiteral(key),
|
||||||
|
t.objectExpression(Object.entries(value).map(([k, v]) => createManagedChildProp(k, v)))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new setting to the settings.json file. Used when there is no existing key
|
||||||
|
*
|
||||||
|
* @param ast AST of the entire settings.json file
|
||||||
|
* @param key the key name to add
|
||||||
|
* @param value managed value which should be set at `key`
|
||||||
|
*/
|
||||||
|
const addManagedProp = (ast: t.ObjectExpression, key: string, value: Record<string, any>) => {
|
||||||
|
ast.properties.push(createManagedProp(key, value));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace an existing setting in the settings.json file with the `managedValue`, ignoring its
|
||||||
|
* type, used when the value of the existing setting is not an ObjectExpression
|
||||||
|
*
|
||||||
|
* @param ast AST of the entire settings.json file
|
||||||
|
* @param existing node which should be replaced
|
||||||
|
* @param value managed value which should replace the current value, regardless of its type
|
||||||
|
*/
|
||||||
|
const replaceManagedProp = (
|
||||||
|
ast: t.ObjectExpression,
|
||||||
|
existing: BasicObjectProp,
|
||||||
|
value: Record<string, any>
|
||||||
|
) => {
|
||||||
|
remove(ast.properties, existing);
|
||||||
|
addManagedProp(ast, existing.key.value, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge the managed value in to the value already in the settings.json file. Any property which is
|
||||||
|
* labeled with a `// self managed` comment is untouched, any property which is `// @managed` but
|
||||||
|
* no longer in the `managedValue` is removed, and any properties in the `managedValue` are either
|
||||||
|
* added or updated based on their existence in the AST.
|
||||||
|
*
|
||||||
|
* @param properties Object expression properties list which we will merge with ("key": <value>)
|
||||||
|
* @param managedValue the managed value that should be merged into the existing values
|
||||||
|
*/
|
||||||
|
const mergeManagedProperties = (
|
||||||
|
properties: t.ObjectExpression['properties'],
|
||||||
|
managedValue: Record<string, any>
|
||||||
|
) => {
|
||||||
|
// iterate through all the keys in the managed `value` and either add them to the
|
||||||
|
// prop, update their value, or ignore them because they are "// self managed"
|
||||||
|
for (const [key, value] of Object.entries(managedValue)) {
|
||||||
|
const existing = properties.filter(isBasicObjectProp).find((p) => p.key.value === key);
|
||||||
|
|
||||||
|
if (!existing) {
|
||||||
|
// add the new managed prop
|
||||||
|
properties.push(createManagedChildProp(key, value));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSelfManaged(existing)) {
|
||||||
|
// strip "// @managed" comment if conflicting with "// self managed"
|
||||||
|
existing.leadingComments = (existing.leadingComments ?? []).filter(
|
||||||
|
(c) => c.value.trim() !== '@managed'
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isManaged(existing)) {
|
||||||
|
// the prop already exists and is still managed, so update it's value
|
||||||
|
existing.value = parseExpression(JSON.stringify(value));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// take over the unmanaged child prop by deleting the previous prop and replacing it
|
||||||
|
// with a brand new one
|
||||||
|
remove(properties, existing);
|
||||||
|
properties.push(createManagedChildProp(key, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterate through the props to find "// @managed" props which are no longer in
|
||||||
|
// the `managedValue` and remove them
|
||||||
|
for (const prop of properties) {
|
||||||
|
if (
|
||||||
|
isBasicObjectProp(prop) &&
|
||||||
|
isManaged(prop) &&
|
||||||
|
!Object.prototype.hasOwnProperty.call(managedValue, prop.key.value)
|
||||||
|
) {
|
||||||
|
remove(properties, prop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the settings.json file used by VSCode in the Kibana repository. If the file starts
|
||||||
|
* with the comment "// self managed" then it is not touched. If a top-level keys is prefixed with
|
||||||
|
* `// self managed` then all the properties of that setting are left untouched. And finally, if
|
||||||
|
* a specific child property of a setting like `search.exclude` is prefixed with `// self managed`
|
||||||
|
* then it is left untouched.
|
||||||
|
*
|
||||||
|
* We don't just use `JSON.parse()` and `JSON.stringify()` in order to support this customization and
|
||||||
|
* also to support users using comments in this file, which is very useful for temporarily disabling settings.
|
||||||
|
*
|
||||||
|
* After the config file is updated it is formatted with prettier.
|
||||||
|
*
|
||||||
|
* @param keys The config keys which are managed
|
||||||
|
* @param infoText The text which should be written to the top of the file to educate users how to customize the settings
|
||||||
|
* @param json The settings file as a string
|
||||||
|
*/
|
||||||
|
export function updateVscodeConfig(keys: ManagedConfigKey[], infoText: string, json?: string) {
|
||||||
|
json = json || '{}';
|
||||||
|
const ast = parseExpression(json);
|
||||||
|
|
||||||
|
if (ast.type !== 'ObjectExpression') {
|
||||||
|
throw new Error(`expected VSCode config to contain a JSON object`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSelfManaged(ast)) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const { key, value } of keys) {
|
||||||
|
const existingProp = ast.properties.filter(isBasicObjectProp).find((p) => p.key.value === key);
|
||||||
|
|
||||||
|
if (isSelfManaged(existingProp)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existingProp && existingProp.value.type === 'ObjectExpression') {
|
||||||
|
// setting exists and is an object so merge properties of `value` with it
|
||||||
|
mergeManagedProperties(existingProp.value.properties, value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existingProp) {
|
||||||
|
// setting exists but its value is not an object expression so replace it
|
||||||
|
replaceManagedProp(ast, existingProp, value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// setting isn't in config file so create it
|
||||||
|
addManagedProp(ast, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast.leadingComments = [
|
||||||
|
(infoText
|
||||||
|
? {
|
||||||
|
type: 'CommentBlock',
|
||||||
|
value: `*
|
||||||
|
* @managed
|
||||||
|
*
|
||||||
|
* ${infoText.split(/\r?\n/).join('\n * ')}
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
type: 'CommentLine',
|
||||||
|
value: ' @managed',
|
||||||
|
}) as t.CommentBlock,
|
||||||
|
...(ast.leadingComments ?? [])?.filter((c) => !c.value.includes('@managed')),
|
||||||
|
];
|
||||||
|
|
||||||
|
return Prettier.format(generate(ast).code, {
|
||||||
|
endOfLine: 'auto',
|
||||||
|
filepath: 'settings.json',
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Path from 'path';
|
||||||
|
import Fs from 'fs/promises';
|
||||||
|
|
||||||
|
import { REPO_ROOT } from '@kbn/utils';
|
||||||
|
import dedent from 'dedent';
|
||||||
|
|
||||||
|
import { run } from '../run';
|
||||||
|
|
||||||
|
import { MANAGED_CONFIG_KEYS } from './managed_config_keys';
|
||||||
|
import { updateVscodeConfig } from './update_vscode_config';
|
||||||
|
|
||||||
|
export function runUpdateVscodeConfigCli() {
|
||||||
|
run(async ({ log }) => {
|
||||||
|
const path = Path.resolve(REPO_ROOT, '.vscode/settings.json');
|
||||||
|
|
||||||
|
let json;
|
||||||
|
try {
|
||||||
|
json = await Fs.readFile(path, 'utf-8');
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code !== 'ENOENT') {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedJson = updateVscodeConfig(
|
||||||
|
MANAGED_CONFIG_KEYS,
|
||||||
|
dedent`
|
||||||
|
Some settings in this file are managed by @kbn/dev-utils. When a setting is managed it is preceeded
|
||||||
|
with a comment "// @managed" comment. Replace that with "// self managed" and the scripts will not
|
||||||
|
touch that value. Put a "// self managed" comment at the top of the file, or above a group of settings
|
||||||
|
to disable management of that entire section.
|
||||||
|
`,
|
||||||
|
json
|
||||||
|
);
|
||||||
|
await Fs.mkdir(Path.dirname(path), { recursive: true });
|
||||||
|
await Fs.writeFile(path, updatedJson);
|
||||||
|
|
||||||
|
log.success('updated', path);
|
||||||
|
});
|
||||||
|
}
|
|
@ -446,78 +446,33 @@ describe('OptimizerConfig::create()', () => {
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
expect(findKibanaPlatformPlugins.mock).toMatchInlineSnapshot(`
|
expect(findKibanaPlatformPlugins.mock.calls).toMatchInlineSnapshot(`
|
||||||
Object {
|
Array [
|
||||||
"calls": Array [
|
Array [
|
||||||
Array [
|
Symbol(parsed plugin scan dirs),
|
||||||
Symbol(parsed plugin scan dirs),
|
Symbol(parsed plugin paths),
|
||||||
Symbol(parsed plugin paths),
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
"instances": Array [
|
]
|
||||||
[Window],
|
|
||||||
],
|
|
||||||
"invocationCallOrder": Array [
|
|
||||||
25,
|
|
||||||
],
|
|
||||||
"results": Array [
|
|
||||||
Object {
|
|
||||||
"type": "return",
|
|
||||||
"value": Symbol(new platform plugins),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
`);
|
`);
|
||||||
|
|
||||||
expect(filterById.mock).toMatchInlineSnapshot(`
|
expect(filterById.mock.calls).toMatchInlineSnapshot(`
|
||||||
Object {
|
Array [
|
||||||
"calls": Array [
|
Array [
|
||||||
Array [
|
Array [],
|
||||||
Array [],
|
Symbol(focused bundles),
|
||||||
Symbol(focused bundles),
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
"instances": Array [
|
]
|
||||||
[Window],
|
|
||||||
],
|
|
||||||
"invocationCallOrder": Array [
|
|
||||||
28,
|
|
||||||
],
|
|
||||||
"results": Array [
|
|
||||||
Object {
|
|
||||||
"type": "return",
|
|
||||||
"value": Symbol(filtered bundles),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
`);
|
`);
|
||||||
|
|
||||||
expect(getPluginBundles.mock).toMatchInlineSnapshot(`
|
expect(getPluginBundles.mock.calls).toMatchInlineSnapshot(`
|
||||||
Object {
|
Array [
|
||||||
"calls": Array [
|
Array [
|
||||||
Array [
|
Symbol(new platform plugins),
|
||||||
Symbol(new platform plugins),
|
Symbol(parsed repo root),
|
||||||
Symbol(parsed repo root),
|
Symbol(parsed output root),
|
||||||
Symbol(parsed output root),
|
Symbol(limits),
|
||||||
Symbol(limits),
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
"instances": Array [
|
]
|
||||||
[Window],
|
|
||||||
],
|
|
||||||
"invocationCallOrder": Array [
|
|
||||||
26,
|
|
||||||
],
|
|
||||||
"results": Array [
|
|
||||||
Object {
|
|
||||||
"type": "return",
|
|
||||||
"value": Array [
|
|
||||||
Symbol(bundle1),
|
|
||||||
Symbol(bundle2),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
12
packages/kbn-pm/dist/index.js
vendored
12
packages/kbn-pm/dist/index.js
vendored
|
@ -8968,9 +8968,17 @@ const BootstrapCommand = {
|
||||||
// NOTE: We don't probably need this anymore, is actually not being used
|
// NOTE: We don't probably need this anymore, is actually not being used
|
||||||
|
|
||||||
|
|
||||||
await Object(_utils_link_project_executables__WEBPACK_IMPORTED_MODULE_2__["linkProjectExecutables"])(projects, projectGraph); // Build typescript references
|
await Object(_utils_link_project_executables__WEBPACK_IMPORTED_MODULE_2__["linkProjectExecutables"])(projects, projectGraph); // Update vscode settings
|
||||||
|
|
||||||
await Object(_utils_child_process__WEBPACK_IMPORTED_MODULE_1__["spawnStreaming"])('node', ['scripts/build_ts_refs', '--ignore-type-failures', '--info'], {
|
await Object(_utils_child_process__WEBPACK_IMPORTED_MODULE_1__["spawnStreaming"])(process.execPath, ['scripts/update_vscode_config'], {
|
||||||
|
cwd: kbn.getAbsolute(),
|
||||||
|
env: process.env
|
||||||
|
}, {
|
||||||
|
prefix: '[vscode]',
|
||||||
|
debug: false
|
||||||
|
}); // Build typescript references
|
||||||
|
|
||||||
|
await Object(_utils_child_process__WEBPACK_IMPORTED_MODULE_1__["spawnStreaming"])(process.execPath, ['scripts/build_ts_refs', '--ignore-type-failures', '--info'], {
|
||||||
cwd: kbn.getAbsolute(),
|
cwd: kbn.getAbsolute(),
|
||||||
env: process.env
|
env: process.env
|
||||||
}, {
|
}, {
|
||||||
|
|
|
@ -102,9 +102,20 @@ export const BootstrapCommand: ICommand = {
|
||||||
// NOTE: We don't probably need this anymore, is actually not being used
|
// NOTE: We don't probably need this anymore, is actually not being used
|
||||||
await linkProjectExecutables(projects, projectGraph);
|
await linkProjectExecutables(projects, projectGraph);
|
||||||
|
|
||||||
|
// Update vscode settings
|
||||||
|
await spawnStreaming(
|
||||||
|
process.execPath,
|
||||||
|
['scripts/update_vscode_config'],
|
||||||
|
{
|
||||||
|
cwd: kbn.getAbsolute(),
|
||||||
|
env: process.env,
|
||||||
|
},
|
||||||
|
{ prefix: '[vscode]', debug: false }
|
||||||
|
);
|
||||||
|
|
||||||
// Build typescript references
|
// Build typescript references
|
||||||
await spawnStreaming(
|
await spawnStreaming(
|
||||||
'node',
|
process.execPath,
|
||||||
['scripts/build_ts_refs', '--ignore-type-failures', '--info'],
|
['scripts/build_ts_refs', '--ignore-type-failures', '--info'],
|
||||||
{
|
{
|
||||||
cwd: kbn.getAbsolute(),
|
cwd: kbn.getAbsolute(),
|
||||||
|
|
10
scripts/update_vscode_config.js
Normal file
10
scripts/update_vscode_config.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
require('../src/setup_node_env');
|
||||||
|
require('@kbn/dev-utils').runUpdateVscodeConfigCli();
|
22
yarn.lock
22
yarn.lock
|
@ -110,6 +110,15 @@
|
||||||
jsesc "^2.5.1"
|
jsesc "^2.5.1"
|
||||||
source-map "^0.5.0"
|
source-map "^0.5.0"
|
||||||
|
|
||||||
|
"@babel/generator@^7.12.11":
|
||||||
|
version "7.14.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.5.tgz#848d7b9f031caca9d0cd0af01b063f226f52d785"
|
||||||
|
integrity sha512-y3rlP+/G25OIX3mYKKIOlQRcqj7YgrvHxOLbVmyLJ9bPmi5ttvUmpydVjcFjZphOktWuA7ovbx91ECloWTfjIA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.14.5"
|
||||||
|
jsesc "^2.5.1"
|
||||||
|
source-map "^0.5.0"
|
||||||
|
|
||||||
"@babel/helper-annotate-as-pure@^7.0.0", "@babel/helper-annotate-as-pure@^7.10.4", "@babel/helper-annotate-as-pure@^7.12.10":
|
"@babel/helper-annotate-as-pure@^7.0.0", "@babel/helper-annotate-as-pure@^7.10.4", "@babel/helper-annotate-as-pure@^7.12.10":
|
||||||
version "7.12.10"
|
version "7.12.10"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz#54ab9b000e60a93644ce17b3f37d313aaf1d115d"
|
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz#54ab9b000e60a93644ce17b3f37d313aaf1d115d"
|
||||||
|
@ -300,6 +309,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed"
|
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed"
|
||||||
integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==
|
integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==
|
||||||
|
|
||||||
|
"@babel/helper-validator-identifier@^7.14.5":
|
||||||
|
version "7.14.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz#d0f0e277c512e0c938277faa85a3968c9a44c0e8"
|
||||||
|
integrity sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==
|
||||||
|
|
||||||
"@babel/helper-validator-option@^7.12.1", "@babel/helper-validator-option@^7.12.11":
|
"@babel/helper-validator-option@^7.12.1", "@babel/helper-validator-option@^7.12.11":
|
||||||
version "7.12.11"
|
version "7.12.11"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.11.tgz#d66cb8b7a3e7fe4c6962b32020a131ecf0847f4f"
|
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.11.tgz#d66cb8b7a3e7fe4c6962b32020a131ecf0847f4f"
|
||||||
|
@ -1217,6 +1231,14 @@
|
||||||
lodash "^4.17.19"
|
lodash "^4.17.19"
|
||||||
to-fast-properties "^2.0.0"
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
|
"@babel/types@^7.14.5":
|
||||||
|
version "7.14.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.5.tgz#3bb997ba829a2104cedb20689c4a5b8121d383ff"
|
||||||
|
integrity sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-validator-identifier" "^7.14.5"
|
||||||
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
"@base2/pretty-print-object@1.0.0":
|
"@base2/pretty-print-object@1.0.0":
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@base2/pretty-print-object/-/pretty-print-object-1.0.0.tgz#860ce718b0b73f4009e153541faff2cb6b85d047"
|
resolved "https://registry.yarnpkg.com/@base2/pretty-print-object/-/pretty-print-object-1.0.0.tgz#860ce718b0b73f4009e153541faff2cb6b85d047"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue