Implement package linter (#148496)

This PR implements a linter like the TS Project linter, except for
packages in the repo. It does this by extracting the reusable bits from
the TS Project linter and reusing them for the project linter. The only
rule that exists for packages right now is that the "name" in the
package.json file matches the "id" in Kibana.jsonc. The goal is to use a
rule to migrate kibana.json files on the future.

Additionally, a new rule for validating the indentation of tsconfig.json
files was added.

Validating and fixing violations is what has triggered review by so many
teams, but we plan to treat those review requests as notifications of
the changes and not as blockers for merging.

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Spencer 2023-01-09 17:49:29 -06:00 committed by GitHub
parent 039ed991d8
commit d6be4a4b06
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
218 changed files with 3917 additions and 1650 deletions

View file

@ -115,6 +115,7 @@ export class CliDevMode {
}
const { watchPaths, ignorePaths } = getServerWatchPaths({
runExamples: cliArgs.runExamples,
pluginPaths: config.plugins.additionalPluginPaths,
pluginScanDirs: config.plugins.pluginSearchPaths,
});

View file

@ -10,13 +10,48 @@ import Path from 'path';
import { createAbsolutePathSerializer } from '@kbn/jest-serializers';
import { REPO_ROOT } from '@kbn/repo-info';
import type { KibanaPackageType } from '@kbn/repo-packages';
const TYPES = Object.keys(
(() => {
const asObj: { [k in KibanaPackageType]: true } = {
'functional-tests': true,
'plugin-browser': true,
'plugin-server': true,
'shared-browser': true,
'shared-common': true,
'shared-scss': true,
'shared-server': true,
'test-helper': true,
};
return asObj;
})()
);
import { getServerWatchPaths } from './get_server_watch_paths';
jest.mock('@kbn/repo-packages', () => ({
getPackages: jest.fn(),
getPluginPackagesFilter: jest.fn().mockReturnValue(() => true),
}));
const mockGetPluginPackagesFilter = jest.requireMock('@kbn/repo-packages').getPluginPackagesFilter;
const mockGetPackages = jest.requireMock('@kbn/repo-packages').getPackages;
expect.addSnapshotSerializer(createAbsolutePathSerializer());
it('produces the right watch and ignore list', () => {
mockGetPackages.mockReturnValue(
TYPES.flatMap((type) => ({
isPlugin: type.startsWith('plugin-'),
directory: Path.resolve(REPO_ROOT, 'packages', type),
manifest: {
type,
},
}))
);
const { watchPaths, ignorePaths } = getServerWatchPaths({
runExamples: false,
pluginPaths: [Path.resolve(REPO_ROOT, 'x-pack/test/plugin_functional/plugins/resolver_test')],
pluginScanDirs: [
Path.resolve(REPO_ROOT, 'src/plugins'),
@ -33,14 +68,9 @@ it('produces the right watch and ignore list', () => {
<absolute path>/src/plugins,
<absolute path>/test/plugin_functional/plugins,
<absolute path>/x-pack/plugins,
<absolute path>/packages,
<absolute path>/packages/shared-ux,
<absolute path>/packages/analytics,
<absolute path>/packages/analytics/shippers,
<absolute path>/packages/analytics/shippers/elastic_v3,
<absolute path>/packages/home,
<absolute path>/packages/content-management,
<absolute path>/x-pack/packages/ml,
<absolute path>/packages/plugin-server,
<absolute path>/packages/shared-common,
<absolute path>/packages/shared-server,
]
`);
@ -89,4 +119,22 @@ it('produces the right watch and ignore list', () => {
<absolute path>/x-pack/plugins/observability/e2e,
]
`);
expect(mockGetPluginPackagesFilter.mock.calls).toMatchInlineSnapshot(`
Array [
Array [
Object {
"examples": false,
"parentDirs": Array [
<absolute path>/src/plugins,
<absolute path>/test/plugin_functional/plugins,
<absolute path>/x-pack/plugins,
],
"paths": Array [
<absolute path>/x-pack/test/plugin_functional/plugins/resolver_test,
],
},
],
]
`);
});

View file

@ -7,24 +7,24 @@
*/
import Path from 'path';
import Fs from 'fs';
import { REPO_ROOT } from '@kbn/repo-info';
import { BAZEL_PACKAGE_DIRS } from '@kbn/bazel-packages';
import { getPackages, getPluginPackagesFilter } from '@kbn/repo-packages';
interface Options {
runExamples: boolean;
pluginPaths: string[];
pluginScanDirs: string[];
}
export type WatchPaths = ReturnType<typeof getServerWatchPaths>;
export function getServerWatchPaths({ pluginPaths, pluginScanDirs }: Options) {
export function getServerWatchPaths(opts: Options) {
const fromRoot = (p: string) => Path.resolve(REPO_ROOT, p);
const pluginInternalDirsIgnore = pluginScanDirs
const pluginInternalDirsIgnore = opts.pluginScanDirs
.map((scanDir) => Path.resolve(scanDir, '*'))
.concat(pluginPaths)
.concat(opts.pluginPaths)
.reduce(
(acc: string[], path) => [
...acc,
@ -38,19 +38,33 @@ export function getServerWatchPaths({ pluginPaths, pluginScanDirs }: Options) {
[]
);
function getServerPkgDirs() {
const pluginFilter = getPluginPackagesFilter({
examples: opts.runExamples,
paths: opts.pluginPaths,
parentDirs: opts.pluginScanDirs,
});
return getPackages(REPO_ROOT).flatMap((p) => {
if (p.isPlugin) {
return pluginFilter(p) && p.manifest.type === 'plugin-server' ? p.directory : [];
}
return p.manifest.type === 'shared-common' || p.manifest.type === 'shared-server'
? p.directory
: [];
});
}
const watchPaths = Array.from(
new Set(
[
fromRoot('src/core'),
fromRoot('src/legacy/server'),
fromRoot('src/legacy/utils'),
fromRoot('config'),
...pluginPaths,
...pluginScanDirs,
...BAZEL_PACKAGE_DIRS,
].map((path) => Path.resolve(path))
)
).filter((path) => Fs.existsSync(fromRoot(path)));
new Set([
fromRoot('src/core'),
fromRoot('config'),
...opts.pluginPaths.map((path) => Path.resolve(path)),
...opts.pluginScanDirs.map((path) => Path.resolve(path)),
...getServerPkgDirs(),
])
);
const ignorePaths = [
/[\\\/](\..*|node_modules|bower_components|target|public|__[a-z0-9_]+__|coverage)([\\\/]|$)/,

View file

@ -20,8 +20,8 @@
"@kbn/ci-stats-reporter",
"@kbn/jest-serializers",
"@kbn/stdio-dev-helpers",
"@kbn/bazel-packages",
"@kbn/tooling-log",
"@kbn/repo-packages",
],
"exclude": [
"target/**/*",