diff --git a/.eslintrc.js b/.eslintrc.js index a07d0830907b6..ff4ac180c3774 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -296,10 +296,7 @@ module.exports = { errorMessage: `Plugins may only import from src/core/server and src/core/public.`, }, { - target: [ - '(src|x-pack)/plugins/*/server/**/*', - '!x-pack/plugins/apm/**/*', // https://github.com/elastic/kibana/issues/67210 - ], + target: ['(src|x-pack)/plugins/*/server/**/*'], from: ['(src|x-pack)/plugins/*/public/**/*'], errorMessage: `Server code can not import from public, use a common directory.`, }, diff --git a/docs/api/using-api.asciidoc b/docs/api/using-api.asciidoc index c61edfb62b079..c796aac3d6b27 100644 --- a/docs/api/using-api.asciidoc +++ b/docs/api/using-api.asciidoc @@ -61,10 +61,8 @@ For all APIs, you must use a request header. The {kib} APIs support the `kbn-xsr By default, you must use `kbn-xsrf` for all API calls, except in the following scenarios: * The API endpoint uses the `GET` or `HEAD` operations - -* The path is whitelisted using the <> setting - -* XSRF protections are disabled using the `server.xsrf.disableProtection` setting +* The path is whitelisted using the <> setting +* XSRF protections are disabled using the <> setting `Content-Type: application/json`:: Applicable only when you send a payload in the API request. {kib} API requests and responses use JSON. diff --git a/docs/apm/api.asciidoc b/docs/apm/api.asciidoc index 97fdcd3e13de9..01ba084b9e9e7 100644 --- a/docs/apm/api.asciidoc +++ b/docs/apm/api.asciidoc @@ -40,8 +40,8 @@ users interacting with APM APIs must have <> setting -* XSRF protections are disabled using the `server.xsrf.disableProtection` setting +* The path is whitelisted using the <> setting +* XSRF protections are disabled using the <> setting `Content-Type: application/json`:: Applicable only when you send a payload in the API request. diff --git a/docs/developer/getting-started/index.asciidoc b/docs/developer/getting-started/index.asciidoc index 10e603a8da8bb..9b334a55c4203 100644 --- a/docs/developer/getting-started/index.asciidoc +++ b/docs/developer/getting-started/index.asciidoc @@ -30,7 +30,7 @@ you can switch to the correct version when using nvm by running: nvm use ---- -Install the latest version of https://yarnpkg.com[yarn]. +Install the latest version of https://classic.yarnpkg.com/en/docs/install[yarn v1]. Bootstrap {kib} and install all the dependencies: diff --git a/docs/developer/plugin/external-plugin-functional-tests.asciidoc b/docs/developer/plugin/external-plugin-functional-tests.asciidoc index 706bf6af8ed9b..7e5b5b79d06e9 100644 --- a/docs/developer/plugin/external-plugin-functional-tests.asciidoc +++ b/docs/developer/plugin/external-plugin-functional-tests.asciidoc @@ -13,7 +13,7 @@ To get started copy and paste this example to `test/functional/config.js`: ["source","js"] ----------- import { resolve } from 'path'; -import { resolveKibanaPath } from '@kbn/plugin-helpers'; +import { REPO_ROOT } from '@kbn/dev-utils'; import { MyServiceProvider } from './services/my_service'; import { MyAppPageProvider } from './services/my_app_page'; @@ -24,7 +24,7 @@ export default async function ({ readConfigFile }) { // read the {kib} config file so that we can utilize some of // its services and PageObjects - const kibanaConfig = await readConfigFile(resolveKibanaPath('test/functional/config.js')); + const kibanaConfig = await readConfigFile(resolve(REPO_ROOT, 'test/functional/config.js')); return { // list paths to the files that contain your plugins tests diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.action_global_apply_filter.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.action_global_apply_filter.md new file mode 100644 index 0000000000000..14075ba1beba0 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.action_global_apply_filter.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [ACTION\_GLOBAL\_APPLY\_FILTER](./kibana-plugin-plugins-data-public.action_global_apply_filter.md) + +## ACTION\_GLOBAL\_APPLY\_FILTER variable + +Signature: + +```typescript +ACTION_GLOBAL_APPLY_FILTER = "ACTION_GLOBAL_APPLY_FILTER" +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldlist._constructor_.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldlist._constructor_.md index 3b60ac0f48edd..9f9613a5a68f7 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldlist._constructor_.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldlist._constructor_.md @@ -9,7 +9,7 @@ Constructs a new instance of the `FieldList` class Signature: ```typescript -constructor(indexPattern: IndexPattern, specs?: FieldSpec[], shortDotsEnable?: boolean, onNotification?: () => void); +constructor(indexPattern: IndexPattern, specs?: FieldSpec[], shortDotsEnable?: boolean, onNotification?: OnNotification); ``` ## Parameters @@ -19,5 +19,5 @@ constructor(indexPattern: IndexPattern, specs?: FieldSpec[], shortDotsEnable?: b | indexPattern | IndexPattern | | | specs | FieldSpec[] | | | shortDotsEnable | boolean | | -| onNotification | () => void | | +| onNotification | OnNotification | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.intervalname.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.intervalname.md new file mode 100644 index 0000000000000..762b4a37bfd28 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.intervalname.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPattern](./kibana-plugin-plugins-data-public.indexpattern.md) > [intervalName](./kibana-plugin-plugins-data-public.indexpattern.intervalname.md) + +## IndexPattern.intervalName property + +Signature: + +```typescript +intervalName: string | undefined; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md index 649f8ef077e3f..c15cb3358f689 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md @@ -27,9 +27,12 @@ export declare class IndexPattern implements IIndexPattern | [formatField](./kibana-plugin-plugins-data-public.indexpattern.formatfield.md) | | any | | | [formatHit](./kibana-plugin-plugins-data-public.indexpattern.formathit.md) | | any | | | [id](./kibana-plugin-plugins-data-public.indexpattern.id.md) | | string | | +| [intervalName](./kibana-plugin-plugins-data-public.indexpattern.intervalname.md) | | string | undefined | | | [metaFields](./kibana-plugin-plugins-data-public.indexpattern.metafields.md) | | string[] | | +| [sourceFilters](./kibana-plugin-plugins-data-public.indexpattern.sourcefilters.md) | | SourceFilter[] | | | [timeFieldName](./kibana-plugin-plugins-data-public.indexpattern.timefieldname.md) | | string | undefined | | | [title](./kibana-plugin-plugins-data-public.indexpattern.title.md) | | string | | +| [type](./kibana-plugin-plugins-data-public.indexpattern.type.md) | | string | undefined | | | [typeMeta](./kibana-plugin-plugins-data-public.indexpattern.typemeta.md) | | TypeMeta | | ## Methods diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.prepbody.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.prepbody.md index 5c9f017b571da..1d77b2a55860e 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.prepbody.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.prepbody.md @@ -8,12 +8,26 @@ ```typescript prepBody(): { - [key: string]: any; + title: string; + timeFieldName: string | undefined; + intervalName: string | undefined; + sourceFilters: string | undefined; + fields: string | undefined; + fieldFormatMap: string | undefined; + type: string | undefined; + typeMeta: string | undefined; }; ``` Returns: `{ - [key: string]: any; + title: string; + timeFieldName: string | undefined; + intervalName: string | undefined; + sourceFilters: string | undefined; + fields: string | undefined; + fieldFormatMap: string | undefined; + type: string | undefined; + typeMeta: string | undefined; }` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.sourcefilters.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.sourcefilters.md new file mode 100644 index 0000000000000..10ccf8e137627 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.sourcefilters.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPattern](./kibana-plugin-plugins-data-public.indexpattern.md) > [sourceFilters](./kibana-plugin-plugins-data-public.indexpattern.sourcefilters.md) + +## IndexPattern.sourceFilters property + +Signature: + +```typescript +sourceFilters?: SourceFilter[]; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.type.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.type.md new file mode 100644 index 0000000000000..7a10d058b9c65 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.type.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPattern](./kibana-plugin-plugins-data-public.indexpattern.md) > [type](./kibana-plugin-plugins-data-public.indexpattern.type.md) + +## IndexPattern.type property + +Signature: + +```typescript +type: string | undefined; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md index a5453c7c51d5b..09702df4fdb54 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md @@ -89,6 +89,7 @@ | Variable | Description | | --- | --- | +| [ACTION\_GLOBAL\_APPLY\_FILTER](./kibana-plugin-plugins-data-public.action_global_apply_filter.md) | | | [AggGroupLabels](./kibana-plugin-plugins-data-public.agggrouplabels.md) | | | [AggGroupNames](./kibana-plugin-plugins-data-public.agggroupnames.md) | | | [baseFormattersPublic](./kibana-plugin-plugins-data-public.baseformatterspublic.md) | | diff --git a/docs/settings/monitoring-settings.asciidoc b/docs/settings/monitoring-settings.asciidoc index 5b8fa0725d96b..d538519eefcc4 100644 --- a/docs/settings/monitoring-settings.asciidoc +++ b/docs/settings/monitoring-settings.asciidoc @@ -5,12 +5,12 @@ Monitoring settings ++++ -By default, the Monitoring application is enabled, but data collection -is disabled. When you first start {kib} monitoring, you are prompted to -enable data collection. If you are using {stack-security-features}, you must be -signed in as a user with the `cluster:manage` privilege to enable -data collection. The built-in `superuser` role has this privilege and the -built-in `elastic` user has this role. +By default, *{stack-monitor-app}* is enabled, but data collection is disabled. +When you first start {kib} monitoring, you are prompted to enable data +collection. If you are using {stack-security-features}, you must be signed in as +a user with the `cluster:manage` privilege to enable data collection. The +built-in `superuser` role has this privilege and the built-in `elastic` user has +this role. You can adjust how monitoring data is collected from {kib} and displayed in {kib} by configuring settings in the @@ -49,7 +49,7 @@ For more information, see in {kib} to the {es} monitoring cluster and to verify licensing status on the {es} monitoring cluster. + + - Every other request performed by the Stack Monitoring UI to the monitoring {es} + Every other request performed by *{stack-monitor-app}* to the monitoring {es} cluster uses the authenticated user's credentials, which must be the same on both the {es} monitoring cluster and the {es} production cluster. + + @@ -60,7 +60,7 @@ For more information, see in {kib} to the {es} monitoring cluster and to verify licensing status on the {es} monitoring cluster. + + - Every other request performed by the Stack Monitoring UI to the monitoring {es} + Every other request performed by *{stack-monitor-app}* to the monitoring {es} cluster uses the authenticated user's credentials, which must be the same on both the {es} monitoring cluster and the {es} production cluster. + + @@ -83,7 +83,7 @@ These settings control how data is collected from {kib}. |=== | `monitoring.kibana.collection.enabled` | Set to `true` (default) to enable data collection from the {kib} NodeJS server - for {kib} Dashboards to be featured in the Monitoring. + for {kib} dashboards to be featured in *{stack-monitor-app}*. | `monitoring.kibana.collection.interval` | Specifies the number of milliseconds to wait in between data sampling on the @@ -96,16 +96,26 @@ These settings control how data is collected from {kib}. [[monitoring-ui-settings]] ==== Monitoring UI settings -These settings adjust how the {kib} Monitoring page displays monitoring data. +These settings adjust how *{stack-monitor-app}* displays monitoring data. However, the defaults work best in most circumstances. For more information about configuring {kib}, see -{kibana-ref}/settings.html[Setting Kibana Server Properties]. +{kibana-ref}/settings.html[Setting {kib} server properties]. [cols="2*<"] |=== | `monitoring.ui.elasticsearch.logFetchCount` - | Specifies the number of log entries to display in the Monitoring UI. Defaults to - `10`. The maximum value is `50`. + | Specifies the number of log entries to display in *{stack-monitor-app}*. + Defaults to `10`. The maximum value is `50`. + +| `monitoring.ui.enabled` + | Set to `false` to hide *{stack-monitor-app}*. The monitoring back-end + continues to run as an agent for sending {kib} stats to the monitoring + cluster. Defaults to `true`. + +| `monitoring.ui.logs.index` + | Specifies the name of the indices that are shown on the + <> page in *{stack-monitor-app}*. The default value + is `filebeat-*`. | `monitoring.ui.max_bucket_size` | Specifies the number of term buckets to return out of the overall terms list when @@ -120,18 +130,13 @@ about configuring {kib}, see `monitoring.ui.collection.interval` in `elasticsearch.yml`, use the same value in this setting. -| `monitoring.ui.enabled` - | Set to `false` to hide the Monitoring UI in {kib}. The monitoring back-end - continues to run as an agent for sending {kib} stats to the monitoring - cluster. Defaults to `true`. - |=== [float] [[monitoring-ui-cgroup-settings]] ===== Monitoring UI container settings -The Monitoring UI exposes the Cgroup statistics that we collect for you to make +*{stack-monitor-app}* exposes the Cgroup statistics that we collect for you to make better decisions about your container performance, rather than guessing based on the overall machine performance. If you are not running your applications in a container, then Cgroup statistics are not useful. diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index 018cc656362b8..4a931aabd3646 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -577,7 +577,7 @@ all http requests to https over the port configured as `server.port`. | An array of supported protocols with versions. Valid protocols: `TLSv1`, `TLSv1.1`, `TLSv1.2`. *Default: TLSv1.1, TLSv1.2* -| `server.xsrf.whitelist:` +| [[settings-xsrf-whitelist]] `server.xsrf.whitelist:` | It is not recommended to disable protections for arbitrary API endpoints. Instead, supply the `kbn-xsrf` header. The `server.xsrf.whitelist` setting requires the following format: @@ -592,6 +592,9 @@ The `server.xsrf.whitelist` setting requires the following format: [cols="2*<"] |=== +| [[settings-xsrf-disableProtection]] `server.xsrf.disableProtection:` + | Setting this to `true` will completely disable Cross-site request forgery protection in Kibana. This is not recommended. *Default: `false`* + | `status.allowAnonymous:` | If authentication is enabled, setting this to `true` enables unauthenticated users to access the {kib} diff --git a/examples/embeddable_examples/public/book/book_embeddable.tsx b/examples/embeddable_examples/public/book/book_embeddable.tsx index 33876ab24414e..b033fe86cd1c7 100644 --- a/examples/embeddable_examples/public/book/book_embeddable.tsx +++ b/examples/embeddable_examples/public/book/book_embeddable.tsx @@ -60,7 +60,8 @@ function getHasMatch(search?: string, savedAttributes?: BookSavedObjectAttribute ); } -export class BookEmbeddable extends Embeddable +export class BookEmbeddable + extends Embeddable implements ReferenceOrValueEmbeddable { public readonly type = BOOK_EMBEDDABLE; private subscription: Subscription; diff --git a/package.json b/package.json index 1bf6e8b977af8..b8cf2e1e27774 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "**/@types/chai": "^4.2.11", "**/cypress/@types/lodash": "^4.14.159", "**/cypress/lodash": "^4.17.20", - "**/typescript": "3.9.5", + "**/typescript": "4.0.2", "**/graphql-toolkit/lodash": "^4.17.15", "**/hoist-non-react-statics": "^3.3.2", "**/isomorphic-git/**/base64-js": "^1.2.1", @@ -338,8 +338,8 @@ "@types/vinyl": "^2.0.4", "@types/vinyl-fs": "^2.4.11", "@types/zen-observable": "^0.8.0", - "@typescript-eslint/eslint-plugin": "^3.7.1", - "@typescript-eslint/parser": "^3.7.1", + "@typescript-eslint/eslint-plugin": "^3.10.0", + "@typescript-eslint/parser": "^3.10.0", "angular-aria": "^1.8.0", "angular-mocks": "^1.7.9", "angular-recursion": "^1.0.5", @@ -381,7 +381,7 @@ "eslint-plugin-no-unsanitized": "^3.0.2", "eslint-plugin-node": "^11.0.0", "eslint-plugin-prefer-object-spread": "^1.2.1", - "eslint-plugin-prettier": "^3.1.3", + "eslint-plugin-prettier": "^3.1.4", "eslint-plugin-react": "^7.20.3", "eslint-plugin-react-hooks": "^4.0.4", "eslint-plugin-react-perf": "^3.2.3", @@ -443,7 +443,7 @@ "pkg-up": "^2.0.0", "pngjs": "^3.4.0", "postcss": "^7.0.32", - "prettier": "^2.0.5", + "prettier": "^2.1.1", "prop-types": "15.6.0", "proxyquire": "1.8.0", "react-grid-layout": "^0.16.2", @@ -469,7 +469,7 @@ "tape": "^4.13.0", "topojson-client": "3.0.0", "tree-kill": "^1.2.2", - "typescript": "3.9.5", + "typescript": "4.0.2", "typings-tester": "^0.3.2", "ui-select": "0.19.8", "vega": "^5.13.0", diff --git a/packages/eslint-config-kibana/package.json b/packages/eslint-config-kibana/package.json index 618f71daf0339..4ec3bcdfd7c05 100644 --- a/packages/eslint-config-kibana/package.json +++ b/packages/eslint-config-kibana/package.json @@ -15,8 +15,8 @@ }, "homepage": "https://github.com/elastic/kibana/tree/master/packages/eslint-config-kibana", "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^3.7.1", - "@typescript-eslint/parser": "^3.7.1", + "@typescript-eslint/eslint-plugin": "^3.10.0", + "@typescript-eslint/parser": "^3.10.0", "babel-eslint": "^10.0.3", "eslint": "^6.8.0", "eslint-plugin-babel": "^5.3.0", diff --git a/packages/kbn-analytics/package.json b/packages/kbn-analytics/package.json index 873252ceb0a1a..b04b5b32d0746 100644 --- a/packages/kbn-analytics/package.json +++ b/packages/kbn-analytics/package.json @@ -17,6 +17,6 @@ "@babel/cli": "^7.10.5", "@kbn/dev-utils": "1.0.0", "@kbn/babel-preset": "1.0.0", - "typescript": "3.9.5" + "typescript": "4.0.2" } } diff --git a/packages/kbn-config-schema/package.json b/packages/kbn-config-schema/package.json index 10b607dcd4312..10b1741d98441 100644 --- a/packages/kbn-config-schema/package.json +++ b/packages/kbn-config-schema/package.json @@ -10,7 +10,7 @@ "kbn:bootstrap": "yarn build" }, "devDependencies": { - "typescript": "3.9.5", + "typescript": "4.0.2", "tsd": "^0.7.4" }, "peerDependencies": { diff --git a/packages/kbn-dev-utils/package.json b/packages/kbn-dev-utils/package.json index 7ce433f80bed0..4f6f995f38f31 100644 --- a/packages/kbn-dev-utils/package.json +++ b/packages/kbn-dev-utils/package.json @@ -1,32 +1,38 @@ { "name": "@kbn/dev-utils", - "main": "./target/index.js", "version": "1.0.0", - "license": "Apache-2.0", "private": true, + "license": "Apache-2.0", + "main": "./target/index.js", "scripts": { "build": "tsc", "kbn:bootstrap": "yarn build", "kbn:watch": "yarn build --watch" }, "dependencies": { + "@babel/core": "^7.11.1", "axios": "^0.19.0", "chalk": "^4.1.0", + "cheerio": "0.22.0", "dedent": "^0.7.0", "execa": "^4.0.2", "exit-hook": "^2.2.0", "getopts": "^2.2.5", + "globby": "^8.0.1", "load-json-file": "^6.2.0", - "normalize-path": "^3.0.0", + "markdown-it": "^10.0.0", "moment": "^2.24.0", + "normalize-path": "^3.0.0", "rxjs": "^6.5.5", "strip-ansi": "^6.0.0", "tree-kill": "^1.2.2", - "tslib": "^2.0.0" + "vinyl": "^2.2.0" }, "devDependencies": { - "typescript": "3.9.5", + "@kbn/babel-preset": "1.0.0", "@kbn/expect": "1.0.0", - "chance": "1.0.18" + "@types/vinyl": "^2.0.4", + "chance": "1.0.18", + "typescript": "4.0.2" } } diff --git a/packages/kbn-dev-utils/src/babel.ts b/packages/kbn-dev-utils/src/babel.ts new file mode 100644 index 0000000000000..e48fe81d0232c --- /dev/null +++ b/packages/kbn-dev-utils/src/babel.ts @@ -0,0 +1,59 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import File from 'vinyl'; +import * as Babel from '@babel/core'; + +const transformedFiles = new WeakSet(); + +/** + * Returns a promise that resolves when the file has been + * mutated so the contents of the file are tranformed with + * babel, include inline sourcemaps, and the filename has + * been updated to use .js. + * + * If the file was previously transformed with this function + * the promise will just resolve immediately. + */ +export async function transformFileWithBabel(file: File) { + if (!(file.contents instanceof Buffer)) { + throw new Error('file must be buffered'); + } + + if (transformedFiles.has(file)) { + return; + } + + const source = file.contents.toString('utf8'); + const result = await Babel.transformAsync(source, { + babelrc: false, + configFile: false, + sourceMaps: 'inline', + filename: file.path, + presets: [require.resolve('@kbn/babel-preset/node_preset')], + }); + + if (!result || typeof result.code !== 'string') { + throw new Error('babel transformation failed without an error...'); + } + + file.contents = Buffer.from(result.code); + file.extname = '.js'; + transformedFiles.add(file); +} diff --git a/packages/kbn-dev-utils/src/index.ts b/packages/kbn-dev-utils/src/index.ts index 798746d159f60..2871fe2ffcf4a 100644 --- a/packages/kbn-dev-utils/src/index.ts +++ b/packages/kbn-dev-utils/src/index.ts @@ -41,3 +41,6 @@ export * from './stdio'; export * from './ci_stats_reporter'; export * from './plugin_list'; export * from './simple_kibana_platform_plugin_discovery'; +export * from './streams'; +export * from './babel'; +export * from './parse_kibana_platform_plugin'; diff --git a/packages/kbn-dev-utils/src/parse_kibana_platform_plugin.ts b/packages/kbn-dev-utils/src/parse_kibana_platform_plugin.ts new file mode 100644 index 0000000000000..83d8c2684d7ca --- /dev/null +++ b/packages/kbn-dev-utils/src/parse_kibana_platform_plugin.ts @@ -0,0 +1,59 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import Path from 'path'; +import loadJsonFile from 'load-json-file'; + +export interface KibanaPlatformPlugin { + readonly directory: string; + readonly manifestPath: string; + readonly manifest: { + id: string; + ui: boolean; + server: boolean; + [key: string]: unknown; + }; +} + +export function parseKibanaPlatformPlugin(manifestPath: string): KibanaPlatformPlugin { + if (!Path.isAbsolute(manifestPath)) { + throw new TypeError('expected new platform manifest path to be absolute'); + } + + const manifest = loadJsonFile.sync(manifestPath); + if (!manifest || typeof manifest !== 'object' || Array.isArray(manifest)) { + throw new TypeError('expected new platform plugin manifest to be a JSON encoded object'); + } + + if (typeof manifest.id !== 'string') { + throw new TypeError('expected new platform plugin manifest to have a string id'); + } + + return { + directory: Path.dirname(manifestPath), + manifestPath, + manifest: { + ...manifest, + + ui: !!manifest.ui, + server: !!manifest.server, + id: manifest.id, + }, + }; +} diff --git a/packages/kbn-dev-utils/src/run/flags.ts b/packages/kbn-dev-utils/src/run/flags.ts index 12642bceca15a..54758b4a7dbf8 100644 --- a/packages/kbn-dev-utils/src/run/flags.ts +++ b/packages/kbn-dev-utils/src/run/flags.ts @@ -52,8 +52,8 @@ export function mergeFlagOptions(global: FlagOptions = {}, local: FlagOptions = boolean: [...(global.boolean || []), ...(local.boolean || [])], string: [...(global.string || []), ...(local.string || [])], default: { - ...global.alias, - ...local.alias, + ...global.default, + ...local.default, }, help: local.help, diff --git a/packages/kbn-dev-utils/src/serializers/index.ts b/packages/kbn-dev-utils/src/serializers/index.ts index e645a3be3fe5d..6e0ac0b8be029 100644 --- a/packages/kbn-dev-utils/src/serializers/index.ts +++ b/packages/kbn-dev-utils/src/serializers/index.ts @@ -21,3 +21,4 @@ export * from './absolute_path_serializer'; export * from './strip_ansi_serializer'; export * from './recursive_serializer'; export * from './any_instance_serizlizer'; +export * from './replace_serializer'; diff --git a/packages/kbn-dev-utils/src/serializers/replace_serializer.ts b/packages/kbn-dev-utils/src/serializers/replace_serializer.ts new file mode 100644 index 0000000000000..06096c4bee3a2 --- /dev/null +++ b/packages/kbn-dev-utils/src/serializers/replace_serializer.ts @@ -0,0 +1,36 @@ +/* + * 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 { createRecursiveSerializer } from './recursive_serializer'; + +type Replacer = (substring: string, ...args: any[]) => string; + +export function createReplaceSerializer( + toReplace: string | RegExp, + replaceWith: string | Replacer +) { + return createRecursiveSerializer( + typeof toReplace === 'string' + ? (v: any) => typeof v === 'string' && v.includes(toReplace) + : (v: any) => typeof v === 'string' && toReplace.test(v), + typeof replaceWith === 'string' + ? (v: string) => v.replace(toReplace, replaceWith) + : (v: string) => v.replace(toReplace, replaceWith) + ); +} diff --git a/packages/kbn-dev-utils/src/simple_kibana_platform_plugin_discovery.ts b/packages/kbn-dev-utils/src/simple_kibana_platform_plugin_discovery.ts index c7155b2b3c51b..c56d63edb9ac4 100644 --- a/packages/kbn-dev-utils/src/simple_kibana_platform_plugin_discovery.ts +++ b/packages/kbn-dev-utils/src/simple_kibana_platform_plugin_discovery.ts @@ -20,67 +20,37 @@ import Path from 'path'; import globby from 'globby'; -import loadJsonFile from 'load-json-file'; -export interface KibanaPlatformPlugin { - readonly directory: string; - readonly manifestPath: string; - readonly manifest: { - id: string; - [key: string]: unknown; - }; -} +import { parseKibanaPlatformPlugin } from './parse_kibana_platform_plugin'; /** * Helper to find the new platform plugins. */ -export function simpleKibanaPlatformPluginDiscovery(scanDirs: string[], paths: string[]) { +export function simpleKibanaPlatformPluginDiscovery(scanDirs: string[], pluginPaths: string[]) { const patterns = Array.from( new Set([ // find kibana.json files up to 5 levels within the scan dir ...scanDirs.reduce( (acc: string[], dir) => [ ...acc, - `${dir}/*/kibana.json`, - `${dir}/*/*/kibana.json`, - `${dir}/*/*/*/kibana.json`, - `${dir}/*/*/*/*/kibana.json`, - `${dir}/*/*/*/*/*/kibana.json`, + Path.resolve(dir, '*/kibana.json'), + Path.resolve(dir, '*/*/kibana.json'), + Path.resolve(dir, '*/*/*/kibana.json'), + Path.resolve(dir, '*/*/*/*/kibana.json'), + Path.resolve(dir, '*/*/*/*/*/kibana.json'), ], [] ), - ...paths.map((path) => `${path}/kibana.json`), + ...pluginPaths.map((path) => Path.resolve(path, `kibana.json`)), ]) ); const manifestPaths = globby.sync(patterns, { absolute: true }).map((path) => - // absolute paths returned from globby are using normalize or something so the path separators are `/` even on windows, Path.resolve solves this + // absolute paths returned from globby are using normalize or + // something so the path separators are `/` even on windows, + // Path.resolve solves this Path.resolve(path) ); - return manifestPaths.map( - (manifestPath): KibanaPlatformPlugin => { - if (!Path.isAbsolute(manifestPath)) { - throw new TypeError('expected new platform manifest path to be absolute'); - } - - const manifest = loadJsonFile.sync(manifestPath); - if (!manifest || typeof manifest !== 'object' || Array.isArray(manifest)) { - throw new TypeError('expected new platform plugin manifest to be a JSON encoded object'); - } - - if (typeof manifest.id !== 'string') { - throw new TypeError('expected new platform plugin manifest to have a string id'); - } - - return { - directory: Path.dirname(manifestPath), - manifestPath, - manifest: { - ...manifest, - id: manifest.id, - }, - }; - } - ); + return manifestPaths.map(parseKibanaPlatformPlugin); } diff --git a/packages/kbn-plugin-generator/src/streams.ts b/packages/kbn-dev-utils/src/streams.ts similarity index 62% rename from packages/kbn-plugin-generator/src/streams.ts rename to packages/kbn-dev-utils/src/streams.ts index 976008e879dd3..6a868f648e78d 100644 --- a/packages/kbn-plugin-generator/src/streams.ts +++ b/packages/kbn-dev-utils/src/streams.ts @@ -20,7 +20,6 @@ import { Transform } from 'stream'; import File from 'vinyl'; -import { Minimatch } from 'minimatch'; interface BufferedFile extends File { contents: Buffer; @@ -33,41 +32,31 @@ interface BufferedFile extends File { * mutate the file, replace it with another file (return a new File * object), or drop it from the stream (return null) */ -export const tapFileStream = ( +export const transformFileStream = ( fn: (file: BufferedFile) => File | void | null | Promise ) => new Transform({ objectMode: true, - transform(file: BufferedFile, _, cb) { - Promise.resolve(file) - .then(fn) - .then( - (result) => { - // drop the file when null is returned - if (result === null) { - cb(); - } else { - cb(undefined, result || file); - } - }, - (error) => cb(error) - ); - }, - }); + transform(file: File, _, cb) { + Promise.resolve() + .then(async () => { + if (file.isDirectory()) { + return cb(undefined, file); + } -export const excludeFiles = (globs: string[]) => { - const patterns = globs.map( - (g) => - new Minimatch(g, { - matchBase: true, - }) - ); + if (!(file.contents instanceof Buffer)) { + throw new Error('files must be buffered to use transformFileStream()'); + } - return tapFileStream((file) => { - const path = file.relative.replace(/\.ejs$/, ''); - const exclude = patterns.some((p) => p.match(path)); - if (exclude) { - return null; - } + const result = await fn(file as BufferedFile); + + if (result === null) { + // explicitly drop file if null is returned + cb(); + } else { + cb(undefined, result || file); + } + }) + .catch(cb); + }, }); -}; diff --git a/packages/kbn-i18n/package.json b/packages/kbn-i18n/package.json index 0f830acb284a0..680c789bc9d9d 100644 --- a/packages/kbn-i18n/package.json +++ b/packages/kbn-i18n/package.json @@ -21,7 +21,7 @@ "del": "^5.1.0", "getopts": "^2.2.4", "supports-color": "^7.0.0", - "typescript": "3.9.5" + "typescript": "4.0.2" }, "dependencies": { "intl-format-cache": "^2.1.0", diff --git a/packages/kbn-monaco/package.json b/packages/kbn-monaco/package.json index 3e5a3cd216225..ca133010fe230 100644 --- a/packages/kbn-monaco/package.json +++ b/packages/kbn-monaco/package.json @@ -20,7 +20,7 @@ "del": "^5.1.0", "raw-loader": "3.1.0", "supports-color": "^7.0.0", - "typescript": "3.9.5", + "typescript": "4.0.2", "webpack": "^4.41.5", "webpack-cli": "^3.3.10" } diff --git a/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.ts b/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.ts index a848d779dc9a2..8a3379211927b 100644 --- a/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.ts +++ b/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.ts @@ -50,7 +50,7 @@ export function findKibanaPlatformPlugins(scanDirs: string[], paths: string[]) { directory, manifestPath, id: manifest.id, - isUiPlugin: !!manifest.ui, + isUiPlugin: manifest.ui, extraPublicDirs: extraPublicDirs || [], }; } diff --git a/packages/kbn-plugin-generator/package.json b/packages/kbn-plugin-generator/package.json index 89e4251bd7802..1d9637c8279da 100644 --- a/packages/kbn-plugin-generator/package.json +++ b/packages/kbn-plugin-generator/package.json @@ -14,7 +14,7 @@ "execa": "^4.0.2", "inquirer": "^7.3.3", "normalize-path": "^3.0.0", - "prettier": "^2.0.5", + "prettier": "^2.1.1", "vinyl": "^2.2.0", "vinyl-fs": "^3.0.3" }, diff --git a/packages/kbn-plugin-generator/src/plugin_types.ts b/packages/kbn-plugin-generator/src/plugin_types.ts new file mode 100644 index 0000000000000..ae5201f4e8dbb --- /dev/null +++ b/packages/kbn-plugin-generator/src/plugin_types.ts @@ -0,0 +1,60 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import Path from 'path'; + +import { REPO_ROOT } from '@kbn/dev-utils'; + +export interface PluginType { + thirdParty: boolean; + installDir: string; +} + +export const PLUGIN_TYPE_OPTIONS: Array<{ name: string; value: PluginType }> = [ + { + name: 'Installable plugin', + value: { thirdParty: true, installDir: Path.resolve(REPO_ROOT, 'plugins') }, + }, + { + name: 'Kibana Example', + value: { thirdParty: false, installDir: Path.resolve(REPO_ROOT, 'examples') }, + }, + { + name: 'Kibana OSS', + value: { thirdParty: false, installDir: Path.resolve(REPO_ROOT, 'src/plugins') }, + }, + { + name: 'Kibana OSS Functional Testing', + value: { + thirdParty: false, + installDir: Path.resolve(REPO_ROOT, 'test/plugin_functional/plugins'), + }, + }, + { + name: 'X-Pack', + value: { thirdParty: false, installDir: Path.resolve(REPO_ROOT, 'x-pack/plugins') }, + }, + { + name: 'X-Pack Functional Testing', + value: { + thirdParty: false, + installDir: Path.resolve(REPO_ROOT, 'x-pack/test/plugin_functional/plugins'), + }, + }, +]; diff --git a/packages/kbn-plugin-generator/src/render_template.ts b/packages/kbn-plugin-generator/src/render_template.ts index 18bdcf1be1a6b..894088c119651 100644 --- a/packages/kbn-plugin-generator/src/render_template.ts +++ b/packages/kbn-plugin-generator/src/render_template.ts @@ -23,15 +23,32 @@ import { promisify } from 'util'; import vfs from 'vinyl-fs'; import prettier from 'prettier'; -import { REPO_ROOT } from '@kbn/dev-utils'; +import { REPO_ROOT, transformFileStream } from '@kbn/dev-utils'; import ejs from 'ejs'; +import { Minimatch } from 'minimatch'; import { snakeCase, camelCase, upperCamelCase } from './casing'; -import { excludeFiles, tapFileStream } from './streams'; import { Answers } from './ask_questions'; const asyncPipeline = promisify(pipeline); +const excludeFiles = (globs: string[]) => { + const patterns = globs.map( + (g) => + new Minimatch(g, { + matchBase: true, + }) + ); + + return transformFileStream((file) => { + const path = file.relative.replace(/\.ejs$/, ''); + const exclude = patterns.some((p) => p.match(path)); + if (exclude) { + return null; + } + }); +}; + /** * Stream all the files from the template directory, ignoring * certain files based on the answers, process the .ejs templates @@ -82,7 +99,7 @@ export async function renderTemplates({ ), // render .ejs templates and rename to not use .ejs extension - tapFileStream((file) => { + transformFileStream((file) => { if (file.extname !== '.ejs') { return; } @@ -108,7 +125,7 @@ export async function renderTemplates({ }), // format each file with prettier - tapFileStream((file) => { + transformFileStream((file) => { if (!file.extname) { return; } diff --git a/packages/kbn-plugin-generator/template/README.md.ejs b/packages/kbn-plugin-generator/template/README.md.ejs index 5f30bf0463305..2cd19c904263e 100755 --- a/packages/kbn-plugin-generator/template/README.md.ejs +++ b/packages/kbn-plugin-generator/template/README.md.ejs @@ -7,3 +7,14 @@ A Kibana plugin ## Development See the [kibana contributing guide](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md) for instructions setting up your development environment. + +<% if (thirdPartyPlugin) { %> +## Scripts +
+
yarn kbn bootstrap
+
Execute this to install node_modules and setup the dependencies in your plugin and in Kibana
+ +
yarn plugin-helpers build
+
Execute this to create a distributable version of this plugin that can be installed in Kibana
+
+<% } %> diff --git a/packages/kbn-plugin-generator/template/package.json.ejs b/packages/kbn-plugin-generator/template/package.json.ejs index cbd59894ca47c..ab234b1df2bc5 100644 --- a/packages/kbn-plugin-generator/template/package.json.ejs +++ b/packages/kbn-plugin-generator/template/package.json.ejs @@ -3,6 +3,8 @@ "version": "0.0.0", "private": true, "scripts": { + "build": "yarn plugin-helpers build", + "plugin-helpers": "node ../../scripts/plugin_helpers", "kbn": "node ../../scripts/kbn" } } diff --git a/packages/kbn-plugin-helpers/package.json b/packages/kbn-plugin-helpers/package.json index 9cc34bcda1af4..129c58a4b4174 100644 --- a/packages/kbn-plugin-helpers/package.json +++ b/packages/kbn-plugin-helpers/package.json @@ -1,43 +1,32 @@ { "name": "@kbn/plugin-helpers", - "version": "9.0.2", + "version": "1.0.0", "private": true, "description": "Just some helpers for kibana plugin devs.", "license": "Apache-2.0", - "main": "target/lib/index.js", - "scripts": { - "kbn:bootstrap": "tsc" - }, + "main": "target/index.js", "bin": { "plugin-helpers": "bin/plugin-helpers.js" }, + "scripts": { + "kbn:bootstrap": "rm -rf target && tsc", + "kbn:watch": "tsc --watch" + }, "dependencies": { - "@babel/core": "^7.11.1", - "argv-split": "^2.0.1", - "commander": "^3.0.0", + "@kbn/dev-utils": "1.0.0", + "@kbn/optimizer": "1.0.0", "del": "^5.1.0", "execa": "^4.0.2", - "globby": "^8.0.1", - "gulp-babel": "^8.0.0", - "gulp-rename": "1.4.0", - "gulp-zip": "5.0.1", + "gulp-zip": "^5.0.2", "inquirer": "^1.2.2", - "minimatch": "^3.0.4", - "through2": "^2.0.3", - "through2-map": "^3.0.0", - "vinyl": "^2.2.0", + "load-json-file": "^6.2.0", "vinyl-fs": "^3.0.3" }, "devDependencies": { - "@types/gulp-rename": "^0.0.33", + "@types/decompress": "^4.2.3", "@types/gulp-zip": "^4.0.1", "@types/inquirer": "^6.5.0", - "@types/through2": "^2.0.35", - "@types/through2-map": "^3.0.0", - "@types/vinyl": "^2.0.4", - "typescript": "3.9.5" - }, - "peerDependencies": { - "@kbn/babel-preset": "1.0.0" + "decompress": "^4.2.1", + "typescript": "4.0.2" } } diff --git a/packages/kbn-plugin-helpers/bin/plugin-helpers.js b/packages/kbn-plugin-helpers/src/build_context.ts old mode 100755 new mode 100644 similarity index 73% rename from packages/kbn-plugin-helpers/bin/plugin-helpers.js rename to packages/kbn-plugin-helpers/src/build_context.ts index 175ff1019fa2d..62300d5a34e49 --- a/packages/kbn-plugin-helpers/bin/plugin-helpers.js +++ b/packages/kbn-plugin-helpers/src/build_context.ts @@ -1,5 +1,3 @@ -#!/usr/bin/env node - /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -19,10 +17,16 @@ * under the License. */ -const nodeMajorVersion = parseFloat(process.version.replace(/^v(\d+)\..+/, '$1')); -if (nodeMajorVersion < 6) { - console.error('FATAL: kibana-plugin-helpers requires node 6+'); - process.exit(1); -} +import { ToolingLog } from '@kbn/dev-utils'; -require('../target/cli'); +import { Plugin } from './load_kibana_platform_plugin'; +import { Config } from './config'; + +export interface BuildContext { + log: ToolingLog; + plugin: Plugin; + config: Config; + sourceDir: string; + buildDir: string; + kibanaVersion: string; +} diff --git a/packages/kbn-plugin-helpers/src/cli.ts b/packages/kbn-plugin-helpers/src/cli.ts index 18ddc62cba8a6..21b6559f63650 100644 --- a/packages/kbn-plugin-helpers/src/cli.ts +++ b/packages/kbn-plugin-helpers/src/cli.ts @@ -17,59 +17,86 @@ * under the License. */ -import Fs from 'fs'; import Path from 'path'; -import program from 'commander'; +import { RunWithCommands, createFlagError, createFailError } from '@kbn/dev-utils'; -import { createCommanderAction } from './lib/commander_action'; -import { docs } from './lib/docs'; -import { enableCollectingUnknownOptions } from './lib/enable_collecting_unknown_options'; +import { findKibanaJson } from './find_kibana_json'; +import { loadKibanaPlatformPlugin } from './load_kibana_platform_plugin'; +import * as Tasks from './tasks'; +import { BuildContext } from './build_context'; +import { resolveKibanaVersion } from './resolve_kibana_version'; +import { loadConfig } from './config'; -const pkg = JSON.parse(Fs.readFileSync(Path.resolve(__dirname, '../package.json'), 'utf8')); -program.version(pkg.version); +export function runCli() { + new RunWithCommands({ + description: 'Some helper tasks for plugin-authors', + }) + .command({ + name: 'build', + description: ` + Copies files from the source into a zip archive that can be distributed for + installation into production Kibana installs. The archive includes the non- + development npm dependencies and builds itself using raw files in the source + directory so make sure they are clean/up to date. The resulting archive can + be found at: -enableCollectingUnknownOptions( - program - .command('start') - .description('Start kibana and have it include this plugin') - .on('--help', docs('start')) - .action( - createCommanderAction('start', (command) => ({ - flags: command.unknownOptions, - })) - ) -); + build/{plugin.id}-{kibanaVersion}.zip -program - .command('build [files...]') - .description('Build a distributable archive') - .on('--help', docs('build')) - .option('--skip-archive', "Don't create the zip file, leave the build path alone") - .option( - '-d, --build-destination ', - 'Target path for the build output, absolute or relative to the plugin root' - ) - .option('-b, --build-version ', 'Version for the build output') - .option('-k, --kibana-version ', 'Kibana version for the build output') - .action( - createCommanderAction('build', (command, files) => ({ - buildDestination: command.buildDestination, - buildVersion: command.buildVersion, - kibanaVersion: command.kibanaVersion, - skipArchive: Boolean(command.skipArchive), - files, - })) - ); + `, + flags: { + boolean: ['skip-archive'], + string: ['kibana-version'], + alias: { + k: 'kibana-version', + }, + help: ` + --skip-archive Don't create the zip file, just create the build/kibana directory + --kibana-version, -v Kibana version that the + `, + }, + async run({ log, flags }) { + const versionFlag = flags['kibana-version']; + if (versionFlag !== undefined && typeof versionFlag !== 'string') { + throw createFlagError('expected a single --kibana-version flag'); + } -program - .command('test:mocha [files...]') - .description('Run the server tests using mocha') - .on('--help', docs('test/mocha')) - .action( - createCommanderAction('testMocha', (command, files) => ({ - files, - })) - ); + const skipArchive = flags['skip-archive']; + if (skipArchive !== undefined && typeof skipArchive !== 'boolean') { + throw createFlagError('expected a single --skip-archive flag'); + } -program.parse(process.argv); + const pluginDir = await findKibanaJson(process.cwd()); + if (!pluginDir) { + throw createFailError( + `Unable to find Kibana Platform plugin in [${process.cwd()}] or any of its parent directories. Has it been migrated properly? Does it have a kibana.json file?` + ); + } + + const plugin = loadKibanaPlatformPlugin(pluginDir); + const config = await loadConfig(log, plugin); + const kibanaVersion = await resolveKibanaVersion(versionFlag, plugin); + const sourceDir = plugin.directory; + const buildDir = Path.resolve(plugin.directory, 'build/kibana', plugin.manifest.id); + + const context: BuildContext = { + log, + plugin, + config, + sourceDir, + buildDir, + kibanaVersion, + }; + + await Tasks.initTargets(context); + await Tasks.optimize(context); + await Tasks.writeServerFiles(context); + await Tasks.yarnInstall(context); + + if (skipArchive !== true) { + await Tasks.createArchive(context); + } + }, + }) + .execute(); +} diff --git a/packages/kbn-plugin-helpers/src/config.ts b/packages/kbn-plugin-helpers/src/config.ts new file mode 100644 index 0000000000000..bd5ad8ab6acc7 --- /dev/null +++ b/packages/kbn-plugin-helpers/src/config.ts @@ -0,0 +1,83 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import Path from 'path'; + +import loadJsonFile from 'load-json-file'; + +import { ToolingLog } from '@kbn/dev-utils'; +import { Plugin } from './load_kibana_platform_plugin'; + +export interface Config { + skipInstallDependencies: boolean; + serverSourcePatterns?: string[]; +} + +const isArrayOfStrings = (v: any): v is string[] => + Array.isArray(v) && v.every((p) => typeof p === 'string'); + +export async function loadConfig(log: ToolingLog, plugin: Plugin): Promise { + try { + const path = Path.resolve(plugin.directory, '.kibana-plugin-helpers.json'); + const file = await loadJsonFile(path); + + if (!(typeof file === 'object' && file && !Array.isArray(file))) { + throw new TypeError(`expected config at [${path}] to be an object`); + } + + const { + skipInstallDependencies = false, + buildSourcePatterns, + serverSourcePatterns, + ...rest + } = file; + + if (typeof skipInstallDependencies !== 'boolean') { + throw new TypeError(`expected [skipInstallDependencies] at [${path}] to be a boolean`); + } + + if (buildSourcePatterns) { + log.warning( + `DEPRECATED: rename [buildSourcePatterns] to [serverSourcePatterns] in [${path}]` + ); + } + const ssp = buildSourcePatterns || serverSourcePatterns; + if (ssp !== undefined && !isArrayOfStrings(ssp)) { + throw new TypeError(`expected [serverSourcePatterns] at [${path}] to be an array of strings`); + } + + if (Object.keys(rest).length) { + throw new TypeError(`unexpected key in [${path}]: ${Object.keys(rest).join(', ')}`); + } + + log.info(`Loaded config file from [${path}]`); + return { + skipInstallDependencies, + serverSourcePatterns: ssp, + }; + } catch (error) { + if (error.code === 'ENOENT') { + return { + skipInstallDependencies: false, + }; + } + + throw error; + } +} diff --git a/packages/kbn-plugin-helpers/src/lib/run.ts b/packages/kbn-plugin-helpers/src/find_kibana_json.ts similarity index 65% rename from packages/kbn-plugin-helpers/src/lib/run.ts rename to packages/kbn-plugin-helpers/src/find_kibana_json.ts index 2b1a2a63c1074..9340309056830 100644 --- a/packages/kbn-plugin-helpers/src/lib/run.ts +++ b/packages/kbn-plugin-helpers/src/find_kibana_json.ts @@ -17,21 +17,21 @@ * under the License. */ -import { pluginConfig, PluginConfig } from './plugin_config'; -import { tasks, Tasks } from './tasks'; +import Path from 'path'; +import Fs from 'fs'; +import { promisify } from 'util'; -export interface TaskContext { - plugin: PluginConfig; - run: typeof run; - options?: any; -} +const existsAsync = promisify(Fs.exists); + +export async function findKibanaJson(directory: string): Promise { + if (await existsAsync(Path.resolve(directory, 'kibana.json'))) { + return directory; + } -export function run(name: keyof Tasks, options?: any) { - const action = tasks[name]; - if (!action) { - throw new Error('Invalid task: "' + name + '"'); + const parent = Path.dirname(directory); + if (parent === directory) { + return undefined; } - const plugin = pluginConfig(); - return action({ plugin, run, options }); + return findKibanaJson(parent); } diff --git a/packages/kbn-plugin-helpers/src/tasks/start/index.ts b/packages/kbn-plugin-helpers/src/index.ts similarity index 96% rename from packages/kbn-plugin-helpers/src/tasks/start/index.ts rename to packages/kbn-plugin-helpers/src/index.ts index cf34bdbadf416..a05bc698bde17 100644 --- a/packages/kbn-plugin-helpers/src/tasks/start/index.ts +++ b/packages/kbn-plugin-helpers/src/index.ts @@ -17,4 +17,4 @@ * under the License. */ -export * from './start_task'; +export * from './cli'; diff --git a/packages/kbn-plugin-helpers/src/integration_tests/build.test.ts b/packages/kbn-plugin-helpers/src/integration_tests/build.test.ts new file mode 100644 index 0000000000000..62f83cd672f3d --- /dev/null +++ b/packages/kbn-plugin-helpers/src/integration_tests/build.test.ts @@ -0,0 +1,123 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import Path from 'path'; +import Fs from 'fs'; + +import execa from 'execa'; +import { createStripAnsiSerializer, REPO_ROOT, createReplaceSerializer } from '@kbn/dev-utils'; +import decompress from 'decompress'; +import del from 'del'; +import globby from 'globby'; +import loadJsonFile from 'load-json-file'; + +const PLUGIN_DIR = Path.resolve(REPO_ROOT, 'plugins/foo_test_plugin'); +const PLUGIN_BUILD_DIR = Path.resolve(PLUGIN_DIR, 'build'); +const PLUGIN_ARCHIVE = Path.resolve(PLUGIN_BUILD_DIR, `fooTestPlugin-7.5.0.zip`); +const TMP_DIR = Path.resolve(__dirname, '__tmp__'); + +expect.addSnapshotSerializer(createReplaceSerializer(/[\d\.]+ sec/g, '