diff --git a/.ci/Jenkinsfile_visual_baseline b/.ci/Jenkinsfile_visual_baseline
index 2a16c499fa168..7c7cc8d98c306 100644
--- a/.ci/Jenkinsfile_visual_baseline
+++ b/.ci/Jenkinsfile_visual_baseline
@@ -21,5 +21,6 @@ kibanaPipeline(timeoutMinutes: 120) {
}
kibanaPipeline.sendMail()
+ slackNotifications.onFailure()
}
}
diff --git a/.ci/packer_cache_for_branch.sh b/.ci/packer_cache_for_branch.sh
index a9fbe781915b6..5b4a94be50fa2 100755
--- a/.ci/packer_cache_for_branch.sh
+++ b/.ci/packer_cache_for_branch.sh
@@ -46,7 +46,7 @@ echo "Creating bootstrap_cache archive"
# archive cacheable directories
mkdir -p "$HOME/.kibana/bootstrap_cache"
tar -cf "$HOME/.kibana/bootstrap_cache/$branch.tar" \
- x-pack/plugins/reporting/.chromium \
+ .chromium \
.es \
.chromedriver \
.geckodriver;
diff --git a/.eslintignore b/.eslintignore
index 9de2cc2872960..4b5e781c26971 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,6 +1,7 @@
**/*.js.snap
**/graphql/types.ts
/.es
+/.chromium
/build
/built_assets
/config/apm.dev.js
diff --git a/.eslintrc.js b/.eslintrc.js
index 8d979dc0f8645..4425ad3a12659 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -906,6 +906,18 @@ module.exports = {
},
},
+ /**
+ * Enterprise Search overrides
+ */
+ {
+ files: ['x-pack/plugins/enterprise_search/**/*.{ts,tsx}'],
+ excludedFiles: ['x-pack/plugins/enterprise_search/**/*.{test,mock}.{ts,tsx}'],
+ rules: {
+ 'react-hooks/exhaustive-deps': 'off',
+ '@typescript-eslint/no-explicit-any': 'error',
+ },
+ },
+
/**
* disable jsx-a11y for kbn-ui-framework
*/
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 4aab9943022d4..f053c6da9c29b 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -201,6 +201,11 @@ x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @elastic/kib
# Design
**/*.scss @elastic/kibana-design
+# Enterprise Search
+/x-pack/plugins/enterprise_search/ @elastic/app-search-frontend @elastic/workplace-search-frontend
+/x-pack/test/functional_enterprise_search/ @elastic/app-search-frontend @elastic/workplace-search-frontend
+/x-pack/plugins/enterprise_search/**/*.scss @elastic/ent-search-design
+
# Elasticsearch UI
/src/plugins/dev_tools/ @elastic/es-ui
/src/plugins/console/ @elastic/es-ui
diff --git a/.gitignore b/.gitignore
index 32377ec0f1ffe..716cea937f9c0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
.signing-config.json
.ackrc
/.es
+/.chromium
.DS_Store
.node_binaries
.native_modules
diff --git a/docs/apm/api.asciidoc b/docs/apm/api.asciidoc
index f6bc83d4086c2..97fdcd3e13de9 100644
--- a/docs/apm/api.asciidoc
+++ b/docs/apm/api.asciidoc
@@ -398,7 +398,7 @@ include::api.asciidoc[tag=using-the-APIs]
[%collapsible%open]
======
`version` :::
- (required, string) Name of service.
+ (required, string) Version of service.
`environment` :::
(optional, string) Environment of service.
diff --git a/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.md b/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.md
index 0e2b9bd60ab67..b88a179c5c4b3 100644
--- a/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.md
+++ b/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.md
@@ -19,5 +19,6 @@ export interface DiscoveredPlugin
| [configPath](./kibana-plugin-core-server.discoveredplugin.configpath.md) | ConfigPath
| Root configuration path used by the plugin, defaults to "id" in snake\_case format. |
| [id](./kibana-plugin-core-server.discoveredplugin.id.md) | PluginName
| Identifier of the plugin. |
| [optionalPlugins](./kibana-plugin-core-server.discoveredplugin.optionalplugins.md) | readonly PluginName[]
| An optional list of the other plugins that if installed and enabled \*\*may be\*\* leveraged by this plugin for some additional functionality but otherwise are not required for this plugin to work properly. |
+| [requiredBundles](./kibana-plugin-core-server.discoveredplugin.requiredbundles.md) | readonly PluginName[]
| List of plugin ids that this plugin's UI code imports modules from that are not in requiredPlugins
. |
| [requiredPlugins](./kibana-plugin-core-server.discoveredplugin.requiredplugins.md) | readonly PluginName[]
| An optional list of the other plugins that \*\*must be\*\* installed and enabled for this plugin to function properly. |
diff --git a/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.requiredbundles.md b/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.requiredbundles.md
new file mode 100644
index 0000000000000..6d54adb5236ea
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.requiredbundles.md
@@ -0,0 +1,18 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [DiscoveredPlugin](./kibana-plugin-core-server.discoveredplugin.md) > [requiredBundles](./kibana-plugin-core-server.discoveredplugin.requiredbundles.md)
+
+## DiscoveredPlugin.requiredBundles property
+
+List of plugin ids that this plugin's UI code imports modules from that are not in `requiredPlugins`.
+
+Signature:
+
+```typescript
+readonly requiredBundles: readonly PluginName[];
+```
+
+## Remarks
+
+The plugins listed here will be loaded in the browser, even if the plugin is disabled. Required by `@kbn/optimizer` to support cross-plugin imports. "core" and plugins already listed in `requiredPlugins` do not need to be duplicated here.
+
diff --git a/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md b/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md
index 5edee51d6c523..6db2f89590149 100644
--- a/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md
+++ b/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md
@@ -25,6 +25,7 @@ Should never be used in code outside of Core but is exported for documentation p
| [id](./kibana-plugin-core-server.pluginmanifest.id.md) | PluginName
| Identifier of the plugin. Must be a string in camelCase. Part of a plugin public contract. Other plugins leverage it to access plugin API, navigate to the plugin, etc. |
| [kibanaVersion](./kibana-plugin-core-server.pluginmanifest.kibanaversion.md) | string
| The version of Kibana the plugin is compatible with, defaults to "version". |
| [optionalPlugins](./kibana-plugin-core-server.pluginmanifest.optionalplugins.md) | readonly PluginName[]
| An optional list of the other plugins that if installed and enabled \*\*may be\*\* leveraged by this plugin for some additional functionality but otherwise are not required for this plugin to work properly. |
+| [requiredBundles](./kibana-plugin-core-server.pluginmanifest.requiredbundles.md) | readonly string[]
| List of plugin ids that this plugin's UI code imports modules from that are not in requiredPlugins
. |
| [requiredPlugins](./kibana-plugin-core-server.pluginmanifest.requiredplugins.md) | readonly PluginName[]
| An optional list of the other plugins that \*\*must be\*\* installed and enabled for this plugin to function properly. |
| [server](./kibana-plugin-core-server.pluginmanifest.server.md) | boolean
| Specifies whether plugin includes some server-side specific functionality. |
| [ui](./kibana-plugin-core-server.pluginmanifest.ui.md) | boolean
| Specifies whether plugin includes some client/browser specific functionality that should be included into client bundle via public/ui_plugin.js
file. |
diff --git a/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.requiredbundles.md b/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.requiredbundles.md
new file mode 100644
index 0000000000000..98505d07101fe
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.requiredbundles.md
@@ -0,0 +1,18 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [PluginManifest](./kibana-plugin-core-server.pluginmanifest.md) > [requiredBundles](./kibana-plugin-core-server.pluginmanifest.requiredbundles.md)
+
+## PluginManifest.requiredBundles property
+
+List of plugin ids that this plugin's UI code imports modules from that are not in `requiredPlugins`.
+
+Signature:
+
+```typescript
+readonly requiredBundles: readonly string[];
+```
+
+## Remarks
+
+The plugins listed here will be loaded in the browser, even if the plugin is disabled. Required by `@kbn/optimizer` to support cross-plugin imports. "core" and plugins already listed in `requiredPlugins` do not need to be duplicated here.
+
diff --git a/docs/management/images/management-license.png b/docs/management/images/management-license.png
index 3347aec8632e4..8df9402939b2e 100644
Binary files a/docs/management/images/management-license.png and b/docs/management/images/management-license.png differ
diff --git a/docs/management/managing-licenses.asciidoc b/docs/management/managing-licenses.asciidoc
index 6cd6657a0aaeb..99cfd12eeade9 100644
--- a/docs/management/managing-licenses.asciidoc
+++ b/docs/management/managing-licenses.asciidoc
@@ -1,28 +1,27 @@
[[managing-licenses]]
== License Management
-When you install the default distribution of {kib}, you receive a basic license
-with no expiration date. For the full list of free features that are included in
-the basic license, refer to https://www.elastic.co/subscriptions[the subscription page].
+When you install the default distribution of {kib}, you receive free features
+with no expiration date. For the full list of features, refer to
+{subscriptions}.
-If you want to try out the full set of platinum features, you can activate a
-30-day trial license. To view the
-status of your license, start a trial, or install a new license, open the menu, then go to *Stack Management > {es} > License Management*.
+If you want to try out the full set of features, you can activate a free 30-day
+trial. To view the status of your license, start a trial, or install a new
+license, open the menu, then go to *Stack Management > {es} > License Management*.
NOTE: You can start a trial only if your cluster has not already activated a
trial license for the current major product version. For example, if you have
already activated a trial for 6.0, you cannot start a new trial until
-7.0. You can, however, contact `info@elastic.co` to request an extended trial
-license.
+7.0. You can, however, request an extended trial at {extendtrial}.
When you activate a new license level, new features appear in *Stack Management*.
[role="screenshot"]
image::images/management-license.png[]
-At the end of the trial period, the platinum features operate in a
-<>. You can revert to a basic license,
-extend the trial, or purchase a subscription.
+At the end of the trial period, some features operate in a
+<>. You can revert to Basic, extend the trial,
+or purchase a subscription.
TIP: If {security-features} are enabled, unless you have a trial license,
you must configure Transport Layer Security (TLS) in {es}.
diff --git a/docs/user/reporting/index.asciidoc b/docs/user/reporting/index.asciidoc
index 4123912b79237..6acdbbe3f0a99 100644
--- a/docs/user/reporting/index.asciidoc
+++ b/docs/user/reporting/index.asciidoc
@@ -19,7 +19,7 @@ image::user/reporting/images/share-button.png["Share"]
[float]
== Setup
-{reporting} is automatically enabled in {kib}. The first time {kib} runs, it extracts a custom build for the Chromium web browser, which
+{reporting} is automatically enabled in {kib}. It runs a custom build of the Chromium web browser, which
runs on the server in headless mode to load {kib} and capture the rendered {kib} charts as images.
Chromium is an open-source project not related to Elastic, but the Chromium binary for {kib} has been custom-built by Elastic to ensure it
diff --git a/examples/bfetch_explorer/kibana.json b/examples/bfetch_explorer/kibana.json
index 0039e9647bf83..f32cdfc13a1fe 100644
--- a/examples/bfetch_explorer/kibana.json
+++ b/examples/bfetch_explorer/kibana.json
@@ -5,5 +5,6 @@
"server": true,
"ui": true,
"requiredPlugins": ["bfetch", "developerExamples"],
- "optionalPlugins": []
+ "optionalPlugins": [],
+ "requiredBundles": ["kibanaReact"]
}
diff --git a/examples/dashboard_embeddable_examples/kibana.json b/examples/dashboard_embeddable_examples/kibana.json
index bb2ced569edb5..807229fad9dcf 100644
--- a/examples/dashboard_embeddable_examples/kibana.json
+++ b/examples/dashboard_embeddable_examples/kibana.json
@@ -5,5 +5,6 @@
"server": false,
"ui": true,
"requiredPlugins": ["embeddable", "embeddableExamples", "dashboard", "developerExamples"],
- "optionalPlugins": []
+ "optionalPlugins": [],
+ "requiredBundles": ["esUiShared"]
}
diff --git a/examples/embeddable_examples/kibana.json b/examples/embeddable_examples/kibana.json
index 8ae04c1f6c644..771c19cfdbd3d 100644
--- a/examples/embeddable_examples/kibana.json
+++ b/examples/embeddable_examples/kibana.json
@@ -6,5 +6,6 @@
"ui": true,
"requiredPlugins": ["embeddable", "uiActions"],
"optionalPlugins": [],
- "extraPublicDirs": ["public/todo", "public/hello_world", "public/todo/todo_ref_embeddable"]
+ "extraPublicDirs": ["public/todo", "public/hello_world", "public/todo/todo_ref_embeddable"],
+ "requiredBundles": ["kibanaReact"]
}
diff --git a/examples/state_containers_examples/kibana.json b/examples/state_containers_examples/kibana.json
index 66da207cb4e77..58346af8f1d19 100644
--- a/examples/state_containers_examples/kibana.json
+++ b/examples/state_containers_examples/kibana.json
@@ -5,5 +5,6 @@
"server": true,
"ui": true,
"requiredPlugins": ["navigation", "data", "developerExamples"],
- "optionalPlugins": []
+ "optionalPlugins": [],
+ "requiredBundles": ["kibanaUtils", "kibanaReact"]
}
diff --git a/examples/ui_action_examples/kibana.json b/examples/ui_action_examples/kibana.json
index cd12442daf61c..0e0b6b6830b95 100644
--- a/examples/ui_action_examples/kibana.json
+++ b/examples/ui_action_examples/kibana.json
@@ -5,5 +5,6 @@
"server": false,
"ui": true,
"requiredPlugins": ["uiActions"],
- "optionalPlugins": []
+ "optionalPlugins": [],
+ "requiredBundles": ["kibanaReact"]
}
diff --git a/examples/ui_actions_explorer/kibana.json b/examples/ui_actions_explorer/kibana.json
index f57072e89b06d..0a55e60374710 100644
--- a/examples/ui_actions_explorer/kibana.json
+++ b/examples/ui_actions_explorer/kibana.json
@@ -5,5 +5,6 @@
"server": false,
"ui": true,
"requiredPlugins": ["uiActions", "uiActionsExamples", "developerExamples"],
- "optionalPlugins": []
+ "optionalPlugins": [],
+ "requiredBundles": ["kibanaReact"]
}
diff --git a/package.json b/package.json
index 1a497a2ec8b10..a45f240ce13af 100644
--- a/package.json
+++ b/package.json
@@ -127,7 +127,7 @@
"@elastic/datemath": "5.0.3",
"@elastic/elasticsearch": "7.8.0",
"@elastic/ems-client": "7.9.3",
- "@elastic/eui": "24.1.0",
+ "@elastic/eui": "26.3.1",
"@elastic/filesaver": "1.1.2",
"@elastic/good": "8.1.1-kibana2",
"@elastic/numeral": "^2.5.0",
diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/kibana.json b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/kibana.json
index 20c8046daa65e..33f53e336598d 100644
--- a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/kibana.json
+++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/kibana.json
@@ -1,4 +1,5 @@
{
"id": "bar",
- "ui": true
+ "ui": true,
+ "requiredBundles": ["foo"]
}
diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/_other_styles.scss b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/_other_styles.scss
new file mode 100644
index 0000000000000..2c1b9562b9567
--- /dev/null
+++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/_other_styles.scss
@@ -0,0 +1,3 @@
+p {
+ background-color: rebeccapurple;
+}
diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/styles.scss b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/styles.scss
index e71a2d485a2f8..1dc7bbe9daeb0 100644
--- a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/styles.scss
+++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/styles.scss
@@ -1,3 +1,5 @@
+@import "./other_styles.scss";
+
body {
width: $globalStyleConstant;
background-image: url("ui/icon.svg");
diff --git a/packages/kbn-optimizer/src/cli.ts b/packages/kbn-optimizer/src/cli.ts
index 0916f12a7110d..9d3f4b88a258f 100644
--- a/packages/kbn-optimizer/src/cli.ts
+++ b/packages/kbn-optimizer/src/cli.ts
@@ -87,6 +87,11 @@ run(
throw createFlagError('expected --report-stats to have no value');
}
+ const filter = typeof flags.filter === 'string' ? [flags.filter] : flags.filter;
+ if (!Array.isArray(filter) || !filter.every((f) => typeof f === 'string')) {
+ throw createFlagError('expected --filter to be one or more strings');
+ }
+
const config = OptimizerConfig.create({
repoRoot: REPO_ROOT,
watch,
@@ -99,6 +104,7 @@ run(
extraPluginScanDirs,
inspectWorkers,
includeCoreBundle,
+ filter,
});
let update$ = runOptimizer(config);
@@ -128,12 +134,13 @@ run(
'inspect-workers',
'report-stats',
],
- string: ['workers', 'scan-dir'],
+ string: ['workers', 'scan-dir', 'filter'],
default: {
core: true,
examples: true,
cache: true,
'inspect-workers': true,
+ filter: [],
},
help: `
--watch run the optimizer in watch mode
@@ -142,6 +149,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
+ --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
--scan-dir add a directory to the list of directories scanned for plugins (specify as many times as necessary)
diff --git a/packages/kbn-optimizer/src/common/bundle.test.ts b/packages/kbn-optimizer/src/common/bundle.test.ts
index b209bbca25ac4..6197a08485854 100644
--- a/packages/kbn-optimizer/src/common/bundle.test.ts
+++ b/packages/kbn-optimizer/src/common/bundle.test.ts
@@ -50,6 +50,7 @@ it('creates cache keys', () => {
"spec": Object {
"contextDir": "/foo/bar",
"id": "bar",
+ "manifestPath": undefined,
"outputDir": "/foo/bar/target",
"publicDirNames": Array [
"public",
@@ -85,6 +86,7 @@ it('parses bundles from JSON specs', () => {
},
"contextDir": "/foo/bar",
"id": "bar",
+ "manifestPath": undefined,
"outputDir": "/foo/bar/target",
"publicDirNames": Array [
"public",
diff --git a/packages/kbn-optimizer/src/common/bundle.ts b/packages/kbn-optimizer/src/common/bundle.ts
index 80af94c30f8da..a354da7a21521 100644
--- a/packages/kbn-optimizer/src/common/bundle.ts
+++ b/packages/kbn-optimizer/src/common/bundle.ts
@@ -18,6 +18,7 @@
*/
import Path from 'path';
+import Fs from 'fs';
import { BundleCache } from './bundle_cache';
import { UnknownVals } from './ts_helpers';
@@ -25,6 +26,11 @@ import { includes, ascending, entriesToObject } from './array_helpers';
const VALID_BUNDLE_TYPES = ['plugin' as const, 'entry' as const];
+const DEFAULT_IMPLICIT_BUNDLE_DEPS = ['core'];
+
+const isStringArray = (input: any): input is string[] =>
+ Array.isArray(input) && input.every((x) => typeof x === 'string');
+
export interface BundleSpec {
readonly type: typeof VALID_BUNDLE_TYPES[0];
/** Unique id for this bundle */
@@ -37,6 +43,8 @@ export interface BundleSpec {
readonly sourceRoot: string;
/** Absolute path to the directory where output should be written */
readonly outputDir: string;
+ /** Absolute path to a kibana.json manifest file, if omitted we assume there are not dependenices */
+ readonly manifestPath?: string;
}
export class Bundle {
@@ -56,6 +64,12 @@ export class Bundle {
public readonly sourceRoot: BundleSpec['sourceRoot'];
/** Absolute path to the output directory for this bundle */
public readonly outputDir: BundleSpec['outputDir'];
+ /**
+ * Absolute path to a manifest file with "requiredBundles" which will be
+ * used to allow bundleRefs from this bundle to the exports of another bundle.
+ * Every bundle mentioned in the `requiredBundles` must be built together.
+ */
+ public readonly manifestPath: BundleSpec['manifestPath'];
public readonly cache: BundleCache;
@@ -66,6 +80,7 @@ export class Bundle {
this.contextDir = spec.contextDir;
this.sourceRoot = spec.sourceRoot;
this.outputDir = spec.outputDir;
+ this.manifestPath = spec.manifestPath;
this.cache = new BundleCache(Path.resolve(this.outputDir, '.kbn-optimizer-cache'));
}
@@ -96,8 +111,54 @@ export class Bundle {
contextDir: this.contextDir,
sourceRoot: this.sourceRoot,
outputDir: this.outputDir,
+ manifestPath: this.manifestPath,
};
}
+
+ readBundleDeps(): { implicit: string[]; explicit: string[] } {
+ if (!this.manifestPath) {
+ return {
+ implicit: [...DEFAULT_IMPLICIT_BUNDLE_DEPS],
+ explicit: [],
+ };
+ }
+
+ let json: string;
+ try {
+ json = Fs.readFileSync(this.manifestPath, 'utf8');
+ } catch (error) {
+ if (error.code !== 'ENOENT') {
+ throw error;
+ }
+
+ json = '{}';
+ }
+
+ let parsedManifest: { requiredPlugins?: string[]; requiredBundles?: string[] };
+ try {
+ parsedManifest = JSON.parse(json);
+ } catch (error) {
+ throw new Error(
+ `unable to parse manifest at [${this.manifestPath}], error: [${error.message}]`
+ );
+ }
+
+ if (typeof parsedManifest === 'object' && parsedManifest) {
+ const explicit = parsedManifest.requiredBundles || [];
+ const implicit = [...DEFAULT_IMPLICIT_BUNDLE_DEPS, ...(parsedManifest.requiredPlugins || [])];
+
+ if (isStringArray(explicit) && isStringArray(implicit)) {
+ return {
+ explicit,
+ implicit,
+ };
+ }
+ }
+
+ throw new Error(
+ `Expected "requiredBundles" and "requiredPlugins" in manifest file [${this.manifestPath}] to be arrays of strings`
+ );
+ }
}
/**
@@ -152,6 +213,13 @@ export function parseBundles(json: string) {
throw new Error('`bundles[]` must have an absolute path `outputDir` property');
}
+ const { manifestPath } = spec;
+ if (manifestPath !== undefined) {
+ if (!(typeof manifestPath === 'string' && Path.isAbsolute(manifestPath))) {
+ throw new Error('`bundles[]` must have an absolute path `manifestPath` property');
+ }
+ }
+
return new Bundle({
type,
id,
@@ -159,6 +227,7 @@ export function parseBundles(json: string) {
contextDir,
sourceRoot,
outputDir,
+ manifestPath,
});
}
);
diff --git a/packages/kbn-optimizer/src/common/bundle_cache.ts b/packages/kbn-optimizer/src/common/bundle_cache.ts
index 5ae3e4c28a201..7607e270b5b4f 100644
--- a/packages/kbn-optimizer/src/common/bundle_cache.ts
+++ b/packages/kbn-optimizer/src/common/bundle_cache.ts
@@ -24,6 +24,7 @@ export interface State {
optimizerCacheKey?: unknown;
cacheKey?: unknown;
moduleCount?: number;
+ workUnits?: number;
files?: string[];
bundleRefExportIds?: string[];
}
@@ -96,6 +97,10 @@ export class BundleCache {
return this.get().cacheKey;
}
+ public getWorkUnits() {
+ return this.get().workUnits;
+ }
+
public getOptimizerCacheKey() {
return this.get().optimizerCacheKey;
}
diff --git a/packages/kbn-optimizer/src/common/bundle_refs.ts b/packages/kbn-optimizer/src/common/bundle_refs.ts
index a5c60f2031c0b..85731f32f8991 100644
--- a/packages/kbn-optimizer/src/common/bundle_refs.ts
+++ b/packages/kbn-optimizer/src/common/bundle_refs.ts
@@ -114,6 +114,10 @@ export class BundleRefs {
constructor(private readonly refs: BundleRef[]) {}
+ public forBundleIds(bundleIds: string[]) {
+ return this.refs.filter((r) => bundleIds.includes(r.bundleId));
+ }
+
public filterByExportIds(exportIds: string[]) {
return this.refs.filter((r) => exportIds.includes(r.exportId));
}
diff --git a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap
index 211cfac3806ad..c52873ab7ec20 100644
--- a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap
+++ b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap
@@ -10,6 +10,7 @@ OptimizerConfig {
},
"contextDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar,
"id": "bar",
+ "manifestPath": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/kibana.json,
"outputDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/target/public,
"publicDirNames": Array [
"public",
@@ -24,6 +25,7 @@ OptimizerConfig {
},
"contextDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo,
"id": "foo",
+ "manifestPath": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/kibana.json,
"outputDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/target/public,
"publicDirNames": Array [
"public",
@@ -42,18 +44,21 @@ OptimizerConfig {
"extraPublicDirs": Array [],
"id": "bar",
"isUiPlugin": true,
+ "manifestPath": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/kibana.json,
},
Object {
"directory": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo,
"extraPublicDirs": Array [],
"id": "foo",
"isUiPlugin": true,
+ "manifestPath": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/kibana.json,
},
Object {
"directory": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/nested/baz,
"extraPublicDirs": Array [],
"id": "baz",
"isUiPlugin": false,
+ "manifestPath": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/nested/baz/kibana.json,
},
],
"profileWebpack": false,
@@ -66,7 +71,7 @@ OptimizerConfig {
}
`;
-exports[`prepares assets for distribution: bar bundle 1`] = `"(function(modules){var installedModules={};function __webpack_require__(moduleId){if(installedModules[moduleId]){return installedModules[moduleId].exports}var module=installedModules[moduleId]={i:moduleId,l:false,exports:{}};modules[moduleId].call(module.exports,module,module.exports,__webpack_require__);module.l=true;return module.exports}__webpack_require__.m=modules;__webpack_require__.c=installedModules;__webpack_require__.d=function(exports,name,getter){if(!__webpack_require__.o(exports,name)){Object.defineProperty(exports,name,{enumerable:true,get:getter})}};__webpack_require__.r=function(exports){if(typeof Symbol!==\\"undefined\\"&&Symbol.toStringTag){Object.defineProperty(exports,Symbol.toStringTag,{value:\\"Module\\"})}Object.defineProperty(exports,\\"__esModule\\",{value:true})};__webpack_require__.t=function(value,mode){if(mode&1)value=__webpack_require__(value);if(mode&8)return value;if(mode&4&&typeof value===\\"object\\"&&value&&value.__esModule)return value;var ns=Object.create(null);__webpack_require__.r(ns);Object.defineProperty(ns,\\"default\\",{enumerable:true,value:value});if(mode&2&&typeof value!=\\"string\\")for(var key in value)__webpack_require__.d(ns,key,function(key){return value[key]}.bind(null,key));return ns};__webpack_require__.n=function(module){var getter=module&&module.__esModule?function getDefault(){return module[\\"default\\"]}:function getModuleExports(){return module};__webpack_require__.d(getter,\\"a\\",getter);return getter};__webpack_require__.o=function(object,property){return Object.prototype.hasOwnProperty.call(object,property)};__webpack_require__.p=\\"\\";return __webpack_require__(__webpack_require__.s=5)})([function(module,exports,__webpack_require__){\\"use strict\\";var isOldIE=function isOldIE(){var memo;return function memorize(){if(typeof memo===\\"undefined\\"){memo=Boolean(window&&document&&document.all&&!window.atob)}return memo}}();var getTarget=function getTarget(){var memo={};return function memorize(target){if(typeof memo[target]===\\"undefined\\"){var styleTarget=document.querySelector(target);if(window.HTMLIFrameElement&&styleTarget instanceof window.HTMLIFrameElement){try{styleTarget=styleTarget.contentDocument.head}catch(e){styleTarget=null}}memo[target]=styleTarget}return memo[target]}}();var stylesInDom=[];function getIndexByIdentifier(identifier){var result=-1;for(var i=0;i {
expect(foo.cache.getModuleCount()).toBe(6);
expect(foo.cache.getReferencedFiles()).toMatchInlineSnapshot(`
Array [
+ /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/kibana.json,
/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/async_import.ts,
/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/ext.ts,
/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/index.ts,
@@ -160,12 +161,17 @@ it('builds expected bundles, saves bundle counts to metadata', async () => {
Array [
/node_modules/css-loader/package.json,
/node_modules/style-loader/package.json,
+ /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/kibana.json,
/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/index.scss,
/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/index.ts,
+ /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/legacy/_other_styles.scss,
/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/legacy/styles.scss,
/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/lib.ts,
/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/src/legacy/ui/public/icon.svg,
+ /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/src/legacy/ui/public/styles/_globals_v7dark.scss,
+ /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/src/legacy/ui/public/styles/_globals_v7light.scss,
/packages/kbn-optimizer/target/worker/entry_point_creator.js,
+ /packages/kbn-optimizer/target/worker/postcss.config.js,
/packages/kbn-ui-shared-deps/public_path_module_creator.js,
]
`);
diff --git a/packages/kbn-optimizer/src/log_optimizer_state.ts b/packages/kbn-optimizer/src/log_optimizer_state.ts
index 23767be610da4..20d98f74dbe86 100644
--- a/packages/kbn-optimizer/src/log_optimizer_state.ts
+++ b/packages/kbn-optimizer/src/log_optimizer_state.ts
@@ -54,12 +54,18 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) {
if (event?.type === 'worker started') {
let moduleCount = 0;
+ let workUnits = 0;
for (const bundle of event.bundles) {
moduleCount += bundle.cache.getModuleCount() ?? NaN;
+ workUnits += bundle.cache.getWorkUnits() ?? NaN;
}
- const mcString = isFinite(moduleCount) ? String(moduleCount) : '?';
- const bcString = String(event.bundles.length);
- log.info(`starting worker [${bcString} bundles, ${mcString} modules]`);
+
+ log.info(
+ `starting worker [${event.bundles.length} ${
+ event.bundles.length === 1 ? 'bundle' : 'bundles'
+ }]`
+ );
+ log.debug(`modules [${moduleCount}] work units [${workUnits}]`);
}
if (state.phase === 'reallocating') {
diff --git a/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.test.ts b/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.test.ts
index ca50a49e26913..5443a88eb1a63 100644
--- a/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.test.ts
+++ b/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.test.ts
@@ -23,11 +23,11 @@ import { Bundle } from '../common';
import { assignBundlesToWorkers, Assignments } from './assign_bundles_to_workers';
-const hasModuleCount = (b: Bundle) => b.cache.getModuleCount() !== undefined;
-const noModuleCount = (b: Bundle) => b.cache.getModuleCount() === undefined;
+const hasWorkUnits = (b: Bundle) => b.cache.getWorkUnits() !== undefined;
+const noWorkUnits = (b: Bundle) => b.cache.getWorkUnits() === undefined;
const summarizeBundles = (w: Assignments) =>
[
- w.moduleCount ? `${w.moduleCount} known modules` : '',
+ w.workUnits ? `${w.workUnits} work units` : '',
w.newBundles ? `${w.newBundles} new bundles` : '',
]
.filter(Boolean)
@@ -42,15 +42,15 @@ const assertReturnVal = (workers: Assignments[]) => {
expect(workers).toBeInstanceOf(Array);
for (const worker of workers) {
expect(worker).toEqual({
- moduleCount: expect.any(Number),
+ workUnits: expect.any(Number),
newBundles: expect.any(Number),
bundles: expect.any(Array),
});
- expect(worker.bundles.filter(noModuleCount).length).toBe(worker.newBundles);
+ expect(worker.bundles.filter(noWorkUnits).length).toBe(worker.newBundles);
expect(
- worker.bundles.filter(hasModuleCount).reduce((sum, b) => sum + b.cache.getModuleCount()!, 0)
- ).toBe(worker.moduleCount);
+ worker.bundles.filter(hasWorkUnits).reduce((sum, b) => sum + b.cache.getWorkUnits()!, 0)
+ ).toBe(worker.workUnits);
}
};
@@ -76,7 +76,7 @@ const getBundles = ({
for (let i = 1; i <= withCounts; i++) {
const id = `foo${i}`;
const bundle = testBundle(id);
- bundle.cache.set({ moduleCount: i % 5 === 0 ? i * 10 : i });
+ bundle.cache.set({ workUnits: i % 5 === 0 ? i * 10 : i });
bundles.push(bundle);
}
@@ -95,8 +95,8 @@ it('creates less workers if maxWorkersCount is larger than bundle count', () =>
expect(workers.length).toBe(2);
expect(readConfigs(workers)).toMatchInlineSnapshot(`
Array [
- "worker 0 (1 known modules) => foo1",
- "worker 1 (2 known modules) => foo2",
+ "worker 0 (1 work units) => foo1",
+ "worker 1 (2 work units) => foo2",
]
`);
});
@@ -121,10 +121,10 @@ it('distributes bundles without module counts evenly after assigning modules wit
assertReturnVal(workers);
expect(readConfigs(workers)).toMatchInlineSnapshot(`
Array [
- "worker 0 (78 known modules, 3 new bundles) => foo5,foo11,foo8,foo6,foo2,foo1,bar9,bar5,bar1",
- "worker 1 (78 known modules, 3 new bundles) => foo16,foo14,foo13,foo12,foo9,foo7,foo4,foo3,bar8,bar4,bar0",
- "worker 2 (100 known modules, 2 new bundles) => foo10,bar7,bar3",
- "worker 3 (150 known modules, 2 new bundles) => foo15,bar6,bar2",
+ "worker 0 (78 work units, 3 new bundles) => foo5,foo11,foo8,foo6,foo2,foo1,bar9,bar5,bar1",
+ "worker 1 (78 work units, 3 new bundles) => foo16,foo14,foo13,foo12,foo9,foo7,foo4,foo3,bar8,bar4,bar0",
+ "worker 2 (100 work units, 2 new bundles) => foo10,bar7,bar3",
+ "worker 3 (150 work units, 2 new bundles) => foo15,bar6,bar2",
]
`);
});
@@ -135,8 +135,8 @@ it('distributes 2 bundles to workers evenly', () => {
assertReturnVal(workers);
expect(readConfigs(workers)).toMatchInlineSnapshot(`
Array [
- "worker 0 (1 known modules) => foo1",
- "worker 1 (2 known modules) => foo2",
+ "worker 0 (1 work units) => foo1",
+ "worker 1 (2 work units) => foo2",
]
`);
});
@@ -147,10 +147,10 @@ it('distributes 5 bundles to workers evenly', () => {
assertReturnVal(workers);
expect(readConfigs(workers)).toMatchInlineSnapshot(`
Array [
- "worker 0 (3 known modules) => foo2,foo1",
- "worker 1 (3 known modules) => foo3",
- "worker 2 (4 known modules) => foo4",
- "worker 3 (50 known modules) => foo5",
+ "worker 0 (3 work units) => foo2,foo1",
+ "worker 1 (3 work units) => foo3",
+ "worker 2 (4 work units) => foo4",
+ "worker 3 (50 work units) => foo5",
]
`);
});
@@ -161,10 +161,10 @@ it('distributes 10 bundles to workers evenly', () => {
assertReturnVal(workers);
expect(readConfigs(workers)).toMatchInlineSnapshot(`
Array [
- "worker 0 (20 known modules) => foo9,foo6,foo4,foo1",
- "worker 1 (20 known modules) => foo8,foo7,foo3,foo2",
- "worker 2 (50 known modules) => foo5",
- "worker 3 (100 known modules) => foo10",
+ "worker 0 (20 work units) => foo9,foo6,foo4,foo1",
+ "worker 1 (20 work units) => foo8,foo7,foo3,foo2",
+ "worker 2 (50 work units) => foo5",
+ "worker 3 (100 work units) => foo10",
]
`);
});
@@ -175,10 +175,10 @@ it('distributes 15 bundles to workers evenly', () => {
assertReturnVal(workers);
expect(readConfigs(workers)).toMatchInlineSnapshot(`
Array [
- "worker 0 (70 known modules) => foo14,foo13,foo12,foo11,foo9,foo6,foo4,foo1",
- "worker 1 (70 known modules) => foo5,foo8,foo7,foo3,foo2",
- "worker 2 (100 known modules) => foo10",
- "worker 3 (150 known modules) => foo15",
+ "worker 0 (70 work units) => foo14,foo13,foo12,foo11,foo9,foo6,foo4,foo1",
+ "worker 1 (70 work units) => foo5,foo8,foo7,foo3,foo2",
+ "worker 2 (100 work units) => foo10",
+ "worker 3 (150 work units) => foo15",
]
`);
});
@@ -189,10 +189,10 @@ it('distributes 20 bundles to workers evenly', () => {
assertReturnVal(workers);
expect(readConfigs(workers)).toMatchInlineSnapshot(`
Array [
- "worker 0 (153 known modules) => foo15,foo3",
- "worker 1 (153 known modules) => foo10,foo16,foo13,foo11,foo7,foo6",
- "worker 2 (154 known modules) => foo5,foo19,foo18,foo17,foo14,foo12,foo9,foo8,foo4,foo2,foo1",
- "worker 3 (200 known modules) => foo20",
+ "worker 0 (153 work units) => foo15,foo3",
+ "worker 1 (153 work units) => foo10,foo16,foo13,foo11,foo7,foo6",
+ "worker 2 (154 work units) => foo5,foo19,foo18,foo17,foo14,foo12,foo9,foo8,foo4,foo2,foo1",
+ "worker 3 (200 work units) => foo20",
]
`);
});
@@ -203,10 +203,10 @@ it('distributes 25 bundles to workers evenly', () => {
assertReturnVal(workers);
expect(readConfigs(workers)).toMatchInlineSnapshot(`
Array [
- "worker 0 (250 known modules) => foo20,foo17,foo13,foo9,foo8,foo2,foo1",
- "worker 1 (250 known modules) => foo15,foo23,foo22,foo18,foo16,foo11,foo7,foo3",
- "worker 2 (250 known modules) => foo10,foo5,foo24,foo21,foo19,foo14,foo12,foo6,foo4",
- "worker 3 (250 known modules) => foo25",
+ "worker 0 (250 work units) => foo20,foo17,foo13,foo9,foo8,foo2,foo1",
+ "worker 1 (250 work units) => foo15,foo23,foo22,foo18,foo16,foo11,foo7,foo3",
+ "worker 2 (250 work units) => foo10,foo5,foo24,foo21,foo19,foo14,foo12,foo6,foo4",
+ "worker 3 (250 work units) => foo25",
]
`);
});
@@ -217,10 +217,10 @@ it('distributes 30 bundles to workers evenly', () => {
assertReturnVal(workers);
expect(readConfigs(workers)).toMatchInlineSnapshot(`
Array [
- "worker 0 (352 known modules) => foo30,foo22,foo14,foo11,foo4,foo1",
- "worker 1 (352 known modules) => foo15,foo10,foo28,foo24,foo19,foo16,foo9,foo6",
- "worker 2 (353 known modules) => foo20,foo5,foo29,foo23,foo21,foo13,foo12,foo3,foo2",
- "worker 3 (353 known modules) => foo25,foo27,foo26,foo18,foo17,foo8,foo7",
+ "worker 0 (352 work units) => foo30,foo22,foo14,foo11,foo4,foo1",
+ "worker 1 (352 work units) => foo15,foo10,foo28,foo24,foo19,foo16,foo9,foo6",
+ "worker 2 (353 work units) => foo20,foo5,foo29,foo23,foo21,foo13,foo12,foo3,foo2",
+ "worker 3 (353 work units) => foo25,foo27,foo26,foo18,foo17,foo8,foo7",
]
`);
});
diff --git a/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.ts b/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.ts
index e1bcb22230bf9..44a3b21c5fd47 100644
--- a/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.ts
+++ b/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.ts
@@ -20,19 +20,18 @@
import { Bundle, descending, ascending } from '../common';
// helper types used inside getWorkerConfigs so we don't have
-// to calculate moduleCounts over and over
-
+// to calculate workUnits over and over
export interface Assignments {
- moduleCount: number;
+ workUnits: number;
newBundles: number;
bundles: Bundle[];
}
/** assign a wrapped bundle to a worker */
const assignBundle = (worker: Assignments, bundle: Bundle) => {
- const moduleCount = bundle.cache.getModuleCount();
- if (moduleCount !== undefined) {
- worker.moduleCount += moduleCount;
+ const workUnits = bundle.cache.getWorkUnits();
+ if (workUnits !== undefined) {
+ worker.workUnits += workUnits;
} else {
worker.newBundles += 1;
}
@@ -59,7 +58,7 @@ export function assignBundlesToWorkers(bundles: Bundle[], maxWorkerCount: number
const workers: Assignments[] = [];
for (let i = 0; i < workerCount; i++) {
workers.push({
- moduleCount: 0,
+ workUnits: 0,
newBundles: 0,
bundles: [],
});
@@ -67,18 +66,18 @@ export function assignBundlesToWorkers(bundles: Bundle[], maxWorkerCount: number
/**
* separate the bundles which do and don't have module
- * counts and sort them by [moduleCount, id]
+ * counts and sort them by [workUnits, id]
*/
const bundlesWithCountsDesc = bundles
- .filter((b) => b.cache.getModuleCount() !== undefined)
+ .filter((b) => b.cache.getWorkUnits() !== undefined)
.sort(
descending(
- (b) => b.cache.getModuleCount(),
+ (b) => b.cache.getWorkUnits(),
(b) => b.id
)
);
const bundlesWithoutModuleCounts = bundles
- .filter((b) => b.cache.getModuleCount() === undefined)
+ .filter((b) => b.cache.getWorkUnits() === undefined)
.sort(descending((b) => b.id));
/**
@@ -87,9 +86,9 @@ export function assignBundlesToWorkers(bundles: Bundle[], maxWorkerCount: number
* with module counts are assigned
*/
while (bundlesWithCountsDesc.length) {
- const [smallestWorker, nextSmallestWorker] = workers.sort(ascending((w) => w.moduleCount));
+ const [smallestWorker, nextSmallestWorker] = workers.sort(ascending((w) => w.workUnits));
- while (!nextSmallestWorker || smallestWorker.moduleCount <= nextSmallestWorker.moduleCount) {
+ while (!nextSmallestWorker || smallestWorker.workUnits <= nextSmallestWorker.workUnits) {
const bundle = bundlesWithCountsDesc.shift();
if (!bundle) {
@@ -104,7 +103,7 @@ export function assignBundlesToWorkers(bundles: Bundle[], maxWorkerCount: number
* assign bundles without module counts to workers round-robin
* starting with the smallest workers
*/
- workers.sort(ascending((w) => w.moduleCount));
+ workers.sort(ascending((w) => w.workUnits));
while (bundlesWithoutModuleCounts.length) {
for (const worker of workers) {
const bundle = bundlesWithoutModuleCounts.shift();
diff --git a/packages/kbn-optimizer/src/optimizer/filter_by_id.test.ts b/packages/kbn-optimizer/src/optimizer/filter_by_id.test.ts
new file mode 100644
index 0000000000000..3e848fe616b49
--- /dev/null
+++ b/packages/kbn-optimizer/src/optimizer/filter_by_id.test.ts
@@ -0,0 +1,72 @@
+/*
+ * 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 { filterById, HasId } from './filter_by_id';
+
+const bundles: HasId[] = [
+ { id: 'foo' },
+ { id: 'bar' },
+ { id: 'abc' },
+ { id: 'abcd' },
+ { id: 'abcde' },
+ { id: 'example_a' },
+];
+
+const print = (result: HasId[]) =>
+ result
+ .map((b) => b.id)
+ .sort((a, b) => a.localeCompare(b))
+ .join(', ');
+
+it('[] matches everything', () => {
+ expect(print(filterById([], bundles))).toMatchInlineSnapshot(
+ `"abc, abcd, abcde, bar, example_a, foo"`
+ );
+});
+
+it('* matches everything', () => {
+ expect(print(filterById(['*'], bundles))).toMatchInlineSnapshot(
+ `"abc, abcd, abcde, bar, example_a, foo"`
+ );
+});
+
+it('combines mutliple filters to select any bundle which is matched', () => {
+ expect(print(filterById(['foo', 'bar'], bundles))).toMatchInlineSnapshot(`"bar, foo"`);
+ expect(print(filterById(['bar', 'abc*'], bundles))).toMatchInlineSnapshot(
+ `"abc, abcd, abcde, bar"`
+ );
+});
+
+it('matches everything if any filter is *', () => {
+ expect(print(filterById(['*', '!abc*'], bundles))).toMatchInlineSnapshot(
+ `"abc, abcd, abcde, bar, example_a, foo"`
+ );
+});
+
+it('only matches bundles which are matched by an entire single filter', () => {
+ expect(print(filterById(['*,!abc*'], bundles))).toMatchInlineSnapshot(`"bar, example_a, foo"`);
+});
+
+it('handles purely positive filters', () => {
+ expect(print(filterById(['abc*'], bundles))).toMatchInlineSnapshot(`"abc, abcd, abcde"`);
+});
+
+it('handles purely negative filters', () => {
+ expect(print(filterById(['!abc*'], bundles))).toMatchInlineSnapshot(`"bar, example_a, foo"`);
+});
diff --git a/packages/kbn-optimizer/src/optimizer/filter_by_id.ts b/packages/kbn-optimizer/src/optimizer/filter_by_id.ts
new file mode 100644
index 0000000000000..ccf61a9efc880
--- /dev/null
+++ b/packages/kbn-optimizer/src/optimizer/filter_by_id.ts
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+export interface HasId {
+ id: string;
+}
+
+function parseFilter(filter: string) {
+ const positive: RegExp[] = [];
+ const negative: RegExp[] = [];
+
+ for (const segment of filter.split(',')) {
+ let trimmed = segment.trim();
+ let list = positive;
+
+ if (trimmed.startsWith('!')) {
+ trimmed = trimmed.slice(1);
+ list = negative;
+ }
+
+ list.push(new RegExp(`^${trimmed.split('*').join('.*')}$`));
+ }
+
+ return (bundle: HasId) =>
+ (!positive.length || positive.some((p) => p.test(bundle.id))) &&
+ (!negative.length || !negative.some((p) => p.test(bundle.id)));
+}
+
+export function filterById(filterStrings: string[], bundles: T[]) {
+ const filters = filterStrings.map(parseFilter);
+ return bundles.filter((b) => !filters.length || filters.some((f) => f(b)));
+}
diff --git a/packages/kbn-optimizer/src/optimizer/get_plugin_bundles.test.ts b/packages/kbn-optimizer/src/optimizer/get_plugin_bundles.test.ts
index bbd3ddc11f448..a70cfc759dd55 100644
--- a/packages/kbn-optimizer/src/optimizer/get_plugin_bundles.test.ts
+++ b/packages/kbn-optimizer/src/optimizer/get_plugin_bundles.test.ts
@@ -32,18 +32,21 @@ it('returns a bundle for core and each plugin', () => {
id: 'foo',
isUiPlugin: true,
extraPublicDirs: [],
+ manifestPath: '/repo/plugins/foo/kibana.json',
},
{
directory: '/repo/plugins/bar',
id: 'bar',
isUiPlugin: false,
extraPublicDirs: [],
+ manifestPath: '/repo/plugins/bar/kibana.json',
},
{
directory: '/outside/of/repo/plugins/baz',
id: 'baz',
isUiPlugin: true,
extraPublicDirs: [],
+ manifestPath: '/outside/of/repo/plugins/baz/kibana.json',
},
],
'/repo'
@@ -53,6 +56,7 @@ it('returns a bundle for core and each plugin', () => {
Object {
"contextDir": /plugins/foo,
"id": "foo",
+ "manifestPath": /plugins/foo/kibana.json,
"outputDir": /plugins/foo/target/public,
"publicDirNames": Array [
"public",
@@ -63,6 +67,7 @@ it('returns a bundle for core and each plugin', () => {
Object {
"contextDir": "/outside/of/repo/plugins/baz",
"id": "baz",
+ "manifestPath": "/outside/of/repo/plugins/baz/kibana.json",
"outputDir": "/outside/of/repo/plugins/baz/target/public",
"publicDirNames": Array [
"public",
diff --git a/packages/kbn-optimizer/src/optimizer/get_plugin_bundles.ts b/packages/kbn-optimizer/src/optimizer/get_plugin_bundles.ts
index 2635289088725..04ab992addeec 100644
--- a/packages/kbn-optimizer/src/optimizer/get_plugin_bundles.ts
+++ b/packages/kbn-optimizer/src/optimizer/get_plugin_bundles.ts
@@ -35,6 +35,7 @@ export function getPluginBundles(plugins: KibanaPlatformPlugin[], repoRoot: stri
sourceRoot: repoRoot,
contextDir: p.directory,
outputDir: Path.resolve(p.directory, 'target/public'),
+ manifestPath: p.manifestPath,
})
);
}
diff --git a/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.test.ts b/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.test.ts
index f7b457ca42c6d..06fffc953f58b 100644
--- a/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.test.ts
+++ b/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.test.ts
@@ -40,24 +40,28 @@ it('parses kibana.json files of plugins found in pluginDirs', () => {
"extraPublicDirs": Array [],
"id": "bar",
"isUiPlugin": true,
+ "manifestPath": /packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/kibana.json,
},
Object {
"directory": /packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo,
"extraPublicDirs": Array [],
"id": "foo",
"isUiPlugin": true,
+ "manifestPath": /packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/kibana.json,
},
Object {
"directory": /packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/nested/baz,
"extraPublicDirs": Array [],
"id": "baz",
"isUiPlugin": false,
+ "manifestPath": /packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/nested/baz/kibana.json,
},
Object {
"directory": /packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz,
"extraPublicDirs": Array [],
"id": "test_baz",
"isUiPlugin": false,
+ "manifestPath": /packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz/kibana.json,
},
]
`);
diff --git a/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.ts b/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.ts
index 83637691004f4..b489c53be47b9 100644
--- a/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.ts
+++ b/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.ts
@@ -24,6 +24,7 @@ import loadJsonFile from 'load-json-file';
export interface KibanaPlatformPlugin {
readonly directory: string;
+ readonly manifestPath: string;
readonly id: string;
readonly isUiPlugin: boolean;
readonly extraPublicDirs: string[];
@@ -92,6 +93,7 @@ function readKibanaPlatformPlugin(manifestPath: string): KibanaPlatformPlugin {
return {
directory: Path.dirname(manifestPath),
+ manifestPath,
id: manifest.id,
isUiPlugin: !!manifest.ui,
extraPublicDirs: extraPublicDirs || [],
diff --git a/packages/kbn-optimizer/src/optimizer/optimizer_config.test.ts b/packages/kbn-optimizer/src/optimizer/optimizer_config.test.ts
index 5b46d67479fd5..f97646e2bbbd3 100644
--- a/packages/kbn-optimizer/src/optimizer/optimizer_config.test.ts
+++ b/packages/kbn-optimizer/src/optimizer/optimizer_config.test.ts
@@ -21,6 +21,7 @@ jest.mock('./assign_bundles_to_workers.ts');
jest.mock('./kibana_platform_plugins.ts');
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';
@@ -113,6 +114,7 @@ describe('OptimizerConfig::parseOptions()', () => {
Object {
"cache": true,
"dist": false,
+ "filters": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
@@ -139,6 +141,7 @@ describe('OptimizerConfig::parseOptions()', () => {
Object {
"cache": false,
"dist": false,
+ "filters": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
@@ -165,6 +168,7 @@ describe('OptimizerConfig::parseOptions()', () => {
Object {
"cache": true,
"dist": false,
+ "filters": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
@@ -193,6 +197,7 @@ describe('OptimizerConfig::parseOptions()', () => {
Object {
"cache": true,
"dist": false,
+ "filters": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
@@ -218,6 +223,7 @@ describe('OptimizerConfig::parseOptions()', () => {
Object {
"cache": true,
"dist": false,
+ "filters": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
@@ -243,6 +249,7 @@ describe('OptimizerConfig::parseOptions()', () => {
Object {
"cache": true,
"dist": false,
+ "filters": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
@@ -265,6 +272,7 @@ describe('OptimizerConfig::parseOptions()', () => {
Object {
"cache": false,
"dist": false,
+ "filters": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
@@ -287,6 +295,7 @@ describe('OptimizerConfig::parseOptions()', () => {
Object {
"cache": false,
"dist": false,
+ "filters": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
@@ -310,6 +319,7 @@ describe('OptimizerConfig::parseOptions()', () => {
Object {
"cache": false,
"dist": false,
+ "filters": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
@@ -333,6 +343,7 @@ describe('OptimizerConfig::parseOptions()', () => {
Object {
"cache": true,
"dist": false,
+ "filters": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
@@ -358,6 +369,7 @@ describe('OptimizerConfig::create()', () => {
const findKibanaPlatformPlugins: jest.Mock = jest.requireMock('./kibana_platform_plugins.ts')
.findKibanaPlatformPlugins;
const getPluginBundles: jest.Mock = jest.requireMock('./get_plugin_bundles.ts').getPluginBundles;
+ const filterById: jest.Mock = jest.requireMock('./filter_by_id.ts').filterById;
beforeEach(() => {
if ('mock' in OptimizerConfig.parseOptions) {
@@ -370,6 +382,7 @@ describe('OptimizerConfig::create()', () => {
]);
findKibanaPlatformPlugins.mockReturnValue(Symbol('new platform plugins'));
getPluginBundles.mockReturnValue([Symbol('bundle1'), Symbol('bundle2')]);
+ filterById.mockReturnValue(Symbol('filtered bundles'));
jest.spyOn(OptimizerConfig, 'parseOptions').mockImplementation((): any => ({
cache: Symbol('parsed cache'),
@@ -382,6 +395,7 @@ describe('OptimizerConfig::create()', () => {
themeTags: Symbol('theme tags'),
inspectWorkers: Symbol('parsed inspect workers'),
profileWebpack: Symbol('parsed profile webpack'),
+ filters: [],
}));
});
@@ -392,10 +406,7 @@ describe('OptimizerConfig::create()', () => {
expect(config).toMatchInlineSnapshot(`
OptimizerConfig {
- "bundles": Array [
- Symbol(bundle1),
- Symbol(bundle2),
- ],
+ "bundles": Symbol(filtered bundles),
"cache": Symbol(parsed cache),
"dist": Symbol(parsed dist),
"inspectWorkers": Symbol(parsed inspect workers),
@@ -431,6 +442,32 @@ describe('OptimizerConfig::create()', () => {
}
`);
+ expect(filterById.mock).toMatchInlineSnapshot(`
+ Object {
+ "calls": Array [
+ Array [
+ Array [],
+ Array [
+ Symbol(bundle1),
+ Symbol(bundle2),
+ ],
+ ],
+ ],
+ "instances": Array [
+ [Window],
+ ],
+ "invocationCallOrder": Array [
+ 23,
+ ],
+ "results": Array [
+ Object {
+ "type": "return",
+ "value": Symbol(filtered bundles),
+ },
+ ],
+ }
+ `);
+
expect(getPluginBundles.mock).toMatchInlineSnapshot(`
Object {
"calls": Array [
diff --git a/packages/kbn-optimizer/src/optimizer/optimizer_config.ts b/packages/kbn-optimizer/src/optimizer/optimizer_config.ts
index 7757004139d0d..0e588ab36238b 100644
--- a/packages/kbn-optimizer/src/optimizer/optimizer_config.ts
+++ b/packages/kbn-optimizer/src/optimizer/optimizer_config.ts
@@ -31,6 +31,7 @@ import {
import { findKibanaPlatformPlugins, KibanaPlatformPlugin } from './kibana_platform_plugins';
import { getPluginBundles } from './get_plugin_bundles';
+import { filterById } from './filter_by_id';
function pickMaxWorkerCount(dist: boolean) {
// don't break if cpus() returns nothing, or an empty array
@@ -77,6 +78,18 @@ interface Options {
pluginScanDirs?: string[];
/** absolute paths that should be added to the default scan dirs */
extraPluginScanDirs?: string[];
+ /**
+ * array of comma separated patterns that will be matched against bundle ids.
+ * bundles will only be built if they match one of the specified patterns.
+ * `*` can exist anywhere in each pattern and will match anything, `!` inverts the pattern
+ *
+ * examples:
+ * --filter foo --filter bar # [foo, bar], excludes [foobar]
+ * --filter foo,bar # [foo, bar], excludes [foobar]
+ * --filter foo* # [foo, foobar], excludes [bar]
+ * --filter f*r # [foobar], excludes [foo, bar]
+ */
+ filter?: string[];
/** flag that causes the core bundle to be built along with plugins */
includeCoreBundle?: boolean;
@@ -103,6 +116,7 @@ interface ParsedOptions {
dist: boolean;
pluginPaths: string[];
pluginScanDirs: string[];
+ filters: string[];
inspectWorkers: boolean;
includeCoreBundle: boolean;
themeTags: ThemeTags;
@@ -118,6 +132,7 @@ export class OptimizerConfig {
const inspectWorkers = !!options.inspectWorkers;
const cache = options.cache !== false && !process.env.KBN_OPTIMIZER_NO_CACHE;
const includeCoreBundle = !!options.includeCoreBundle;
+ const filters = options.filter || [];
const repoRoot = options.repoRoot;
if (!Path.isAbsolute(repoRoot)) {
@@ -172,6 +187,7 @@ export class OptimizerConfig {
cache,
pluginScanDirs,
pluginPaths,
+ filters,
inspectWorkers,
includeCoreBundle,
themeTags,
@@ -198,7 +214,7 @@ export class OptimizerConfig {
];
return new OptimizerConfig(
- bundles,
+ filterById(options.filters, bundles),
options.cache,
options.watch,
options.inspectWorkers,
diff --git a/packages/kbn-optimizer/src/worker/bundle_ref_module.ts b/packages/kbn-optimizer/src/worker/bundle_ref_module.ts
index cde25564cf528..563b4ecb4bc37 100644
--- a/packages/kbn-optimizer/src/worker/bundle_ref_module.ts
+++ b/packages/kbn-optimizer/src/worker/bundle_ref_module.ts
@@ -10,6 +10,7 @@
// @ts-ignore not typed by @types/webpack
import Module from 'webpack/lib/Module';
+import { BundleRef } from '../common';
export class BundleRefModule extends Module {
public built = false;
@@ -17,12 +18,12 @@ export class BundleRefModule extends Module {
public buildInfo?: any;
public exportsArgument = '__webpack_exports__';
- constructor(public readonly exportId: string) {
+ constructor(public readonly ref: BundleRef) {
super('kbn/bundleRef', null);
}
libIdent() {
- return this.exportId;
+ return this.ref.exportId;
}
chunkCondition(chunk: any) {
@@ -30,7 +31,7 @@ export class BundleRefModule extends Module {
}
identifier() {
- return '@kbn/bundleRef ' + JSON.stringify(this.exportId);
+ return '@kbn/bundleRef ' + JSON.stringify(this.ref.exportId);
}
readableIdentifier() {
@@ -51,7 +52,7 @@ export class BundleRefModule extends Module {
source() {
return `
__webpack_require__.r(__webpack_exports__);
- var ns = __kbnBundles__.get('${this.exportId}');
+ var ns = __kbnBundles__.get('${this.ref.exportId}');
Object.defineProperties(__webpack_exports__, Object.getOwnPropertyDescriptors(ns))
`;
}
diff --git a/packages/kbn-optimizer/src/worker/bundle_refs_plugin.ts b/packages/kbn-optimizer/src/worker/bundle_refs_plugin.ts
index 9c4d5ed7f8a98..5396d11726f7a 100644
--- a/packages/kbn-optimizer/src/worker/bundle_refs_plugin.ts
+++ b/packages/kbn-optimizer/src/worker/bundle_refs_plugin.ts
@@ -44,6 +44,7 @@ export class BundleRefsPlugin {
private readonly resolvedRefEntryCache = new Map>();
private readonly resolvedRequestCache = new Map>();
private readonly ignorePrefix = Path.resolve(this.bundle.contextDir) + Path.sep;
+ private allowedBundleIds = new Set();
constructor(private readonly bundle: Bundle, private readonly bundleRefs: BundleRefs) {}
@@ -81,6 +82,45 @@ export class BundleRefsPlugin {
}
);
});
+
+ compiler.hooks.compilation.tap('BundleRefsPlugin/getRequiredBundles', (compilation) => {
+ this.allowedBundleIds.clear();
+
+ const manifestPath = this.bundle.manifestPath;
+ if (!manifestPath) {
+ return;
+ }
+
+ const deps = this.bundle.readBundleDeps();
+ for (const ref of this.bundleRefs.forBundleIds([...deps.explicit, ...deps.implicit])) {
+ this.allowedBundleIds.add(ref.bundleId);
+ }
+
+ compilation.hooks.additionalAssets.tap('BundleRefsPlugin/watchManifest', () => {
+ compilation.fileDependencies.add(manifestPath);
+ });
+
+ compilation.hooks.finishModules.tapPromise(
+ 'BundleRefsPlugin/finishModules',
+ async (modules) => {
+ const usedBundleIds = (modules as any[])
+ .filter((m: any): m is BundleRefModule => m instanceof BundleRefModule)
+ .map((m) => m.ref.bundleId);
+
+ const unusedBundleIds = deps.explicit
+ .filter((id) => !usedBundleIds.includes(id))
+ .join(', ');
+
+ if (unusedBundleIds) {
+ const error = new Error(
+ `Bundle for [${this.bundle.id}] lists [${unusedBundleIds}] as a required bundle, but does not use it. Please remove it.`
+ );
+ (error as any).file = manifestPath;
+ compilation.errors.push(error);
+ }
+ }
+ );
+ });
}
private cachedResolveRefEntry(ref: BundleRef) {
@@ -170,21 +210,29 @@ export class BundleRefsPlugin {
return;
}
- const eligibleRefs = this.bundleRefs.filterByContextPrefix(this.bundle, resolved);
- if (!eligibleRefs.length) {
+ const possibleRefs = this.bundleRefs.filterByContextPrefix(this.bundle, resolved);
+ if (!possibleRefs.length) {
// import doesn't match a bundle context
return;
}
- for (const ref of eligibleRefs) {
+ for (const ref of possibleRefs) {
const resolvedEntry = await this.cachedResolveRefEntry(ref);
- if (resolved === resolvedEntry) {
- return new BundleRefModule(ref.exportId);
+ if (resolved !== resolvedEntry) {
+ continue;
}
+
+ if (!this.allowedBundleIds.has(ref.bundleId)) {
+ throw new Error(
+ `import [${request}] references a public export of the [${ref.bundleId}] bundle, but that bundle is not in the "requiredPlugins" or "requiredBundles" list in the plugin manifest [${this.bundle.manifestPath}]`
+ );
+ }
+
+ return new BundleRefModule(ref);
}
- const bundleId = Array.from(new Set(eligibleRefs.map((r) => r.bundleId))).join(', ');
- const publicDir = eligibleRefs.map((r) => r.entry).join(', ');
+ const bundleId = Array.from(new Set(possibleRefs.map((r) => r.bundleId))).join(', ');
+ const publicDir = possibleRefs.map((r) => r.entry).join(', ');
throw new Error(
`import [${request}] references a non-public export of the [${bundleId}] bundle and must point to one of the public directories: [${publicDir}]`
);
diff --git a/packages/kbn-optimizer/src/worker/run_compilers.ts b/packages/kbn-optimizer/src/worker/run_compilers.ts
index ca7673748bde9..c7be943d65a48 100644
--- a/packages/kbn-optimizer/src/worker/run_compilers.ts
+++ b/packages/kbn-optimizer/src/worker/run_compilers.ts
@@ -50,6 +50,15 @@ import {
const PLUGIN_NAME = '@kbn/optimizer';
+/**
+ * sass-loader creates about a 40% overhead on the overall optimizer runtime, and
+ * so this constant is used to indicate to assignBundlesToWorkers() that there is
+ * extra work done in a bundle that has a lot of scss imports. The value is
+ * arbitrary and just intended to weigh the bundles so that they are distributed
+ * across mulitple workers on machines with lots of cores.
+ */
+const EXTRA_SCSS_WORK_UNITS = 100;
+
/**
* Create an Observable for a specific child compiler + bundle
*/
@@ -102,6 +111,11 @@ const observeCompiler = (
const bundleRefExportIds: string[] = [];
const referencedFiles = new Set();
let normalModuleCount = 0;
+ let workUnits = stats.compilation.fileDependencies.size;
+
+ if (bundle.manifestPath) {
+ referencedFiles.add(bundle.manifestPath);
+ }
for (const module of stats.compilation.modules) {
if (isNormalModule(module)) {
@@ -111,6 +125,15 @@ const observeCompiler = (
if (!parsedPath.dirs.includes('node_modules')) {
referencedFiles.add(path);
+
+ if (path.endsWith('.scss')) {
+ workUnits += EXTRA_SCSS_WORK_UNITS;
+
+ for (const depPath of module.buildInfo.fileDependencies) {
+ referencedFiles.add(depPath);
+ }
+ }
+
continue;
}
@@ -127,7 +150,7 @@ const observeCompiler = (
}
if (module instanceof BundleRefModule) {
- bundleRefExportIds.push(module.exportId);
+ bundleRefExportIds.push(module.ref.exportId);
continue;
}
@@ -158,6 +181,7 @@ const observeCompiler = (
optimizerCacheKey: workerConfig.optimizerCacheKey,
cacheKey: bundle.createCacheKey(files, mtimes),
moduleCount: normalModuleCount,
+ workUnits,
files,
});
diff --git a/packages/kbn-test/src/functional_test_runner/lib/config/schema.ts b/packages/kbn-test/src/functional_test_runner/lib/config/schema.ts
index 6cbdc5ec7fc20..e1d3bf1a8d901 100644
--- a/packages/kbn-test/src/functional_test_runner/lib/config/schema.ts
+++ b/packages/kbn-test/src/functional_test_runner/lib/config/schema.ts
@@ -148,7 +148,7 @@ export const schema = Joi.object()
browser: Joi.object()
.keys({
- type: Joi.string().valid('chrome', 'firefox', 'ie', 'msedge').default('chrome'),
+ type: Joi.string().valid('chrome', 'firefox', 'msedge').default('chrome'),
logPollingMs: Joi.number().default(100),
acceptInsecureCerts: Joi.boolean().default(false),
diff --git a/packages/kbn-ui-shared-deps/package.json b/packages/kbn-ui-shared-deps/package.json
index 6ea4a621f92f6..8398d1c081da6 100644
--- a/packages/kbn-ui-shared-deps/package.json
+++ b/packages/kbn-ui-shared-deps/package.json
@@ -10,7 +10,7 @@
},
"dependencies": {
"@elastic/charts": "19.8.1",
- "@elastic/eui": "24.1.0",
+ "@elastic/eui": "26.3.1",
"@elastic/numeral": "^2.5.0",
"@kbn/i18n": "1.0.0",
"@kbn/monaco": "1.0.0",
diff --git a/src/cli/cluster/cluster_manager.ts b/src/cli/cluster/cluster_manager.ts
index 6db6199b391e1..f193f33e6f47e 100644
--- a/src/cli/cluster/cluster_manager.ts
+++ b/src/cli/cluster/cluster_manager.ts
@@ -261,7 +261,7 @@ export class ClusterManager {
/debug\.log$/,
...pluginInternalDirsIgnore,
fromRoot('src/legacy/server/sass/__tmp__'),
- fromRoot('x-pack/plugins/reporting/.chromium'),
+ fromRoot('x-pack/plugins/reporting/chromium'),
fromRoot('x-pack/plugins/security_solution/cypress'),
fromRoot('x-pack/plugins/apm/e2e'),
fromRoot('x-pack/plugins/apm/scripts'),
diff --git a/src/core/public/chrome/chrome_service.tsx b/src/core/public/chrome/chrome_service.tsx
index 1b894bc400f08..d29120e6ee9ac 100644
--- a/src/core/public/chrome/chrome_service.tsx
+++ b/src/core/public/chrome/chrome_service.tsx
@@ -17,7 +17,7 @@
* under the License.
*/
-import { Breadcrumb as EuiBreadcrumb, IconType } from '@elastic/eui';
+import { EuiBreadcrumb, IconType } from '@elastic/eui';
import React from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import { BehaviorSubject, combineLatest, merge, Observable, of, ReplaySubject } from 'rxjs';
diff --git a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap
index 9fee7b50f371b..9ecbc055e3320 100644
--- a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap
+++ b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap
@@ -149,7 +149,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = `
"euiIconType": "logoSecurity",
"id": "security",
"label": "Security",
- "order": 3000,
+ "order": 4000,
},
"data-test-subj": "siem",
"href": "siem",
@@ -164,7 +164,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = `
"euiIconType": "logoObservability",
"id": "observability",
"label": "Observability",
- "order": 2000,
+ "order": 3000,
},
"data-test-subj": "metrics",
"href": "metrics",
@@ -233,7 +233,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = `
"euiIconType": "logoObservability",
"id": "observability",
"label": "Observability",
- "order": 2000,
+ "order": 3000,
},
"data-test-subj": "logs",
"href": "logs",
@@ -372,12 +372,13 @@ exports[`CollapsibleNav renders links grouped by category 1`] = `
handler={[Function]}
/>
}
/>
@@ -3908,16 +3909,9 @@ exports[`CollapsibleNav renders the default nav 2`] = `
handler={[Function]}
/>
-
- }
- />
-
+ />
+
+
+
+
+
@@ -1683,7 +1709,7 @@ exports[`NewVisModal should render as expected 1`] = `
-
+
+
+
+
+
+
-
+
+
+
-
+
+
+
+
+
+
+
@@ -2073,120 +2104,125 @@ exports[`NewVisModal should render as expected 1`] = `
aria-live="polite"
class="euiScreenReaderOnly"
/>
-
+
+
+
+
+
+
-
+
+
+
-
+
+
+
+
+
+
+
@@ -2307,120 +2343,125 @@ exports[`NewVisModal should render as expected 1`] = `
aria-live="polite"
class="euiScreenReaderOnly"
/>
-
+
+
+
+
+
+
-
+
+
+
-
+
+
+
+
+
+
+
@@ -2643,261 +2684,272 @@ exports[`NewVisModal should render as expected 1`] = `
className="visNewVisDialog__types"
data-test-subj="visNewDialogTypes"
>
-
-
- Vis Type 1
-
- }
- onBlur={[Function]}
- onClick={[Function]}
- onFocus={[Function]}
- onMouseEnter={[Function]}
- onMouseLeave={[Function]}
- role="menuitem"
+
-
-
-
- Vis with alias Url
-
- }
- onBlur={[Function]}
- onClick={[Function]}
- onFocus={[Function]}
- onMouseEnter={[Function]}
- onMouseLeave={[Function]}
- role="menuitem"
+
+ Vis Type 1
+
+
+
+
+
+
+
-
+
+
+
-
-
-
+
+ Vis with search
+
+
+
+
+
+
+
diff --git a/src/plugins/visualize/kibana.json b/src/plugins/visualize/kibana.json
index c27cfec24b332..520d1e1daa6fe 100644
--- a/src/plugins/visualize/kibana.json
+++ b/src/plugins/visualize/kibana.json
@@ -11,5 +11,11 @@
"visualizations",
"embeddable"
],
- "optionalPlugins": ["home", "share"]
+ "optionalPlugins": ["home", "share"],
+ "requiredBundles": [
+ "kibanaUtils",
+ "kibanaReact",
+ "home",
+ "discover"
+ ]
}
diff --git a/test/functional/apps/home/_navigation.ts b/test/functional/apps/home/_navigation.ts
index cfe4f9cc3e014..b8fa5b184cd1f 100644
--- a/test/functional/apps/home/_navigation.ts
+++ b/test/functional/apps/home/_navigation.ts
@@ -26,21 +26,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const PageObjects = getPageObjects(['common', 'header', 'home', 'timePicker']);
const appsMenu = getService('appsMenu');
const esArchiver = getService('esArchiver');
- const kibanaServer = getService('kibanaServer');
describe('Kibana browser back navigation should work', function describeIndexTests() {
before(async () => {
await esArchiver.loadIfNeeded('discover');
await esArchiver.loadIfNeeded('logstash_functional');
- if (browser.isInternetExplorer) {
- await kibanaServer.uiSettings.replace({ 'state:storeInSessionStorage': false });
- }
- });
-
- after(async () => {
- if (browser.isInternetExplorer) {
- await kibanaServer.uiSettings.replace({ 'state:storeInSessionStorage': true });
- }
});
it('detect navigate back issues', async () => {
diff --git a/test/functional/page_objects/time_picker.ts b/test/functional/page_objects/time_picker.ts
index 7ef291c8c7005..8a726cee444c1 100644
--- a/test/functional/page_objects/time_picker.ts
+++ b/test/functional/page_objects/time_picker.ts
@@ -98,13 +98,6 @@ export function TimePickerProvider({ getService, getPageObjects }: FtrProviderCo
const input = await testSubjects.find(dataTestSubj);
await input.clearValue();
await input.type(value);
- } else if (browser.isInternetExplorer) {
- const input = await testSubjects.find(dataTestSubj);
- const currentValue = await input.getAttribute('value');
- await input.type(browser.keys.ARROW_RIGHT.repeat(currentValue.length));
- await input.type(browser.keys.BACK_SPACE.repeat(currentValue.length));
- await input.type(value);
- await input.click();
} else {
await testSubjects.setValue(dataTestSubj, value);
}
diff --git a/test/functional/services/common/browser.ts b/test/functional/services/common/browser.ts
index 2d35551b04808..c38ac771e4162 100644
--- a/test/functional/services/common/browser.ts
+++ b/test/functional/services/common/browser.ts
@@ -34,8 +34,6 @@ export async function BrowserProvider({ getService }: FtrProviderContext) {
const log = getService('log');
const { driver, browserType } = await getService('__webdriver__').init();
- const isW3CEnabled = (driver as any).executor_.w3c === true;
-
return new (class BrowserService {
/**
* Keyboard events
@@ -53,19 +51,12 @@ export async function BrowserProvider({ getService }: FtrProviderContext) {
public readonly isFirefox: boolean = browserType === Browsers.Firefox;
- public readonly isInternetExplorer: boolean = browserType === Browsers.InternetExplorer;
-
- /**
- * Is WebDriver instance W3C compatible
- */
- isW3CEnabled = isW3CEnabled;
-
/**
* Returns instance of Actions API based on driver w3c flag
* https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebDriver.html#actions
*/
public getActions() {
- return this.isW3CEnabled ? driver.actions() : driver.actions({ bridge: true });
+ return driver.actions();
}
/**
@@ -164,12 +155,7 @@ export async function BrowserProvider({ getService }: FtrProviderContext) {
*/
public async getCurrentUrl() {
// strip _t=Date query param when url is read
- let current: string;
- if (this.isInternetExplorer) {
- current = await driver.executeScript('return window.document.location.href');
- } else {
- current = await driver.getCurrentUrl();
- }
+ const current = await driver.getCurrentUrl();
const currentWithoutTime = modifyUrl(current, (parsed) => {
delete (parsed.query as any)._t;
return void 0;
@@ -214,15 +200,8 @@ export async function BrowserProvider({ getService }: FtrProviderContext) {
* @return {Promise}
*/
public async moveMouseTo(point: { x: number; y: number }): Promise {
- if (this.isW3CEnabled) {
- await this.getActions().move({ x: 0, y: 0 }).perform();
- await this.getActions().move({ x: point.x, y: point.y, origin: Origin.POINTER }).perform();
- } else {
- await this.getActions()
- .pause(this.getActions().mouse)
- .move({ x: point.x, y: point.y, origin: Origin.POINTER })
- .perform();
- }
+ await this.getActions().move({ x: 0, y: 0 }).perform();
+ await this.getActions().move({ x: point.x, y: point.y, origin: Origin.POINTER }).perform();
}
/**
@@ -237,44 +216,20 @@ export async function BrowserProvider({ getService }: FtrProviderContext) {
from: { offset?: { x: any; y: any }; location: any },
to: { offset?: { x: any; y: any }; location: any }
) {
- if (this.isW3CEnabled) {
- // The offset should be specified in pixels relative to the center of the element's bounding box
- const getW3CPoint = (data: any) => {
- if (!data.offset) {
- data.offset = {};
- }
- return data.location instanceof WebElementWrapper
- ? { x: data.offset.x || 0, y: data.offset.y || 0, origin: data.location._webElement }
- : { x: data.location.x, y: data.location.y, origin: Origin.POINTER };
- };
-
- const startPoint = getW3CPoint(from);
- const endPoint = getW3CPoint(to);
- await this.getActions().move({ x: 0, y: 0 }).perform();
- return await this.getActions().move(startPoint).press().move(endPoint).release().perform();
- } else {
- // The offset should be specified in pixels relative to the top-left corner of the element's bounding box
- const getOffset: any = (offset: { x: number; y: number }) =>
- offset ? { x: offset.x || 0, y: offset.y || 0 } : { x: 0, y: 0 };
-
- if (from.location instanceof WebElementWrapper === false) {
- throw new Error('Dragging point should be WebElementWrapper instance');
- } else if (typeof to.location.x === 'number') {
- return await this.getActions()
- .move({ origin: from.location._webElement })
- .press()
- .move({ x: to.location.x, y: to.location.y, origin: Origin.POINTER })
- .release()
- .perform();
- } else {
- return await new LegacyActionSequence(driver)
- .mouseMove(from.location._webElement, getOffset(from.offset))
- .mouseDown()
- .mouseMove(to.location._webElement, getOffset(to.offset))
- .mouseUp()
- .perform();
+ // The offset should be specified in pixels relative to the center of the element's bounding box
+ const getW3CPoint = (data: any) => {
+ if (!data.offset) {
+ data.offset = {};
}
- }
+ return data.location instanceof WebElementWrapper
+ ? { x: data.offset.x || 0, y: data.offset.y || 0, origin: data.location._webElement }
+ : { x: data.location.x, y: data.location.y, origin: Origin.POINTER };
+ };
+
+ const startPoint = getW3CPoint(from);
+ const endPoint = getW3CPoint(to);
+ await this.getActions().move({ x: 0, y: 0 }).perform();
+ return await this.getActions().move(startPoint).press().move(endPoint).release().perform();
}
/**
@@ -341,19 +296,11 @@ export async function BrowserProvider({ getService }: FtrProviderContext) {
* @return {Promise}
*/
public async clickMouseButton(point: { x: number; y: number }) {
- if (this.isW3CEnabled) {
- await this.getActions().move({ x: 0, y: 0 }).perform();
- await this.getActions()
- .move({ x: point.x, y: point.y, origin: Origin.POINTER })
- .click()
- .perform();
- } else {
- await this.getActions()
- .pause(this.getActions().mouse)
- .move({ x: point.x, y: point.y, origin: Origin.POINTER })
- .click()
- .perform();
- }
+ await this.getActions().move({ x: 0, y: 0 }).perform();
+ await this.getActions()
+ .move({ x: point.x, y: point.y, origin: Origin.POINTER })
+ .click()
+ .perform();
}
/**
diff --git a/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts b/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts
index 281a412653bd0..5011235551bd8 100644
--- a/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts
+++ b/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts
@@ -47,7 +47,6 @@ const RETRY_CLICK_RETRY_ON_ERRORS = [
export class WebElementWrapper {
private By = By;
private Keys = Key;
- public isW3CEnabled: boolean = (this.driver as any).executor_.w3c === true;
public isChromium: boolean = [Browsers.Chrome, Browsers.ChromiumEdge].includes(this.browserType);
public static create(
@@ -141,7 +140,7 @@ export class WebElementWrapper {
}
private getActions() {
- return this.isW3CEnabled ? this.driver.actions() : this.driver.actions({ bridge: true });
+ return this.driver.actions();
}
/**
@@ -233,9 +232,6 @@ export class WebElementWrapper {
* @default { withJS: false }
*/
async clearValue(options: ClearOptions = { withJS: false }) {
- if (this.browserType === Browsers.InternetExplorer) {
- return this.clearValueWithKeyboard();
- }
await this.retryCall(async function clearValue(wrapper) {
if (wrapper.isChromium || options.withJS) {
// https://bugs.chromium.org/p/chromedriver/issues/detail?id=2702
@@ -252,16 +248,6 @@ export class WebElementWrapper {
* @default { charByChar: false }
*/
async clearValueWithKeyboard(options: TypeOptions = { charByChar: false }) {
- if (this.browserType === Browsers.InternetExplorer) {
- const value = await this.getAttribute('value');
- // For IE testing, the text field gets clicked in the middle so
- // first go HOME and then DELETE all chars
- await this.pressKeys(this.Keys.HOME);
- for (let i = 0; i <= value.length; i++) {
- await this.pressKeys(this.Keys.DELETE);
- }
- return;
- }
if (options.charByChar === true) {
const value = await this.getAttribute('value');
for (let i = 0; i <= value.length; i++) {
@@ -429,19 +415,11 @@ export class WebElementWrapper {
public async moveMouseTo(options = { xOffset: 0, yOffset: 0 }) {
await this.retryCall(async function moveMouseTo(wrapper) {
await wrapper.scrollIntoViewIfNecessary();
- if (wrapper.isW3CEnabled) {
- await wrapper.getActions().move({ x: 0, y: 0 }).perform();
- await wrapper
- .getActions()
- .move({ x: options.xOffset, y: options.yOffset, origin: wrapper._webElement })
- .perform();
- } else {
- await wrapper
- .getActions()
- .pause(wrapper.getActions().mouse)
- .move({ x: options.xOffset, y: options.yOffset, origin: wrapper._webElement })
- .perform();
- }
+ await wrapper.getActions().move({ x: 0, y: 0 }).perform();
+ await wrapper
+ .getActions()
+ .move({ x: options.xOffset, y: options.yOffset, origin: wrapper._webElement })
+ .perform();
});
}
@@ -456,21 +434,12 @@ export class WebElementWrapper {
public async clickMouseButton(options = { xOffset: 0, yOffset: 0 }) {
await this.retryCall(async function clickMouseButton(wrapper) {
await wrapper.scrollIntoViewIfNecessary();
- if (wrapper.isW3CEnabled) {
- await wrapper.getActions().move({ x: 0, y: 0 }).perform();
- await wrapper
- .getActions()
- .move({ x: options.xOffset, y: options.yOffset, origin: wrapper._webElement })
- .click()
- .perform();
- } else {
- await wrapper
- .getActions()
- .pause(wrapper.getActions().mouse)
- .move({ x: options.xOffset, y: options.yOffset, origin: wrapper._webElement })
- .click()
- .perform();
- }
+ await wrapper.getActions().move({ x: 0, y: 0 }).perform();
+ await wrapper
+ .getActions()
+ .move({ x: options.xOffset, y: options.yOffset, origin: wrapper._webElement })
+ .click()
+ .perform();
});
}
diff --git a/test/functional/services/remote/browsers.ts b/test/functional/services/remote/browsers.ts
index aa6e364d0a09d..f7942e708a3bb 100644
--- a/test/functional/services/remote/browsers.ts
+++ b/test/functional/services/remote/browsers.ts
@@ -20,6 +20,5 @@
export enum Browsers {
Chrome = 'chrome',
Firefox = 'firefox',
- InternetExplorer = 'ie',
ChromiumEdge = 'msedge',
}
diff --git a/test/functional/services/remote/remote.ts b/test/functional/services/remote/remote.ts
index 99643929c4682..a45403e31095c 100644
--- a/test/functional/services/remote/remote.ts
+++ b/test/functional/services/remote/remote.ts
@@ -64,15 +64,12 @@ export async function RemoteProvider({ getService }: FtrProviderContext) {
};
const { driver, consoleLog$ } = await initWebDriver(log, browserType, lifecycle, browserConfig);
- const isW3CEnabled = (driver as any).executor_.w3c;
-
const caps = await driver.getCapabilities();
- const browserVersion = caps.get(isW3CEnabled ? 'browserVersion' : 'version');
log.info(
- `Remote initialized: ${caps.get(
- 'browserName'
- )} ${browserVersion}, w3c compliance=${isW3CEnabled}, collectingCoverage=${collectCoverage}`
+ `Remote initialized: ${caps.get('browserName')} ${caps.get(
+ 'browserVersion'
+ )}, collectingCoverage=${collectCoverage}`
);
if ([Browsers.Chrome, Browsers.ChromiumEdge].includes(browserType)) {
diff --git a/test/functional/services/remote/webdriver.ts b/test/functional/services/remote/webdriver.ts
index 78f659a064a0c..0611c80f59b92 100644
--- a/test/functional/services/remote/webdriver.ts
+++ b/test/functional/services/remote/webdriver.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { delimiter, resolve } from 'path';
+import { resolve } from 'path';
import Fs from 'fs';
import * as Rx from 'rxjs';
@@ -28,7 +28,7 @@ import { delay } from 'bluebird';
import chromeDriver from 'chromedriver';
// @ts-ignore types not available
import geckoDriver from 'geckodriver';
-import { Builder, Capabilities, logging } from 'selenium-webdriver';
+import { Builder, logging } from 'selenium-webdriver';
import chrome from 'selenium-webdriver/chrome';
import firefox from 'selenium-webdriver/firefox';
import edge from 'selenium-webdriver/edge';
@@ -47,6 +47,7 @@ import { Browsers } from './browsers';
const throttleOption: string = process.env.TEST_THROTTLE_NETWORK as string;
const headlessBrowser: string = process.env.TEST_BROWSER_HEADLESS as string;
+const browserBinaryPath: string = process.env.TEST_BROWSER_BINARY_PATH as string;
const remoteDebug: string = process.env.TEST_REMOTE_DEBUG as string;
const certValidation: string = process.env.NODE_TLS_REJECT_UNAUTHORIZED as string;
const SECOND = 1000;
@@ -54,10 +55,8 @@ const MINUTE = 60 * SECOND;
const NO_QUEUE_COMMANDS = ['getLog', 'getStatus', 'newSession', 'quit'];
const downloadDir = resolve(REPO_ROOT, 'target/functional-tests/downloads');
const chromiumDownloadPrefs = {
- prefs: {
- 'download.default_directory': downloadDir,
- 'download.prompt_for_download': false,
- },
+ 'download.default_directory': downloadDir,
+ 'download.prompt_for_download': false,
};
/**
@@ -93,8 +92,8 @@ async function attemptToCreateCommand(
const buildDriverInstance = async () => {
switch (browserType) {
case 'chrome': {
- const chromeCapabilities = Capabilities.chrome();
- const chromeOptions = [
+ const chromeOptions = new chrome.Options();
+ chromeOptions.addArguments(
// Disables the sandbox for all process types that are normally sandboxed.
'no-sandbox',
// Launches URL in new browser window.
@@ -104,47 +103,55 @@ async function attemptToCreateCommand(
// Use fake device for Media Stream to replace actual camera and microphone.
'use-fake-device-for-media-stream',
// Bypass the media stream infobar by selecting the default device for media streams (e.g. WebRTC). Works with --use-fake-device-for-media-stream.
- 'use-fake-ui-for-media-stream',
- ];
+ 'use-fake-ui-for-media-stream'
+ );
+
if (process.platform === 'linux') {
// The /dev/shm partition is too small in certain VM environments, causing
// Chrome to fail or crash. Use this flag to work-around this issue
// (a temporary directory will always be used to create anonymous shared memory files).
- chromeOptions.push('disable-dev-shm-usage');
+ chromeOptions.addArguments('disable-dev-shm-usage');
}
+
if (headlessBrowser === '1') {
// Use --disable-gpu to avoid an error from a missing Mesa library, as per
// See: https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md
- chromeOptions.push('headless', 'disable-gpu');
+ chromeOptions.headless();
+ chromeOptions.addArguments('disable-gpu');
}
+
if (certValidation === '0') {
- chromeOptions.push('ignore-certificate-errors');
+ chromeOptions.addArguments('ignore-certificate-errors');
}
if (remoteDebug === '1') {
// Visit chrome://inspect in chrome to remotely view/debug
- chromeOptions.push('headless', 'disable-gpu', 'remote-debugging-port=9222');
+ chromeOptions.headless();
+ chromeOptions.addArguments('disable-gpu', 'remote-debugging-port=9222');
+ }
+
+ if (browserBinaryPath) {
+ chromeOptions.setChromeBinaryPath(browserBinaryPath);
}
- chromeCapabilities.set('goog:chromeOptions', {
- w3c: true,
- args: chromeOptions,
- ...chromiumDownloadPrefs,
- });
- chromeCapabilities.set('unexpectedAlertBehaviour', 'accept');
- chromeCapabilities.set('goog:loggingPrefs', { browser: 'ALL' });
- chromeCapabilities.setAcceptInsecureCerts(config.acceptInsecureCerts);
+
+ const prefs = new logging.Preferences();
+ prefs.setLevel(logging.Type.BROWSER, logging.Level.ALL);
+ chromeOptions.setUserPreferences(chromiumDownloadPrefs);
+ chromeOptions.setLoggingPrefs(prefs);
+ chromeOptions.set('unexpectedAlertBehaviour', 'accept');
+ chromeOptions.setAcceptInsecureCerts(config.acceptInsecureCerts);
let session;
if (remoteSessionUrl) {
session = await new Builder()
.forBrowser(browserType)
- .withCapabilities(chromeCapabilities)
+ .setChromeOptions(chromeOptions)
.usingServer(remoteSessionUrl)
.build();
} else {
session = await new Builder()
.forBrowser(browserType)
- .withCapabilities(chromeCapabilities)
+ .setChromeOptions(chromeOptions)
.setChromeService(new chrome.ServiceBuilder(chromeDriver.path).enableVerboseLogging())
.build();
}
@@ -179,7 +186,7 @@ async function attemptToCreateCommand(
edgeOptions.setBinaryPath(edgePaths.browserPath);
const options = edgeOptions.get('ms:edgeOptions');
// overriding options to include preferences
- Object.assign(options, chromiumDownloadPrefs);
+ Object.assign(options, { prefs: chromiumDownloadPrefs });
edgeOptions.set('ms:edgeOptions', options);
const session = await new Builder()
.forBrowser('MicrosoftEdge')
@@ -279,40 +286,6 @@ async function attemptToCreateCommand(
};
}
- case 'ie': {
- // https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/ie_exports_Options.html
- const driverPath = require.resolve('iedriver/lib/iedriver');
- process.env.PATH = driverPath + delimiter + process.env.PATH;
-
- const ieCapabilities = Capabilities.ie();
- ieCapabilities.set('se:ieOptions', {
- 'ie.ensureCleanSession': true,
- ignoreProtectedModeSettings: true,
- ignoreZoomSetting: false, // requires us to have 100% zoom level
- nativeEvents: true, // need this for values to stick but it requires 100% scaling and window focus
- requireWindowFocus: true,
- logLevel: 'TRACE',
- });
-
- let session;
- if (remoteSessionUrl) {
- session = await new Builder()
- .forBrowser(browserType)
- .withCapabilities(ieCapabilities)
- .usingServer(remoteSessionUrl)
- .build();
- } else {
- session = await new Builder()
- .forBrowser(browserType)
- .withCapabilities(ieCapabilities)
- .build();
- }
- return {
- session,
- consoleLog$: Rx.EMPTY,
- };
- }
-
default:
throw new Error(`${browserType} is not supported yet`);
}
diff --git a/test/interpreter_functional/plugins/kbn_tp_run_pipeline/kibana.json b/test/interpreter_functional/plugins/kbn_tp_run_pipeline/kibana.json
index f0c1c3a34fbc0..7eafb185617c4 100644
--- a/test/interpreter_functional/plugins/kbn_tp_run_pipeline/kibana.json
+++ b/test/interpreter_functional/plugins/kbn_tp_run_pipeline/kibana.json
@@ -9,5 +9,8 @@
"expressions"
],
"server": false,
- "ui": true
+ "ui": true,
+ "requiredBundles": [
+ "inspector"
+ ]
}
diff --git a/test/interpreter_functional/plugins/kbn_tp_run_pipeline/package.json b/test/interpreter_functional/plugins/kbn_tp_run_pipeline/package.json
index 535aecba26770..f3e5520a14fe2 100644
--- a/test/interpreter_functional/plugins/kbn_tp_run_pipeline/package.json
+++ b/test/interpreter_functional/plugins/kbn_tp_run_pipeline/package.json
@@ -8,7 +8,7 @@
},
"license": "Apache-2.0",
"dependencies": {
- "@elastic/eui": "24.1.0",
+ "@elastic/eui": "26.3.1",
"react": "^16.12.0",
"react-dom": "^16.12.0"
},
diff --git a/test/plugin_functional/plugins/app_link_test/kibana.json b/test/plugin_functional/plugins/app_link_test/kibana.json
index 8cdc464abfec1..5384d4fee1508 100644
--- a/test/plugin_functional/plugins/app_link_test/kibana.json
+++ b/test/plugin_functional/plugins/app_link_test/kibana.json
@@ -3,5 +3,6 @@
"version": "0.0.1",
"kibanaVersion": "kibana",
"server": false,
- "ui": true
+ "ui": true,
+ "requiredBundles": ["kibanaReact"]
}
diff --git a/test/plugin_functional/plugins/kbn_sample_panel_action/kibana.json b/test/plugin_functional/plugins/kbn_sample_panel_action/kibana.json
index 109afbcd5dabd..08ce182aa0293 100644
--- a/test/plugin_functional/plugins/kbn_sample_panel_action/kibana.json
+++ b/test/plugin_functional/plugins/kbn_sample_panel_action/kibana.json
@@ -5,5 +5,6 @@
"configPath": ["kbn_sample_panel_action"],
"server": false,
"ui": true,
- "requiredPlugins": ["uiActions", "embeddable"]
-}
\ No newline at end of file
+ "requiredPlugins": ["uiActions", "embeddable"],
+ "requiredBundles": ["kibanaReact"]
+}
diff --git a/test/plugin_functional/plugins/kbn_sample_panel_action/package.json b/test/plugin_functional/plugins/kbn_sample_panel_action/package.json
index 612ae3806177c..b9c5b3bc5b836 100644
--- a/test/plugin_functional/plugins/kbn_sample_panel_action/package.json
+++ b/test/plugin_functional/plugins/kbn_sample_panel_action/package.json
@@ -8,7 +8,7 @@
},
"license": "Apache-2.0",
"dependencies": {
- "@elastic/eui": "24.1.0",
+ "@elastic/eui": "26.3.1",
"react": "^16.12.0"
},
"scripts": {
diff --git a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/package.json b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/package.json
index 0a6b5fb185d30..95fafdf221c64 100644
--- a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/package.json
+++ b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/package.json
@@ -8,7 +8,7 @@
},
"license": "Apache-2.0",
"dependencies": {
- "@elastic/eui": "24.1.0",
+ "@elastic/eui": "26.3.1",
"react": "^16.12.0"
},
"scripts": {
diff --git a/test/scripts/jenkins_build_kibana.sh b/test/scripts/jenkins_build_kibana.sh
index 3e49edc8e6ae5..2310a35f94f33 100755
--- a/test/scripts/jenkins_build_kibana.sh
+++ b/test/scripts/jenkins_build_kibana.sh
@@ -2,16 +2,10 @@
source src/dev/ci_setup/setup_env.sh
-echo " -> building examples separate from test plugins"
+echo " -> building kibana platform plugins"
node scripts/build_kibana_platform_plugins \
--oss \
- --examples \
- --verbose;
-
-echo " -> building test plugins"
-node scripts/build_kibana_platform_plugins \
- --oss \
- --no-examples \
+ --filter '!alertingExample' \
--scan-dir "$KIBANA_DIR/test/plugin_functional/plugins" \
--scan-dir "$KIBANA_DIR/test/interpreter_functional/plugins" \
--verbose;
diff --git a/test/scripts/jenkins_xpack_build_kibana.sh b/test/scripts/jenkins_xpack_build_kibana.sh
index 58ef6a42d3fe4..c962b962b1e5e 100755
--- a/test/scripts/jenkins_xpack_build_kibana.sh
+++ b/test/scripts/jenkins_xpack_build_kibana.sh
@@ -3,14 +3,8 @@
cd "$KIBANA_DIR"
source src/dev/ci_setup/setup_env.sh
-echo " -> building examples separate from test plugins"
+echo " -> building kibana platform plugins"
node scripts/build_kibana_platform_plugins \
- --examples \
- --verbose;
-
-echo " -> building test plugins"
-node scripts/build_kibana_platform_plugins \
- --no-examples \
--scan-dir "$KIBANA_DIR/test/plugin_functional/plugins" \
--scan-dir "$XPACK_DIR/test/plugin_functional/plugins" \
--scan-dir "$XPACK_DIR/test/functional_with_es_ssl/fixtures/plugins" \
diff --git a/test/scripts/jenkins_xpack_visual_regression.sh b/test/scripts/jenkins_xpack_visual_regression.sh
index 930d4a74345d9..ac567a188a6d4 100755
--- a/test/scripts/jenkins_xpack_visual_regression.sh
+++ b/test/scripts/jenkins_xpack_visual_regression.sh
@@ -5,7 +5,7 @@ source "$KIBANA_DIR/src/dev/ci_setup/setup_percy.sh"
echo " -> building and extracting default Kibana distributable"
cd "$KIBANA_DIR"
-node scripts/build --debug
+node scripts/build --debug --no-oss
linuxBuild="$(find "$KIBANA_DIR/target" -name 'kibana-*-linux-x86_64.tar.gz')"
installDir="$PARENT_DIR/install/kibana"
mkdir -p "$installDir"
@@ -22,5 +22,5 @@ yarn percy exec -t 10000 -- -- \
# cd "$KIBANA_DIR"
# source "test/scripts/jenkins_xpack_page_load_metrics.sh"
-cd "$XPACK_DIR"
-source "$KIBANA_DIR/test/scripts/jenkins_xpack_saved_objects_field_metrics.sh"
+cd "$KIBANA_DIR"
+source "test/scripts/jenkins_xpack_saved_objects_field_metrics.sh"
diff --git a/x-pack/.gitignore b/x-pack/.gitignore
index 68262c4bf734b..e181caf2b1a49 100644
--- a/x-pack/.gitignore
+++ b/x-pack/.gitignore
@@ -8,7 +8,7 @@
/test/reporting/configs/failure_debug/
/legacy/plugins/reporting/.chromium/
/legacy/plugins/reporting/.phantom/
-/plugins/reporting/.chromium/
+/plugins/reporting/chromium/
/plugins/reporting/.phantom/
/.aws-config.json
/.env
diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json
index 596ba17d343c0..d0055008eb9bf 100644
--- a/x-pack/.i18nrc.json
+++ b/x-pack/.i18nrc.json
@@ -16,6 +16,7 @@
"xpack.data": "plugins/data_enhanced",
"xpack.embeddableEnhanced": "plugins/embeddable_enhanced",
"xpack.endpoint": "plugins/endpoint",
+ "xpack.enterpriseSearch": "plugins/enterprise_search",
"xpack.features": "plugins/features",
"xpack.fileUpload": "plugins/file_upload",
"xpack.globalSearch": ["plugins/global_search"],
diff --git a/x-pack/.telemetryrc.json b/x-pack/.telemetryrc.json
index 4da44667e167f..2c16491c1096b 100644
--- a/x-pack/.telemetryrc.json
+++ b/x-pack/.telemetryrc.json
@@ -7,7 +7,6 @@
"plugins/apm/server/lib/apm_telemetry/index.ts",
"plugins/canvas/server/collectors/collector.ts",
"plugins/infra/server/usage/usage_collector.ts",
- "plugins/ingest_manager/server/collectors/register.ts",
"plugins/lens/server/usage/collectors.ts",
"plugins/reporting/server/usage/reporting_usage_collector.ts",
"plugins/maps/server/maps_telemetry/collectors/register.ts"
diff --git a/x-pack/build_chromium/README.md b/x-pack/build_chromium/README.md
index 72e41afc80c95..ce7e110a5f914 100644
--- a/x-pack/build_chromium/README.md
+++ b/x-pack/build_chromium/README.md
@@ -20,7 +20,8 @@ You'll need access to our GCP account, which is where we have two machines provi
Chromium is built via a build tool called "ninja". The build can be configured by specifying build flags either in an "args.gn" file or via commandline args. We have an "args.gn" file per platform:
- mac: darwin/args.gn
-- linux: linux/args.gn
+- linux 64bit: linux-x64/args.gn
+- ARM 64bit: linux-aarch64/args.gn
- windows: windows/args.gn
The various build flags are not well documented. Some are documented [here](https://www.chromium.org/developers/gn-build-configuration). Some, such as `enable_basic_printing = false`, I only found by poking through 3rd party build scripts.
@@ -65,15 +66,16 @@ Create the build folder:
Copy the `x-pack/build-chromium` folder to each. Replace `you@your-machine` with the correct username and VM name:
-- Mac: `cp -r ~/dev/elastic/kibana/x-pack/build_chromium ~/chromium/build_chromium`
-- Linux: `gcloud compute scp --recurse ~/dev/elastic/kibana/x-pack/build_chromium you@your-machine:~/chromium/build_chromium --zone=us-east1-b`
+- Mac: `cp -r x-pack/build_chromium ~/chromium/build_chromium`
+- Linux: `gcloud compute scp --recurse x-pack/build_chromium you@your-machine:~/chromium/ --zone=us-east1-b --project "XXXXXXXX"`
- Windows: Copy the `build_chromium` folder via the RDP GUI into `c:\chromium\build_chromium`
There is an init script for each platform. This downloads and installs the necessary prerequisites, sets environment variables, etc.
-- Mac: `~/chromium/build_chromium/darwin/init.sh`
-- Linux: `~/chromium/build_chromium/linux/init.sh`
-- Windows `c:\chromium\build_chromium\windows\init.bat`
+- Mac x64: `~/chromium/build_chromium/darwin/init.sh`
+- Linux x64: `~/chromium/build_chromium/linux/init.sh`
+- Linux arm64: `~/chromium/build_chromium/linux/init.sh arm64`
+- Windows x64: `c:\chromium\build_chromium\windows\init.bat`
In windows, at least, you will need to do a number of extra steps:
@@ -102,15 +104,16 @@ Note: In Linux, you should run the build command in tmux so that if your ssh ses
To run the build, replace the sha in the following commands with the sha that you wish to build:
-- Mac: `python ~/chromium/build_chromium/build.py 312d84c8ce62810976feda0d3457108a6dfff9e6`
-- Linux: `python ~/chromium/build_chromium/build.py 312d84c8ce62810976feda0d3457108a6dfff9e6`
-- Windows: `python c:\chromium\build_chromium\build.py 312d84c8ce62810976feda0d3457108a6dfff9e6`
+- Mac x64: `python ~/chromium/build_chromium/build.py 312d84c8ce62810976feda0d3457108a6dfff9e6`
+- Linux x64: `python ~/chromium/build_chromium/build.py 312d84c8ce62810976feda0d3457108a6dfff9e6`
+- Linux arm64: `python ~/chromium/build_chromium/build.py 312d84c8ce62810976feda0d3457108a6dfff9e6 arm64`
+- Windows x64: `python c:\chromium\build_chromium\build.py 312d84c8ce62810976feda0d3457108a6dfff9e6`
## Artifacts
-After the build completes, there will be a .zip file and a .md5 file in `~/chromium/chromium/src/out/headless`. These are named like so: `chromium-{first_7_of_SHA}-{platform}`, for example: `chromium-4747cc2-linux`.
+After the build completes, there will be a .zip file and a .md5 file in `~/chromium/chromium/src/out/headless`. These are named like so: `chromium-{first_7_of_SHA}-{platform}-{arch}`, for example: `chromium-4747cc2-linux-x64`.
-The zip files need to be deployed to s3. For testing, I drop them into `headless-shell-dev`, but for production, they need to be in `headless-shell`. And the `x-pack/plugins/reporting/server/browsers/chromium/paths.ts` file needs to be upated to have the correct `archiveChecksum`, `archiveFilename`, `binaryChecksum` and `baseUrl`. Below is a list of what the archive's are:
+The zip files need to be deployed to GCP Storage. For testing, I drop them into `headless-shell-dev`, but for production, they need to be in `headless-shell`. And the `x-pack/plugins/reporting/server/browsers/chromium/paths.ts` file needs to be upated to have the correct `archiveChecksum`, `archiveFilename`, `binaryChecksum` and `baseUrl`. Below is a list of what the archive's are:
- `archiveChecksum`: The contents of the `.md5` file, which is the `md5` checksum of the zip file.
- `binaryChecksum`: The `md5` checksum of the `headless_shell` binary itself.
@@ -139,8 +142,8 @@ In the case of Windows, you can use IE to open `http://localhost:9221` and see i
The following links provide helpful context about how the Chromium build works, and its prerequisites:
- https://www.chromium.org/developers/how-tos/get-the-code/working-with-release-branches
-- https://chromium.googlesource.com/chromium/src/+/master/docs/windows_build_instructions.md
-- https://chromium.googlesource.com/chromium/src/+/master/docs/mac_build_instructions.md
-- https://chromium.googlesource.com/chromium/src/+/master/docs/linux_build_instructions.md
+- https://chromium.googlesource.com/chromium/src/+/HEAD/docs/windows_build_instructions.md
+- https://chromium.googlesource.com/chromium/src/+/HEAD/docs/mac_build_instructions.md
+- https://chromium.googlesource.com/chromium/src/+/HEAD/docs/linux/build_instructions.md
- Some build-flag descriptions: https://www.chromium.org/developers/gn-build-configuration
- The serverless Chromium project was indispensable: https://github.com/adieuadieu/serverless-chrome/blob/b29445aa5a96d031be2edd5d1fc8651683bf262c/packages/lambda/builds/chromium/build/build.sh
diff --git a/x-pack/build_chromium/build.py b/x-pack/build_chromium/build.py
index 82b0561fdcfe1..52ba325d6f726 100644
--- a/x-pack/build_chromium/build.py
+++ b/x-pack/build_chromium/build.py
@@ -17,7 +17,10 @@
# 4747cc23ae334a57a35ed3c8e6adcdbc8a50d479
source_version = sys.argv[1]
-print('Building Chromium ' + source_version)
+# Set to "arm" to build for ARM on Linux
+arch_name = sys.argv[2] if len(sys.argv) >= 3 else 'x64'
+
+print('Building Chromium ' + source_version + ' for ' + arch_name)
# Set the environment variables required by the build tools
print('Configuring the build environment')
@@ -42,21 +45,29 @@
print('Copying build args: ' + platform_build_args + ' to out/headless/args.gn')
mkdir('out/headless')
shutil.copyfile(platform_build_args, 'out/headless/args.gn')
+
+print('Adding target_cpu to args')
+
+f = open('out/headless/args.gn', 'a')
+f.write('\rtarget_cpu = "' + arch_name + '"')
+f.close()
+
runcmd('gn gen out/headless')
# Build Chromium... this takes *forever* on underpowered VMs
print('Compiling... this will take a while')
runcmd('autoninja -C out/headless headless_shell')
-# Optimize the output on Linux and Mac by stripping inessentials from the binary
-if platform.system() != 'Windows':
+# Optimize the output on Linux x64 and Mac by stripping inessentials from the binary
+# ARM must be cross-compiled from Linux and can not read the ARM binary in order to strip
+if platform.system() != 'Windows' and arch_name != 'arm64':
print('Optimizing headless_shell')
shutil.move('out/headless/headless_shell', 'out/headless/headless_shell_raw')
runcmd('strip -o out/headless/headless_shell out/headless/headless_shell_raw')
# Create the zip and generate the md5 hash using filenames like:
-# chromium-4747cc2-linux.zip
-base_filename = 'out/headless/chromium-' + source_version[:7].strip('.') + '-' + platform.system().lower()
+# chromium-4747cc2-linux_x64.zip
+base_filename = 'out/headless/chromium-' + source_version[:7].strip('.') + '-' + platform.system().lower() + '_' + arch_name
zip_filename = base_filename + '.zip'
md5_filename = base_filename + '.md5'
@@ -66,7 +77,7 @@
def archive_file(name):
"""A little helper function to write individual files to the zip file"""
from_path = os.path.join('out/headless', name)
- to_path = os.path.join('headless_shell-' + platform.system().lower(), name)
+ to_path = os.path.join('headless_shell-' + platform.system().lower() + '_' + arch_name, name)
archive.write(from_path, to_path)
# Each platform has slightly different requirements for what dependencies
@@ -76,6 +87,9 @@ def archive_file(name):
archive_file(os.path.join('swiftshader', 'libEGL.so'))
archive_file(os.path.join('swiftshader', 'libGLESv2.so'))
+ if arch_name == 'arm64':
+ archive_file(os.path.join('swiftshader', 'libEGL.so'))
+
elif platform.system() == 'Windows':
archive_file('headless_shell.exe')
archive_file('dbghelp.dll')
diff --git a/x-pack/build_chromium/init.py b/x-pack/build_chromium/init.py
index a3c5f8dc16fb7..f543922f7653a 100644
--- a/x-pack/build_chromium/init.py
+++ b/x-pack/build_chromium/init.py
@@ -1,4 +1,4 @@
-import os, platform
+import os, platform, sys
from build_util import runcmd, mkdir, md5_file, root_dir, configure_environment
# This is a cross-platform initialization script which should only be run
@@ -29,4 +29,10 @@
# Build Linux deps
if platform.system() == 'Linux':
os.chdir('src')
+
+ if len(sys.argv) >= 2:
+ sysroot_cmd = 'build/linux/sysroot_scripts/install-sysroot.py --arch=' + sys.argv[1]
+ print('Running `' + sysroot_cmd + '`')
+ runcmd(sysroot_cmd)
+
runcmd('build/install-build-deps.sh')
diff --git a/x-pack/build_chromium/linux/init.sh b/x-pack/build_chromium/linux/init.sh
index e259ebded12a1..83cc4a8e5d4d5 100755
--- a/x-pack/build_chromium/linux/init.sh
+++ b/x-pack/build_chromium/linux/init.sh
@@ -10,4 +10,4 @@ fi
# Launch the cross-platform init script using a relative path
# from this script's location.
-python "`dirname "$0"`/../init.py"
+python "`dirname "$0"`/../init.py" $1
diff --git a/x-pack/dev-tools/jest/setup/polyfills.js b/x-pack/dev-tools/jest/setup/polyfills.js
index 822802f3dacb7..a841a3bf9cad0 100644
--- a/x-pack/dev-tools/jest/setup/polyfills.js
+++ b/x-pack/dev-tools/jest/setup/polyfills.js
@@ -21,3 +21,7 @@ require('whatwg-fetch');
if (!global.URL.hasOwnProperty('createObjectURL')) {
Object.defineProperty(global.URL, 'createObjectURL', { value: () => '' });
}
+
+// Will be replaced with a better solution in EUI
+// https://github.com/elastic/eui/issues/3713
+global._isJest = true;
diff --git a/x-pack/examples/ui_actions_enhanced_examples/kibana.json b/x-pack/examples/ui_actions_enhanced_examples/kibana.json
index a1cd895bb3cd6..160352a9afd66 100644
--- a/x-pack/examples/ui_actions_enhanced_examples/kibana.json
+++ b/x-pack/examples/ui_actions_enhanced_examples/kibana.json
@@ -6,5 +6,9 @@
"server": false,
"ui": true,
"requiredPlugins": ["uiActionsEnhanced", "data", "discover"],
- "optionalPlugins": []
+ "optionalPlugins": [],
+ "requiredBundles": [
+ "kibanaUtils",
+ "kibanaReact"
+ ]
}
diff --git a/x-pack/gulpfile.js b/x-pack/gulpfile.js
index 0118d178f54e5..adccaccecd7da 100644
--- a/x-pack/gulpfile.js
+++ b/x-pack/gulpfile.js
@@ -9,13 +9,11 @@ require('../src/setup_node_env');
const { buildTask } = require('./tasks/build');
const { devTask } = require('./tasks/dev');
const { testTask, testKarmaTask, testKarmaDebugTask } = require('./tasks/test');
-const { prepareTask } = require('./tasks/prepare');
// export the tasks that are runnable from the CLI
module.exports = {
build: buildTask,
dev: devTask,
- prepare: prepareTask,
test: testTask,
'test:karma': testKarmaTask,
'test:karma:debug': testKarmaDebugTask,
diff --git a/x-pack/package.json b/x-pack/package.json
index b721cb2fc563a..29264f8920e5d 100644
--- a/x-pack/package.json
+++ b/x-pack/package.json
@@ -196,7 +196,7 @@
"@elastic/apm-rum-react": "^1.1.2",
"@elastic/datemath": "5.0.3",
"@elastic/ems-client": "7.9.3",
- "@elastic/eui": "24.1.0",
+ "@elastic/eui": "26.3.1",
"@elastic/filesaver": "1.1.2",
"@elastic/maki": "6.3.0",
"@elastic/node-crypto": "1.2.1",
diff --git a/x-pack/plugins/actions/README.md b/x-pack/plugins/actions/README.md
index 494f2f38e8bff..9e07727204f88 100644
--- a/x-pack/plugins/actions/README.md
+++ b/x-pack/plugins/actions/README.md
@@ -26,15 +26,19 @@ Table of Contents
- [Executor](#executor)
- [Example](#example)
- [RESTful API](#restful-api)
- - [`POST /api/actions/action`: Create action](#post-apiaction-create-action)
- - [`DELETE /api/actions/action/{id}`: Delete action](#delete-apiactionid-delete-action)
- - [`GET /api/actions`: Get all actions](#get-apiactiongetall-get-all-actions)
- - [`GET /api/actions/action/{id}`: Get action](#get-apiactionid-get-action)
- - [`GET /api/actions/list_action_types`: List action types](#get-apiactiontypes-list-action-types)
- - [`PUT /api/actions/action/{id}`: Update action](#put-apiactionid-update-action)
- - [`POST /api/actions/action/{id}/_execute`: Execute action](#post-apiactionidexecute-execute-action)
+ - [`POST /api/actions/action`: Create action](#post-apiactionsaction-create-action)
+ - [`DELETE /api/actions/action/{id}`: Delete action](#delete-apiactionsactionid-delete-action)
+ - [`GET /api/actions`: Get all actions](#get-apiactions-get-all-actions)
+ - [`GET /api/actions/action/{id}`: Get action](#get-apiactionsactionid-get-action)
+ - [`GET /api/actions/list_action_types`: List action types](#get-apiactionslist_action_types-list-action-types)
+ - [`PUT /api/actions/action/{id}`: Update action](#put-apiactionsactionid-update-action)
+ - [`POST /api/actions/action/{id}/_execute`: Execute action](#post-apiactionsactionid_execute-execute-action)
- [Firing actions](#firing-actions)
+ - [Accessing a scoped ActionsClient](#accessing-a-scoped-actionsclient)
+ - [actionsClient.enqueueExecution(options)](#actionsclientenqueueexecutionoptions)
- [Example](#example-1)
+ - [actionsClient.execute(options)](#actionsclientexecuteoptions)
+ - [Example](#example-2)
- [Built-in Action Types](#built-in-action-types)
- [Server log](#server-log)
- [`config`](#config)
@@ -70,6 +74,11 @@ Table of Contents
- [`secrets`](#secrets-7)
- [`params`](#params-7)
- [`subActionParams (pushToService)`](#subactionparams-pushtoservice-1)
+ - [IBM Resilient](#ibm-resilient)
+ - [`config`](#config-8)
+ - [`secrets`](#secrets-8)
+ - [`params`](#params-8)
+ - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-2)
- [Command Line Utility](#command-line-utility)
- [Developing New Action Types](#developing-new-action-types)
@@ -99,7 +108,7 @@ Built-In-Actions are configured using the _xpack.actions_ namespoace under _kiba
| _xpack.actions._**enabled** | Feature toggle which enabled Actions in Kibana. | boolean |
| _xpack.actions._**whitelistedHosts** | Which _hostnames_ are whitelisted for the Built-In-Action? This list should contain hostnames of every external service you wish to interact with using Webhooks, Email or any other built in Action. Note that you may use the string "\*" in place of a specific hostname to enable Kibana to target any URL, but keep in mind the potential use of such a feature to execute [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) attacks from your server. | Array |
| _xpack.actions._**enabledActionTypes** | A list of _actionTypes_ id's that are enabled. A "\*" may be used as an element to indicate all registered actionTypes should be enabled. The actionTypes registered for Kibana are `.server-log`, `.slack`, `.email`, `.index`, `.pagerduty`, `.webhook`. Default: `["*"]` | Array |
-| _xpack.actions._**preconfigured** | A object of action id / preconfigured actions. Default: `{}` | Array