[kbn/generate] add basic package generator (#127095)

This commit is contained in:
Spencer 2022-03-08 17:04:45 -08:00 committed by GitHub
parent 7923667067
commit ad0eb60772
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 2200 additions and 1166 deletions

View file

@ -32,6 +32,7 @@ snapshots.js
# package overrides
/packages/elastic-eslint-config-kibana
/packages/kbn-plugin-generator/template
/packages/kbn-generate/templates
/packages/kbn-pm/dist
/packages/kbn-test/src/functional_test_runner/__tests__/fixtures/
/packages/kbn-test/src/functional_test_runner/lib/config/__tests__/fixtures/

View file

@ -469,7 +469,9 @@
"@kbn/eslint-import-resolver-kibana": "link:bazel-bin/packages/kbn-eslint-import-resolver-kibana",
"@kbn/eslint-plugin-eslint": "link:bazel-bin/packages/kbn-eslint-plugin-eslint",
"@kbn/expect": "link:bazel-bin/packages/kbn-expect",
"@kbn/generate": "link:bazel-bin/packages/kbn-generate",
"@kbn/optimizer": "link:bazel-bin/packages/kbn-optimizer",
"@kbn/packages": "link:bazel-bin/packages/kbn-packages",
"@kbn/plugin-generator": "link:bazel-bin/packages/kbn-plugin-generator",
"@kbn/plugin-helpers": "link:bazel-bin/packages/kbn-plugin-helpers",
"@kbn/pm": "link:packages/kbn-pm",
@ -585,6 +587,7 @@
"@types/kbn__es-archiver": "link:bazel-bin/packages/kbn-es-archiver/npm_module_types",
"@types/kbn__es-query": "link:bazel-bin/packages/kbn-es-query/npm_module_types",
"@types/kbn__field-types": "link:bazel-bin/packages/kbn-field-types/npm_module_types",
"@types/kbn__generate": "link:bazel-bin/packages/kbn-generate/npm_module_types",
"@types/kbn__i18n": "link:bazel-bin/packages/kbn-i18n/npm_module_types",
"@types/kbn__i18n-react": "link:bazel-bin/packages/kbn-i18n-react/npm_module_types",
"@types/kbn__interpreter": "link:bazel-bin/packages/kbn-interpreter/npm_module_types",
@ -594,6 +597,7 @@
"@types/kbn__mapbox-gl": "link:bazel-bin/packages/kbn-mapbox-gl/npm_module_types",
"@types/kbn__monaco": "link:bazel-bin/packages/kbn-monaco/npm_module_types",
"@types/kbn__optimizer": "link:bazel-bin/packages/kbn-optimizer/npm_module_types",
"@types/kbn__packages": "link:bazel-bin/packages/kbn-packages/npm_module_types",
"@types/kbn__plugin-generator": "link:bazel-bin/packages/kbn-plugin-generator/npm_module_types",
"@types/kbn__plugin-helpers": "link:bazel-bin/packages/kbn-plugin-helpers/npm_module_types",
"@types/kbn__react-field": "link:bazel-bin/packages/kbn-react-field/npm_module_types",

View file

@ -1,79 +1,87 @@
################
################
## This file is automatically generated, to create a new package use `node scripts/generate package --help`
################
################
# It will build all declared code packages
filegroup(
name = "build_pkg_code",
srcs = [
"//packages/elastic-apm-synthtrace:build",
"//packages/elastic-datemath:build",
"//packages/elastic-eslint-config-kibana:build",
"//packages/elastic-safer-lodash-set:build",
"//packages/kbn-ace:build",
"//packages/kbn-alerts:build",
"//packages/kbn-analytics:build",
"//packages/kbn-apm-config-loader:build",
"//packages/kbn-apm-utils:build",
"//packages/kbn-babel-code-parser:build",
"//packages/kbn-babel-preset:build",
"//packages/kbn-cli-dev-mode:build",
"//packages/kbn-config:build",
"//packages/kbn-config-schema:build",
"//packages/kbn-crypto:build",
"//packages/kbn-dev-utils:build",
"//packages/kbn-doc-links:build",
"//packages/kbn-docs-utils:build",
"//packages/kbn-es:build",
"//packages/kbn-es-archiver:build",
"//packages/kbn-es-query:build",
"//packages/kbn-eslint-import-resolver-kibana:build",
"//packages/kbn-eslint-plugin-eslint:build",
"//packages/kbn-expect:build",
"//packages/kbn-field-types:build",
"//packages/kbn-flot-charts:build",
"//packages/kbn-i18n:build",
"//packages/kbn-i18n-react:build",
"//packages/kbn-interpreter:build",
"//packages/kbn-io-ts-utils:build",
"//packages/kbn-logging:build",
"//packages/kbn-logging-mocks:build",
"//packages/kbn-mapbox-gl:build",
"//packages/kbn-monaco:build",
"//packages/kbn-optimizer:build",
"//packages/kbn-plugin-generator:build",
"//packages/kbn-plugin-helpers:build",
"//packages/kbn-react-field:build",
"//packages/kbn-rule-data-utils:build",
"//packages/kbn-securitysolution-autocomplete:build",
"//packages/kbn-securitysolution-list-constants:build",
"//packages/kbn-securitysolution-io-ts-types:build",
"//packages/kbn-securitysolution-io-ts-alerting-types:build",
"//packages/kbn-securitysolution-io-ts-list-types:build",
"//packages/kbn-securitysolution-io-ts-utils:build",
"//packages/kbn-securitysolution-list-api:build",
"//packages/kbn-securitysolution-list-hooks:build",
"//packages/kbn-securitysolution-list-utils:build",
"//packages/kbn-securitysolution-rules:build",
"//packages/kbn-securitysolution-utils:build",
"//packages/kbn-securitysolution-es-utils:build",
"//packages/kbn-securitysolution-t-grid:build",
"//packages/kbn-securitysolution-hook-utils:build",
"//packages/kbn-server-http-tools:build",
"//packages/kbn-server-route-repository:build",
"//packages/kbn-spec-to-console:build",
"//packages/kbn-std:build",
"//packages/kbn-storybook:build",
"//packages/kbn-telemetry-tools:build",
"//packages/kbn-test:build",
"//packages/kbn-test-jest-helpers:build",
"//packages/kbn-test-subj-selector:build",
"//packages/kbn-timelion-grammar:build",
"//packages/kbn-tinymath:build",
"//packages/kbn-type-summarizer:build",
"//packages/kbn-typed-react-router-config:build",
"//packages/kbn-ui-framework:build",
"//packages/kbn-ui-shared-deps-npm:build",
"//packages/kbn-ui-shared-deps-src:build",
"//packages/kbn-ui-theme:build",
"//packages/kbn-utility-types:build",
"//packages/kbn-utils:build",
"//packages/elastic-apm-synthtrace:build",
"//packages/elastic-datemath:build",
"//packages/elastic-eslint-config-kibana:build",
"//packages/elastic-safer-lodash-set:build",
"//packages/kbn-ace:build",
"//packages/kbn-alerts:build",
"//packages/kbn-analytics:build",
"//packages/kbn-apm-config-loader:build",
"//packages/kbn-apm-utils:build",
"//packages/kbn-babel-code-parser:build",
"//packages/kbn-babel-preset:build",
"//packages/kbn-cli-dev-mode:build",
"//packages/kbn-config-schema:build",
"//packages/kbn-config:build",
"//packages/kbn-crypto:build",
"//packages/kbn-dev-utils:build",
"//packages/kbn-doc-links:build",
"//packages/kbn-docs-utils:build",
"//packages/kbn-es-archiver:build",
"//packages/kbn-es-query:build",
"//packages/kbn-es:build",
"//packages/kbn-eslint-import-resolver-kibana:build",
"//packages/kbn-eslint-plugin-eslint:build",
"//packages/kbn-expect:build",
"//packages/kbn-field-types:build",
"//packages/kbn-flot-charts:build",
"//packages/kbn-generate:build",
"//packages/kbn-i18n-react:build",
"//packages/kbn-i18n:build",
"//packages/kbn-interpreter:build",
"//packages/kbn-io-ts-utils:build",
"//packages/kbn-logging-mocks:build",
"//packages/kbn-logging:build",
"//packages/kbn-mapbox-gl:build",
"//packages/kbn-monaco:build",
"//packages/kbn-optimizer:build",
"//packages/kbn-packages:build",
"//packages/kbn-plugin-generator:build",
"//packages/kbn-plugin-helpers:build",
"//packages/kbn-react-field:build",
"//packages/kbn-rule-data-utils:build",
"//packages/kbn-securitysolution-autocomplete:build",
"//packages/kbn-securitysolution-es-utils:build",
"//packages/kbn-securitysolution-hook-utils:build",
"//packages/kbn-securitysolution-io-ts-alerting-types:build",
"//packages/kbn-securitysolution-io-ts-list-types:build",
"//packages/kbn-securitysolution-io-ts-types:build",
"//packages/kbn-securitysolution-io-ts-utils:build",
"//packages/kbn-securitysolution-list-api:build",
"//packages/kbn-securitysolution-list-constants:build",
"//packages/kbn-securitysolution-list-hooks:build",
"//packages/kbn-securitysolution-list-utils:build",
"//packages/kbn-securitysolution-rules:build",
"//packages/kbn-securitysolution-t-grid:build",
"//packages/kbn-securitysolution-utils:build",
"//packages/kbn-server-http-tools:build",
"//packages/kbn-server-route-repository:build",
"//packages/kbn-spec-to-console:build",
"//packages/kbn-std:build",
"//packages/kbn-storybook:build",
"//packages/kbn-telemetry-tools:build",
"//packages/kbn-test-jest-helpers:build",
"//packages/kbn-test-subj-selector:build",
"//packages/kbn-test:build",
"//packages/kbn-timelion-grammar:build",
"//packages/kbn-tinymath:build",
"//packages/kbn-type-summarizer:build",
"//packages/kbn-typed-react-router-config:build",
"//packages/kbn-ui-framework:build",
"//packages/kbn-ui-shared-deps-npm:build",
"//packages/kbn-ui-shared-deps-src:build",
"//packages/kbn-ui-theme:build",
"//packages/kbn-utility-types:build",
"//packages/kbn-utils:build",
],
)
@ -81,77 +89,77 @@ filegroup(
filegroup(
name = "build_pkg_types",
srcs = [
"//packages/elastic-apm-synthtrace:build_types",
"//packages/elastic-datemath:build_types",
"//packages/elastic-safer-lodash-set:build_types",
"//packages/kbn-ace:build_types",
"//packages/kbn-alerts:build_types",
"//packages/kbn-analytics:build_types",
"//packages/kbn-apm-config-loader:build_types",
"//packages/kbn-apm-utils:build_types",
"//packages/kbn-cli-dev-mode:build_types",
"//packages/kbn-config:build_types",
"//packages/kbn-config-schema:build_types",
"//packages/kbn-crypto:build_types",
"//packages/kbn-dev-utils:build_types",
"//packages/kbn-doc-links:build_types",
"//packages/kbn-docs-utils:build_types",
"//packages/kbn-es-archiver:build_types",
"//packages/kbn-es-query:build_types",
"//packages/kbn-field-types:build_types",
"//packages/kbn-i18n:build_types",
"//packages/kbn-i18n-react:build_types",
"//packages/kbn-interpreter:build_types",
"//packages/kbn-io-ts-utils:build_types",
"//packages/kbn-logging:build_types",
"//packages/kbn-logging-mocks:build_types",
"//packages/kbn-mapbox-gl:build_types",
"//packages/kbn-monaco:build_types",
"//packages/kbn-optimizer:build_types",
"//packages/kbn-plugin-generator:build_types",
"//packages/kbn-plugin-helpers:build_types",
"//packages/kbn-react-field:build_types",
"//packages/kbn-rule-data-utils:build_types",
"//packages/kbn-securitysolution-autocomplete:build_types",
"//packages/kbn-securitysolution-es-utils:build_types",
"//packages/kbn-securitysolution-hook-utils:build_types",
"//packages/kbn-securitysolution-io-ts-alerting-types:build_types",
"//packages/kbn-securitysolution-io-ts-list-types:build_types",
"//packages/kbn-securitysolution-io-ts-types:build_types",
"//packages/kbn-securitysolution-io-ts-utils:build_types",
"//packages/kbn-securitysolution-list-api:build_types",
"//packages/kbn-securitysolution-list-constants:build_types",
"//packages/kbn-securitysolution-list-hooks:build_types",
"//packages/kbn-securitysolution-list-utils:build_types",
"//packages/kbn-securitysolution-rules:build_types",
"//packages/kbn-securitysolution-t-grid:build_types",
"//packages/kbn-securitysolution-utils:build_types",
"//packages/kbn-server-http-tools:build_types",
"//packages/kbn-server-route-repository:build_types",
"//packages/kbn-std:build_types",
"//packages/kbn-storybook:build_types",
"//packages/kbn-telemetry-tools:build_types",
"//packages/kbn-test:build_types",
"//packages/kbn-test-jest-helpers:build_types",
"//packages/kbn-type-summarizer:build_types",
"//packages/kbn-typed-react-router-config:build_types",
"//packages/kbn-ui-shared-deps-npm:build_types",
"//packages/kbn-ui-shared-deps-src:build_types",
"//packages/kbn-ui-theme:build_types",
"//packages/kbn-utility-types:build_types",
"//packages/kbn-utils:build_types",
"//packages/elastic-apm-synthtrace:build_types",
"//packages/elastic-datemath:build_types",
"//packages/elastic-safer-lodash-set:build_types",
"//packages/kbn-ace:build_types",
"//packages/kbn-alerts:build_types",
"//packages/kbn-analytics:build_types",
"//packages/kbn-apm-config-loader:build_types",
"//packages/kbn-apm-utils:build_types",
"//packages/kbn-cli-dev-mode:build_types",
"//packages/kbn-config-schema:build_types",
"//packages/kbn-config:build_types",
"//packages/kbn-crypto:build_types",
"//packages/kbn-dev-utils:build_types",
"//packages/kbn-doc-links:build_types",
"//packages/kbn-docs-utils:build_types",
"//packages/kbn-es-archiver:build_types",
"//packages/kbn-es-query:build_types",
"//packages/kbn-field-types:build_types",
"//packages/kbn-generate:build_types",
"//packages/kbn-i18n-react:build_types",
"//packages/kbn-i18n:build_types",
"//packages/kbn-interpreter:build_types",
"//packages/kbn-io-ts-utils:build_types",
"//packages/kbn-logging-mocks:build_types",
"//packages/kbn-logging:build_types",
"//packages/kbn-mapbox-gl:build_types",
"//packages/kbn-monaco:build_types",
"//packages/kbn-optimizer:build_types",
"//packages/kbn-packages:build_types",
"//packages/kbn-plugin-generator:build_types",
"//packages/kbn-plugin-helpers:build_types",
"//packages/kbn-react-field:build_types",
"//packages/kbn-rule-data-utils:build_types",
"//packages/kbn-securitysolution-autocomplete:build_types",
"//packages/kbn-securitysolution-es-utils:build_types",
"//packages/kbn-securitysolution-hook-utils:build_types",
"//packages/kbn-securitysolution-io-ts-alerting-types:build_types",
"//packages/kbn-securitysolution-io-ts-list-types:build_types",
"//packages/kbn-securitysolution-io-ts-types:build_types",
"//packages/kbn-securitysolution-io-ts-utils:build_types",
"//packages/kbn-securitysolution-list-api:build_types",
"//packages/kbn-securitysolution-list-constants:build_types",
"//packages/kbn-securitysolution-list-hooks:build_types",
"//packages/kbn-securitysolution-list-utils:build_types",
"//packages/kbn-securitysolution-rules:build_types",
"//packages/kbn-securitysolution-t-grid:build_types",
"//packages/kbn-securitysolution-utils:build_types",
"//packages/kbn-server-http-tools:build_types",
"//packages/kbn-server-route-repository:build_types",
"//packages/kbn-std:build_types",
"//packages/kbn-storybook:build_types",
"//packages/kbn-telemetry-tools:build_types",
"//packages/kbn-test-jest-helpers:build_types",
"//packages/kbn-test:build_types",
"//packages/kbn-type-summarizer:build_types",
"//packages/kbn-typed-react-router-config:build_types",
"//packages/kbn-ui-shared-deps-npm:build_types",
"//packages/kbn-ui-shared-deps-src:build_types",
"//packages/kbn-ui-theme:build_types",
"//packages/kbn-utility-types:build_types",
"//packages/kbn-utils:build_types",
],
)
# Grouping target to call all underlying packages build
# targets so we can build them all at once
# It will auto build all declared code packages and types packages
filegroup(
name = "build",
srcs = [
":build_pkg_code",
":build_pkg_types"
":build_pkg_code",
":build_pkg_types"
],
)

View file

@ -38,13 +38,14 @@ NPM_MODULE_EXTRA_FILES = [
"README.md",
":certs",
"ci_stats_reporter/package.json",
"sort_package_json/package.json",
"stdio/package.json",
"tooling_log/package.json"
]
RUNTIME_DEPS = [
"//packages/kbn-utils",
"//packages/kbn-std",
"//packages/kbn-utils",
"@npm//@babel/core",
"@npm//axios",
"@npm//chalk",
@ -59,6 +60,7 @@ RUNTIME_DEPS = [
"@npm//normalize-path",
"@npm//prettier",
"@npm//rxjs",
"@npm//sort-package-json",
"@npm//tar",
"@npm//tree-kill",
"@npm//vinyl",
@ -66,8 +68,8 @@ RUNTIME_DEPS = [
]
TYPES_DEPS = [
"//packages/kbn-utils:npm_module_types",
"//packages/kbn-std:npm_module_types",
"//packages/kbn-utils:npm_module_types",
"@npm//@babel/parser",
"@npm//@babel/types",
"@npm//@types/babel__core",
@ -89,6 +91,7 @@ TYPES_DEPS = [
"@npm//exit-hook",
"@npm//getopts",
"@npm//rxjs",
"@npm//sort-package-json",
"@npm//tree-kill",
]

View file

@ -0,0 +1,4 @@
{
"main": "../target_node/sort_package_json",
"types": "../target_types/sort_package_json"
}

View file

@ -32,3 +32,4 @@ export * from './streams';
export * from './babel';
export * from './extract';
export * from './vscode_config';
export * from './sort_package_json';

View file

@ -0,0 +1,43 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import sorter from 'sort-package-json';
export function sortPackageJson(json: string) {
return (
JSON.stringify(
sorter(JSON.parse(json), {
// top level keys in the order they were written when this was implemented
sortOrder: [
'name',
'description',
'keywords',
'private',
'version',
'branch',
'main',
'browser',
'types',
'tsdocMetadata',
'build',
'homepage',
'bugs',
'license',
'kibana',
'author',
'scripts',
'repository',
'engines',
'resolutions',
],
}),
null,
2
) + '\n'
);
}

View file

@ -0,0 +1,110 @@
load("@npm//@bazel/typescript:index.bzl", "ts_config")
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project")
PKG_BASE_NAME = "kbn-generate"
PKG_REQUIRE_NAME = "@kbn/generate"
SOURCE_FILES = glob(
[
"src/**/*.ts",
],
exclude = [
"**/*.test.*"
],
)
SRCS = SOURCE_FILES
filegroup(
name = "srcs",
srcs = SRCS,
)
NPM_MODULE_EXTRA_FILES = glob(["templates/**/*"]) + [
"package.json",
]
RUNTIME_DEPS = [
"//packages/kbn-dev-utils",
"//packages/kbn-packages",
"//packages/kbn-utils",
"@npm//ejs",
"@npm//normalize-path",
]
TYPES_DEPS = [
"//packages/kbn-dev-utils:npm_module_types",
"//packages/kbn-packages:npm_module_types",
"//packages/kbn-utils:npm_module_types",
"@npm//ejs",
"@npm//normalize-path",
"@npm//@types/ejs",
]
jsts_transpiler(
name = "target_node",
srcs = SRCS,
build_pkg_name = package_name(),
)
ts_config(
name = "tsconfig",
src = "tsconfig.json",
deps = [
"//:tsconfig.base.json",
"//:tsconfig.bazel.json",
],
)
ts_project(
name = "tsc_types",
args = ['--pretty'],
srcs = SRCS,
deps = TYPES_DEPS,
declaration = True,
emit_declaration_only = True,
out_dir = "target_types",
root_dir = "src",
tsconfig = ":tsconfig",
)
js_library(
name = PKG_BASE_NAME,
srcs = NPM_MODULE_EXTRA_FILES,
deps = RUNTIME_DEPS + [":target_node"],
package_name = PKG_REQUIRE_NAME,
visibility = ["//visibility:public"],
)
pkg_npm(
name = "npm_module",
deps = [
":%s" % PKG_BASE_NAME,
]
)
filegroup(
name = "build",
srcs = [
":npm_module",
],
visibility = ["//visibility:public"],
)
pkg_npm_types(
name = "npm_module_types",
srcs = SRCS,
deps = [":tsc_types"],
package_name = PKG_REQUIRE_NAME,
tsconfig = ":tsconfig",
visibility = ["//visibility:public"],
)
filegroup(
name = "build_types",
srcs = [
":npm_module_types",
],
visibility = ["//visibility:public"],
)

View file

@ -0,0 +1,7 @@
# @kbn/generate
Provides a CLI for generating different components within Kibana
## `node scripts/generate package`
Generate a Kibana package, run `node scripts/generate package --help` for details about options.

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
module.exports = {
preset: '@kbn/test',
rootDir: '../..',
roots: ['<rootDir>/packages/kbn-generate'],
};

View file

@ -0,0 +1,10 @@
{
"name": "@kbn/generate",
"version": "1.0.0",
"private": true,
"license": "SSPL-1.0 OR Elastic License 2.0",
"main": "./target_node/index.js",
"kibana": {
"devOnly": true
}
}

View file

@ -0,0 +1,184 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import Fsp from 'fs/promises';
import Path from 'path';
import Ejs from 'ejs';
import globby from 'globby';
import { REPO_ROOT } from '@kbn/utils';
import {
RunWithCommands,
createFlagError,
createFailError,
isFailError,
sortPackageJson,
} from '@kbn/dev-utils';
import { discoverPackages, generatePackagesBuildBazelFile } from '@kbn/packages';
import normalizePath from 'normalize-path';
const ROOT_PKG_DIR = Path.resolve(REPO_ROOT, 'packages');
const TEMPLATE_DIR = Path.resolve(__dirname, '../templates/package');
const jsonHelper = (arg: any) => JSON.stringify(arg, null, 2);
const jsHelper = (arg: string) => {
if (typeof arg !== 'string') {
throw new Error('js() only supports strings right now');
}
const hasSingle = arg.includes(`'`);
const hasBacktick = arg.includes('`');
if (!hasSingle) {
return `'${arg}'`;
}
if (!hasBacktick) {
return `\`${arg}\``;
}
return `'${arg.replaceAll(`'`, `\\'`)}'`;
};
export function runGenerateCli() {
new RunWithCommands({
description: 'Run generators for different components in Kibana',
})
.command({
name: 'package',
description: 'Generate a basic package',
usage: 'node scripts/generate package [name]',
flags: {
boolean: ['web', 'force', 'dev'],
string: ['dir'],
help: `
--dev Generate a package which is intended for dev-only use and can access things like devDependencies
--web Build webpack-compatible version of sources for this package
--dir Directory where this package will live, defaults to [./packages]
--force If the packageDir already exists, delete it before generation
`,
},
async run({ log, flags }) {
const [name] = flags._;
if (!name) {
throw createFlagError(`missing package name`);
}
if (!name.startsWith('@kbn/')) {
throw createFlagError(`package name must start with @kbn/`);
}
const typePkgName = `@types/${name.slice(1).replace('/', '__')}`;
const web = !!flags.web;
const dev = !!flags.dev;
const containingDir = flags.dir ? Path.resolve(`${flags.dir}`) : ROOT_PKG_DIR;
const packageDir = Path.resolve(containingDir, name.slice(1).replace('/', '-'));
const repoRelativeDir = normalizePath(Path.relative(REPO_ROOT, packageDir));
try {
await Fsp.readdir(packageDir);
if (!!flags.force) {
await Fsp.rm(packageDir, { recursive: true });
log.warning('deleted existing package at', packageDir);
} else {
throw createFailError(
`Package dir [${packageDir}] already exists, either choose a new package name, or pass --force to delete the package and regenerate it`
);
}
} catch (error) {
if (isFailError(error)) {
throw error;
}
}
const templateFiles = await globby('**/*', {
cwd: TEMPLATE_DIR,
absolute: false,
dot: true,
onlyFiles: true,
});
await Fsp.mkdir(packageDir, { recursive: true });
for (const rel of templateFiles) {
const destDir = Path.resolve(packageDir, Path.dirname(rel));
await Fsp.mkdir(destDir, { recursive: true });
if (Path.basename(rel) === '.empty') {
log.debug('created dir', destDir);
// ignore .empty files in the template, just create the directory
continue;
}
const ejs = !!rel.endsWith('.ejs');
const src = Path.resolve(TEMPLATE_DIR, rel);
const dest = Path.resolve(packageDir, ejs ? rel.slice(0, -4) : rel);
if (!ejs) {
await Fsp.copyFile(src, dest);
log.debug('copied', rel);
continue;
}
const vars = {
pkg: {
name,
web,
dev,
directoryName: Path.basename(repoRelativeDir),
repoRelativeDir,
},
// helpers
json: jsonHelper,
js: jsHelper,
relativePathTo: (rootRelativePath: string) => {
return Path.relative(Path.dirname(dest), Path.resolve(REPO_ROOT, rootRelativePath));
},
};
log.verbose('rendering', src, 'with variables', vars);
let content = await Ejs.renderFile(src, vars);
if (Path.basename(dest) === 'package.json') {
content = sortPackageJson(content);
}
await Fsp.writeFile(dest, content);
log.debug('rendered', rel);
}
log.info('Wrote plugin files to', packageDir);
const packageJsonPath = Path.resolve(REPO_ROOT, 'package.json');
const packageJson = JSON.parse(await Fsp.readFile(packageJsonPath, 'utf8'));
const [addDeps, removeDeps] = dev
? [packageJson.devDependencies, packageJson.dependencies]
: [packageJson.dependencies, packageJson.devDependencies];
addDeps[name] = `link:bazel-bin/${repoRelativeDir}`;
addDeps[typePkgName] = `link:bazel-bin/${repoRelativeDir}/npm_module_types`;
delete removeDeps[name];
delete removeDeps[typePkgName];
await Fsp.writeFile(packageJsonPath, sortPackageJson(JSON.stringify(packageJson)));
log.info('Updated package.json file');
await Fsp.writeFile(
Path.resolve(REPO_ROOT, 'packages/BUILD.bazel'),
generatePackagesBuildBazelFile(await discoverPackages())
);
log.info('Updated packages/BUILD.bazel');
log.success(`Generated ${name}! Please bootstrap to make sure it works.`);
},
})
.execute();
}

View file

@ -0,0 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export * from './cli';

View file

@ -0,0 +1,121 @@
load("@npm//@bazel/typescript:index.bzl", "ts_config")
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project")
PKG_DIRNAME = <%- json(pkg.directoryName) %>
PKG_REQUIRE_NAME = <%- json(pkg.name) %>
SOURCE_FILES = glob(
[
"src/**/*.ts",
],
exclude = [
"**/*.test.*",
],
)
SRCS = SOURCE_FILES
filegroup(
name = "srcs",
srcs = SRCS,
)
NPM_MODULE_EXTRA_FILES = [
"package.json",
]
# In this array place runtime dependencies, including other packages and NPM packages
# which must be available for this code to run.
#
# To reference other packages use:
# "//repo/relative/path/to/package"
# eg. "//packages/kbn-utils"
#
# To reference a NPM package use:
# "@npm//name-of-package"
# eg. "@npm//lodash"
RUNTIME_DEPS = [
]
# In this array place dependencies necessary to build the types, which will include the
# :npm_module_types target of other packages and packages from NPM, including @types/*
# packages.
#
# To reference the types for another package use:
# "//repo/relative/path/to/package:npm_module_types"
# eg. "//packages/kbn-utils:npm_module_types"
#
# References to NPM packages work the same as RUNTIME_DEPS
TYPES_DEPS = [
"//@npm//@types/node",
"//@npm//@types/jest",
]
jsts_transpiler(
name = "target_node",
srcs = SRCS,
build_pkg_name = package_name(),
)
<% if (pkg.web) { %>
jsts_transpiler(
name = "target_web",
srcs = SRCS,
build_pkg_name = package_name(),
web = True,
)
<% } %>
ts_config(
name = "tsconfig",
src = "tsconfig.json",
deps = [
"//:tsconfig.base.json",
"//:tsconfig.bazel.json",
],
)
ts_project(
name = "tsc_types",
args = ['--pretty'],
srcs = SRCS,
deps = TYPES_DEPS,
declaration = True,
emit_declaration_only = True,
out_dir = "target_types",
root_dir = "src",
tsconfig = ":tsconfig",
)
js_library(
name = PKG_DIRNAME,
srcs = NPM_MODULE_EXTRA_FILES,
deps = RUNTIME_DEPS + <%- pkg.web ? '[":target_node", ":target_web"]' : '[":target_node"]' %>,
package_name = PKG_REQUIRE_NAME,
visibility = ["//visibility:public"],
)
pkg_npm(
name = "npm_module",
deps = [":" + PKG_DIRNAME],
)
filegroup(
name = "build",
srcs = [":npm_module"],
visibility = ["//visibility:public"],
)
pkg_npm_types(
name = "npm_module_types",
srcs = SRCS,
deps = [":tsc_types"],
package_name = PKG_REQUIRE_NAME,
tsconfig = ":tsconfig",
visibility = ["//visibility:public"],
)
filegroup(
name = "build_types",
srcs = [":npm_module_types"],
visibility = ["//visibility:public"],
)

View file

@ -0,0 +1,3 @@
# <%- pkg.name %>
Empty package generated by @kbn/generate

View file

@ -0,0 +1,5 @@
module.exports = {
preset: <%- js(pkg.web ? '@kbn/test' : '@kbn/test/jest_node') %>,
rootDir: '../..',
roots: [<%- js(`<rootDir>/${pkg.repoRelativeDir}`) %>],
};

View file

@ -0,0 +1,15 @@
{
"name": <%- json(pkg.name) %>,
"version": "1.0.0",
"private": true,
"license": "SSPL-1.0 OR Elastic License 2.0",
"main": "./target_node/index.js"
<%_ if (pkg.web) { %>,
"browser": "./target_web/index.js"
<%_ } %>
<% if (pkg.dev) { %>,
"kibana": {
"devOnly": true
}
<% } %>
}

View file

@ -0,0 +1,3 @@
export function foo() {
return 'hello world';
}

View file

@ -0,0 +1,17 @@
{
"extends": "<%- relativePathTo("tsconfig.bazel.json") %>",
"compilerOptions": {
"declaration": true,
"emitDeclarationOnly": true,
"outDir": "target_types",
"rootDir": "src",
"stripInternal": false,
"types": [
"jest",
"node"
]
},
"include": [
"src/**/*"
]
}

View file

@ -0,0 +1,17 @@
{
"extends": "../../tsconfig.bazel.json",
"compilerOptions": {
"declaration": true,
"emitDeclarationOnly": true,
"outDir": "target_types",
"rootDir": "src",
"stripInternal": false,
"types": [
"jest",
"node"
]
},
"include": [
"src/**/*"
]
}

View file

@ -0,0 +1,120 @@
load("@npm//@bazel/typescript:index.bzl", "ts_config")
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project")
PKG_DIRNAME = "kbn-packages"
PKG_REQUIRE_NAME = "@kbn/packages"
SOURCE_FILES = glob(
[
"src/**/*.ts",
],
exclude = [
"**/*.test.*",
],
)
SRCS = SOURCE_FILES
filegroup(
name = "srcs",
srcs = SRCS,
)
NPM_MODULE_EXTRA_FILES = [
"package.json",
"README.md",
]
# In this array place runtime dependencies, including other packages and NPM packages
# which must be available for this code to run.
#
# To reference other packages use:
# "//repo/relative/path/to/package"
# eg. "//packages/kbn-utils"
#
# To reference a NPM package use:
# "@npm//name-of-package"
# eg. "@npm//lodash"
RUNTIME_DEPS = [
"//packages/kbn-utils",
"//packages/kbn-std",
"@npm//globby",
]
# In this array place dependencies necessary to build the types, which will include the
# :npm_module_types target of other packages and packages from NPM, including @types/*
# packages.
#
# To reference the types for another package use:
# "//repo/relative/path/to/package:npm_module_types"
# eg. "//packages/kbn-utils:npm_module_types"
#
# References to NPM packages work the same as RUNTIME_DEPS:
# eg. "@npm//@types/babel__core"
TYPES_DEPS = [
"//packages/kbn-utils:npm_module_types",
"//packages/kbn-std:npm_module_types",
"@npm//globby",
]
jsts_transpiler(
name = "target_node",
srcs = SRCS,
build_pkg_name = package_name(),
)
ts_config(
name = "tsconfig",
src = "tsconfig.json",
deps = [
"//:tsconfig.base.json",
"//:tsconfig.bazel.json",
],
)
ts_project(
name = "tsc_types",
args = ['--pretty'],
srcs = SRCS,
deps = TYPES_DEPS,
declaration = True,
emit_declaration_only = True,
out_dir = "target_types",
root_dir = "src",
tsconfig = ":tsconfig",
)
js_library(
name = PKG_DIRNAME,
srcs = NPM_MODULE_EXTRA_FILES,
deps = RUNTIME_DEPS + [":target_node"],
package_name = PKG_REQUIRE_NAME,
visibility = ["//visibility:public"],
)
pkg_npm(
name = "npm_module",
deps = [":" + PKG_DIRNAME],
)
filegroup(
name = "build",
srcs = [":npm_module"],
visibility = ["//visibility:public"],
)
pkg_npm_types(
name = "npm_module_types",
srcs = SRCS,
deps = [":tsc_types"],
package_name = PKG_REQUIRE_NAME,
tsconfig = ":tsconfig",
visibility = ["//visibility:public"],
)
filegroup(
name = "build_types",
srcs = [":npm_module_types"],
visibility = ["//visibility:public"],
)

View file

@ -0,0 +1,3 @@
# @kbn/packages
Empty package generated by @kbn/generate

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
module.exports = {
preset: '@kbn/test/jest_node',
rootDir: '../..',
roots: ['<rootDir>/packages/kbn-packages'],
};

View file

@ -0,0 +1,10 @@
{
"name": "@kbn/packages",
"private": true,
"version": "1.0.0",
"main": "./target_node/index.js",
"license": "SSPL-1.0 OR Elastic License 2.0",
"kibana": {
"devOnly": true
}
}

View file

@ -0,0 +1,28 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import Path from 'path';
import globby from 'globby';
import { REPO_ROOT } from '@kbn/utils';
import { asyncMapWithLimit } from '@kbn/std';
import { Package } from './package';
export async function discoverPackages() {
const packageJsons = globby.sync('*/package.json', {
cwd: Path.resolve(REPO_ROOT, 'packages'),
absolute: true,
});
return await asyncMapWithLimit(
packageJsons.sort((a, b) => a.localeCompare(b)),
10,
(path) => Package.fromDir(Path.dirname(path))
);
}

View file

@ -0,0 +1,85 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { generatePackagesBuildBazelFile } from './generate_packages_build_bazel_file';
import { Package } from './package';
it('produces a valid BUILD.bazel file', () => {
const packages = [
new Package(
'foo',
{},
`
rule(
name = "build"
)
rule(
name = "build_types"
)
`
),
new Package(
'bar',
{},
`
rule(
name= "build_types"
)
`
),
new Package(
'bar',
{},
`
rule(
name ="build"
)
`
),
new Package('bar', {}),
];
expect(generatePackagesBuildBazelFile(packages)).toMatchInlineSnapshot(`
"################
################
## This file is automatically generated, to create a new package use \`node scripts/generate package --help\`
################
################
# It will build all declared code packages
filegroup(
name = \\"build_pkg_code\\",
srcs = [
\\"//foo:build\\",
\\"//bar:build\\",
],
)
# It will build all declared package types
filegroup(
name = \\"build_pkg_types\\",
srcs = [
\\"//foo:build_types\\",
\\"//bar:build_types\\",
],
)
# Grouping target to call all underlying packages build
# targets so we can build them all at once
# It will auto build all declared code packages and types packages
filegroup(
name = \\"build\\",
srcs = [
\\":build_pkg_code\\",
\\":build_pkg_types\\"
],
)
"
`);
});

View file

@ -0,0 +1,49 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { Package } from './package';
export function generatePackagesBuildBazelFile(packages: Package[]) {
return `################
################
## This file is automatically generated, to create a new package use \`node scripts/generate package --help\`
################
################
# It will build all declared code packages
filegroup(
name = "build_pkg_code",
srcs = [
${packages
.flatMap((p) => (p.hasBuildRule() ? ` "//${p.repoRelativeDir}:build",` : []))
.join('\n')}
],
)
# It will build all declared package types
filegroup(
name = "build_pkg_types",
srcs = [
${packages
.flatMap((p) => (p.hasBuildTypesRule() ? ` "//${p.repoRelativeDir}:build_types",` : []))
.join('\n')}
],
)
# Grouping target to call all underlying packages build
# targets so we can build them all at once
# It will auto build all declared code packages and types packages
filegroup(
name = "build",
srcs = [
":build_pkg_code",
":build_pkg_types"
],
)
`;
}

View file

@ -0,0 +1,10 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export * from './discover_packages';
export * from './generate_packages_build_bazel_file';

View file

@ -0,0 +1,38 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import Fs from 'fs';
import Path from 'path';
import { Package } from './package';
const OWN_BAZEL_BUILD_FILE = Fs.readFileSync(Path.resolve(__dirname, '../BUILD.bazel'), 'utf8');
describe('hasBuildRule()', () => {
it('returns true if there is a rule with the name "build"', () => {
const pkg = new Package('foo', {}, OWN_BAZEL_BUILD_FILE);
expect(pkg.hasBuildRule()).toBe(true);
});
it('returns false if there is no rule with name "build"', () => {
const pkg = new Package('foo', {}, ``);
expect(pkg.hasBuildRule()).toBe(false);
});
});
describe('hasBuildTypesRule()', () => {
it('returns true if there is a rule with the name "build_types"', () => {
const pkg = new Package('foo', {}, OWN_BAZEL_BUILD_FILE);
expect(pkg.hasBuildTypesRule()).toBe(true);
});
it('returns false if there is no rule with name "build_types"', () => {
const pkg = new Package('foo', {}, ``);
expect(pkg.hasBuildTypesRule()).toBe(false);
});
});

View file

@ -0,0 +1,50 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import Path from 'path';
import Fsp from 'fs/promises';
import { REPO_ROOT } from '@kbn/utils';
const BUILD_RULE_NAME = /(^|\s)name\s*=\s*"build"/;
const BUILD_TYPES_RULE_NAME = /(^|\s)name\s*=\s*"build_types"/;
export class Package {
static async fromDir(dir: string) {
let pkg;
try {
pkg = JSON.parse(await Fsp.readFile(Path.resolve(dir, 'package.json'), 'utf8'));
} catch (error) {
throw new Error(`unable to parse package.json in [${dir}]: ${error.message}`);
}
let buildBazelContent;
if (pkg.name !== '@kbn/pm') {
try {
buildBazelContent = await Fsp.readFile(Path.resolve(dir, 'BUILD.bazel'), 'utf8');
} catch (error) {
throw new Error(`unable to read BUILD.bazel file in [${dir}]: ${error.message}`);
}
}
return new Package(Path.relative(REPO_ROOT, dir), pkg, buildBazelContent);
}
constructor(
public readonly repoRelativeDir: string,
public readonly pkg: any,
public readonly buildBazelContent?: string
) {}
hasBuildRule() {
return !!(this.buildBazelContent && BUILD_RULE_NAME.test(this.buildBazelContent));
}
hasBuildTypesRule() {
return !!(this.buildBazelContent && BUILD_TYPES_RULE_NAME.test(this.buildBazelContent));
}
}

View file

@ -0,0 +1,17 @@
{
"extends": "../../tsconfig.bazel.json",
"compilerOptions": {
"declaration": true,
"emitDeclarationOnly": true,
"outDir": "target_types",
"rootDir": "src",
"stripInternal": false,
"types": [
"jest",
"node"
]
},
"include": [
"src/**/*"
]
}

File diff suppressed because one or more lines are too long

View file

@ -7,41 +7,10 @@
*/
import Fs from 'fs/promises';
import sorter from 'sort-package-json';
import { sortPackageJson as sort } from '@kbn/dev-utils/sort_package_json';
import { Kibana } from './kibana';
export async function sortPackageJson(kbn: Kibana) {
const packageJsonPath = kbn.getAbsolute('package.json');
const packageJson = await Fs.readFile(packageJsonPath, 'utf-8');
await Fs.writeFile(
packageJsonPath,
JSON.stringify(
sorter(JSON.parse(packageJson), {
// top level keys in the order they were written when this was implemented
sortOrder: [
'name',
'description',
'keywords',
'private',
'version',
'branch',
'types',
'tsdocMetadata',
'build',
'homepage',
'bugs',
'kibana',
'author',
'scripts',
'repository',
'engines',
'resolutions',
],
}),
null,
2
) + '\n'
);
await Fs.writeFile(packageJsonPath, sort(await Fs.readFile(packageJsonPath, 'utf-8')));
}

View file

@ -12,7 +12,7 @@ import { CliError } from './cli_error';
import { parseCliFlags } from './cli_flags';
import * as Path from './path';
const TYPE_SUMMARIZER_PACKAGES = ['@kbn/type-summarizer', '@kbn/crypto'];
const TYPE_SUMMARIZER_PACKAGES = ['@kbn/type-summarizer', '@kbn/crypto', '@kbn/generate'];
const isString = (i: any): i is string => typeof i === 'string' && i.length > 0;

11
scripts/generate.js Normal file
View file

@ -0,0 +1,11 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
require('../src/setup_node_env/ensure_node_preserve_symlinks');
require('source-map-support/register');
require('@kbn/generate').runGenerateCli();

View file

@ -50,9 +50,17 @@ export class File {
}
public isFixture() {
return (
this.relativePath.split(sep).includes('__fixtures__') || this.path.endsWith('.test-d.ts')
);
const parts = this.relativePath.split(sep);
if (parts.includes('__fixtures__') || this.path.endsWith('.test-d.ts')) {
return true;
}
const i = parts.indexOf('kbn-generate');
if (i >= 0 && parts[i + 1] === 'templates') {
return true;
}
return false;
}
public getRelativeParentDirs() {

View file

@ -107,7 +107,10 @@ export const IGNORE_DIRECTORY_GLOBS = [
*
* @type {Array}
*/
export const REMOVE_EXTENSION = ['packages/kbn-plugin-generator/template/**/*.ejs'];
export const REMOVE_EXTENSION = [
'packages/kbn-plugin-generator/template/**/*.ejs',
'packages/kbn-generate/templates/**/*.ejs',
];
/**
* DO NOT ADD FILES TO THIS LIST!!

View file

@ -2989,6 +2989,10 @@
version "0.0.0"
uid ""
"@kbn/generate@link:bazel-bin/packages/kbn-generate":
version "0.0.0"
uid ""
"@kbn/i18n-react@link:bazel-bin/packages/kbn-i18n-react":
version "0.0.0"
uid ""
@ -3025,6 +3029,10 @@
version "0.0.0"
uid ""
"@kbn/packages@link:bazel-bin/packages/kbn-packages":
version "0.0.0"
uid ""
"@kbn/plugin-generator@link:bazel-bin/packages/kbn-plugin-generator":
version "0.0.0"
uid ""
@ -5954,6 +5962,10 @@
version "0.0.0"
uid ""
"@types/kbn__generate@link:bazel-bin/packages/kbn-generate/npm_module_types":
version "0.0.0"
uid ""
"@types/kbn__i18n-react@link:bazel-bin/packages/kbn-i18n-react/npm_module_types":
version "0.0.0"
uid ""
@ -5990,6 +6002,10 @@
version "0.0.0"
uid ""
"@types/kbn__packages@link:bazel-bin/packages/kbn-packages/npm_module_types":
version "0.0.0"
uid ""
"@types/kbn__plugin-generator@link:bazel-bin/packages/kbn-plugin-generator/npm_module_types":
version "0.0.0"
uid ""