mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[API Docs] Add @track-adoption
(#138366)
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: spalger <spencer@elastic.co>
This commit is contained in:
parent
2115309d0a
commit
27d93fdf69
45 changed files with 655 additions and 308 deletions
|
@ -169,6 +169,8 @@ export interface IAnalyticsClient {
|
|||
* Reports a telemetry event.
|
||||
* @param eventType The event type registered via the `registerEventType` API.
|
||||
* @param eventData The properties matching the schema declared in the `registerEventType` API.
|
||||
*
|
||||
* @track-adoption
|
||||
*/
|
||||
reportEvent: <EventTypeData extends object>(
|
||||
eventType: EventType,
|
||||
|
@ -198,8 +200,10 @@ export interface IAnalyticsClient {
|
|||
*/
|
||||
optIn: (optInConfig: OptInConfig) => void;
|
||||
/**
|
||||
* Registers the context provider to enrich the any reported events.
|
||||
* Registers the context provider to enrich any reported events.
|
||||
* @param contextProviderOpts {@link ContextProviderOpts}
|
||||
*
|
||||
* @track-adoption
|
||||
*/
|
||||
registerContextProvider: <Context>(contextProviderOpts: ContextProviderOpts<Context>) => void;
|
||||
/**
|
||||
|
|
|
@ -50,7 +50,7 @@ export interface CiStatsMetric {
|
|||
/** optional limit which will generate an error on PRs when the metric exceeds the limit */
|
||||
limit?: number;
|
||||
/**
|
||||
* path, relative to the repo, where the config file contianing limits
|
||||
* path, relative to the repo, where the config file containing limits
|
||||
* is kept. Linked from PR comments instructing contributors how to fix
|
||||
* their PRs.
|
||||
*/
|
||||
|
|
13
packages/kbn-docs-utils/jest.integration.config.js
Normal file
13
packages/kbn-docs-utils/jest.integration.config.js
Normal 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_integration_node',
|
||||
rootDir: '../..',
|
||||
roots: ['<rootDir>/packages/kbn-docs-utils'],
|
||||
};
|
|
@ -11,7 +11,7 @@ import { Project, Node } from 'ts-morph';
|
|||
import { ToolingLog } from '@kbn/tooling-log';
|
||||
|
||||
import { TypeKind, ApiScope, PluginOrPackage } from '../types';
|
||||
import { getKibanaPlatformPlugin } from '../tests/kibana_platform_plugin_mock';
|
||||
import { getKibanaPlatformPlugin } from '../integration_tests/kibana_platform_plugin_mock';
|
||||
import { getDeclarationNodesForPluginScope } from '../get_declaration_nodes_for_plugin';
|
||||
import { buildApiDeclarationTopNode } from './build_api_declaration';
|
||||
import { isNamedNode } from '../tsmorph_utils';
|
||||
|
@ -29,7 +29,10 @@ function getNodeName(node: Node): string {
|
|||
}
|
||||
|
||||
beforeAll(() => {
|
||||
const tsConfigFilePath = Path.resolve(__dirname, '../tests/__fixtures__/src/tsconfig.json');
|
||||
const tsConfigFilePath = Path.resolve(
|
||||
__dirname,
|
||||
'../integration_tests/__fixtures__/src/tsconfig.json'
|
||||
);
|
||||
const project = new Project({
|
||||
tsConfigFilePath,
|
||||
});
|
||||
|
|
|
@ -23,6 +23,7 @@ export function buildBasicApiDeclaration(node: Node, opts: BuildApiDecOpts): Api
|
|||
const tags = getJSDocTags(node);
|
||||
const deprecated = tags.find((t) => t.getTagName() === 'deprecated') !== undefined;
|
||||
const removeByTag = tags.find((t) => t.getTagName() === 'removeBy');
|
||||
const trackAdoption = tags.find((t) => t.getTagName() === 'track-adoption') !== undefined;
|
||||
|
||||
let label = opts.name;
|
||||
|
||||
|
@ -49,6 +50,7 @@ export function buildBasicApiDeclaration(node: Node, opts: BuildApiDecOpts): Api
|
|||
path: getSourceForNode(node),
|
||||
deprecated,
|
||||
removeBy: removeByTag ? removeByTag.getCommentText() : undefined,
|
||||
trackAdoption,
|
||||
};
|
||||
return {
|
||||
...apiDec,
|
||||
|
|
|
@ -14,7 +14,7 @@ import { ApiScope, PluginOrPackage, Reference } from '../types';
|
|||
import {
|
||||
getKibanaPlatformPackage,
|
||||
getKibanaPlatformPlugin,
|
||||
} from '../tests/kibana_platform_plugin_mock';
|
||||
} from '../integration_tests/kibana_platform_plugin_mock';
|
||||
|
||||
const plugin = getKibanaPlatformPlugin('pluginA');
|
||||
const packageA = getKibanaPlatformPackage('@kbn/package-a');
|
||||
|
@ -135,7 +135,7 @@ it('test full file imports with a matching plugin', () => {
|
|||
"pluginId": "pluginA",
|
||||
"scope": "public",
|
||||
"section": undefined,
|
||||
"text": "packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/foo/index",
|
||||
"text": "packages/kbn-docs-utils/src/api_docs/integration_tests/__fixtures__/src/plugin_a/public/foo/index",
|
||||
},
|
||||
" something",
|
||||
]
|
||||
|
|
|
@ -73,9 +73,8 @@ export function maybeCollectReferences({
|
|||
apiDec,
|
||||
captureReferences,
|
||||
}: MaybeCollectReferencesOpt): ApiReference[] | undefined {
|
||||
if (Node.isReferenceFindable(node)) {
|
||||
return captureReferences || apiDec.deprecated
|
||||
? getReferences({ node, plugins, currentPluginId, log })
|
||||
: undefined;
|
||||
const shouldCaptureReferences = captureReferences || apiDec.deprecated || apiDec.trackAdoption;
|
||||
if (shouldCaptureReferences && Node.isReferenceFindable(node)) {
|
||||
return getReferences({ node, plugins, currentPluginId, log });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import { writeDeprecationDocByApi } from './mdx/write_deprecations_doc_by_api';
|
|||
import { writeDeprecationDocByPlugin } from './mdx/write_deprecations_doc_by_plugin';
|
||||
import { writePluginDirectoryDoc } from './mdx/write_plugin_directory_doc';
|
||||
import { collectApiStatsForPlugin } from './stats';
|
||||
import { countEslintDisableLine, EslintDisableCounts } from './count_eslint_disable';
|
||||
import { countEslintDisableLines, EslintDisableCounts } from './count_eslint_disable';
|
||||
import { writeDeprecationDueByTeam } from './mdx/write_deprecations_due_by_team';
|
||||
import { trimDeletedDocsFromNav } from './trim_deleted_docs_from_nav';
|
||||
import { getAllDocFileIds } from './mdx/get_all_doc_file_ids';
|
||||
|
@ -37,6 +37,7 @@ function isStringArray(arr: unknown | string[]): arr is string[] {
|
|||
export function runBuildApiDocsCli() {
|
||||
run(
|
||||
async ({ log, flags }) => {
|
||||
const collectReferences = flags.references as boolean;
|
||||
const stats = flags.stats && typeof flags.stats === 'string' ? [flags.stats] : flags.stats;
|
||||
const pluginFilter =
|
||||
flags.plugin && typeof flags.plugin === 'string' ? [flags.plugin] : flags.plugin;
|
||||
|
@ -77,13 +78,16 @@ export function runBuildApiDocsCli() {
|
|||
await Fsp.mkdir(outputFolder, { recursive: true });
|
||||
}
|
||||
|
||||
const collectReferences = flags.references as boolean;
|
||||
|
||||
const { pluginApiMap, missingApiItems, unreferencedDeprecations, referencedDeprecations } =
|
||||
getPluginApiMap(project, plugins, log, {
|
||||
collectReferences,
|
||||
pluginFilter: pluginFilter as string[],
|
||||
});
|
||||
const {
|
||||
pluginApiMap,
|
||||
missingApiItems,
|
||||
unreferencedDeprecations,
|
||||
referencedDeprecations,
|
||||
adoptionTrackedAPIs,
|
||||
} = getPluginApiMap(project, plugins, log, {
|
||||
collectReferences,
|
||||
pluginFilter: pluginFilter as string[],
|
||||
});
|
||||
|
||||
const reporter = CiStatsReporter.fromEnv(log);
|
||||
|
||||
|
@ -93,17 +97,22 @@ export function runBuildApiDocsCli() {
|
|||
const pluginApi = pluginApiMap[id];
|
||||
|
||||
allPluginStats[id] = {
|
||||
...(await countEslintDisableLine(plugin.directory)),
|
||||
...collectApiStatsForPlugin(pluginApi, missingApiItems, referencedDeprecations),
|
||||
...(await countEslintDisableLines(plugin.directory)),
|
||||
...collectApiStatsForPlugin(
|
||||
pluginApi,
|
||||
missingApiItems,
|
||||
referencedDeprecations,
|
||||
adoptionTrackedAPIs
|
||||
),
|
||||
owner: plugin.manifest.owner,
|
||||
description: plugin.manifest.description,
|
||||
isPlugin: plugin.isPlugin,
|
||||
};
|
||||
}
|
||||
|
||||
writePluginDirectoryDoc(outputFolder, pluginApiMap, allPluginStats, log);
|
||||
await writePluginDirectoryDoc(outputFolder, pluginApiMap, allPluginStats, log);
|
||||
|
||||
plugins.forEach((plugin) => {
|
||||
for (const plugin of plugins) {
|
||||
// Note that the filtering is done here, and not above because the entire public plugin API has to
|
||||
// be parsed in order to correctly determine reference links, and ensure that `removeBrokenLinks`
|
||||
// doesn't remove more links than necessary.
|
||||
|
@ -153,6 +162,29 @@ export function runBuildApiDocsCli() {
|
|||
group: 'References to deprecated APIs',
|
||||
value: pluginStats.deprecatedAPIsReferencedCount,
|
||||
},
|
||||
{
|
||||
id,
|
||||
meta: {
|
||||
pluginTeam,
|
||||
// `meta` only allows primitives or string[]
|
||||
// Also, each string is allowed to have a max length of 2056,
|
||||
// so it's safer to stringify each element in the array over sending the entire array as stringified.
|
||||
// My internal tests with 4 plugins using the same API gets to a length of 156 chars,
|
||||
// so we should have enough room for tracking popular APIs.
|
||||
// TODO: We can do a follow-up improvement to split the report if we find out we might hit the limit.
|
||||
adoptionTrackedAPIs: pluginStats.adoptionTrackedAPIs.map((metric) =>
|
||||
JSON.stringify(metric)
|
||||
),
|
||||
},
|
||||
group: 'Adoption-tracked APIs',
|
||||
value: pluginStats.adoptionTrackedAPIsCount,
|
||||
},
|
||||
{
|
||||
id,
|
||||
meta: { pluginTeam },
|
||||
group: 'Adoption-tracked APIs that are not used anywhere',
|
||||
value: pluginStats.adoptionTrackedAPIsUnreferencedCount,
|
||||
},
|
||||
{
|
||||
id,
|
||||
meta: { pluginTeam },
|
||||
|
@ -174,7 +206,7 @@ export function runBuildApiDocsCli() {
|
|||
]);
|
||||
|
||||
const getLink = (d: ApiDeclaration) =>
|
||||
`https://github.com/elastic/kibana/tree/master/${d.path}#:~:text=${encodeURIComponent(
|
||||
`https://github.com/elastic/kibana/tree/main/${d.path}#:~:text=${encodeURIComponent(
|
||||
d.label
|
||||
)}`;
|
||||
|
||||
|
@ -251,19 +283,19 @@ export function runBuildApiDocsCli() {
|
|||
|
||||
if (pluginStats.apiCount > 0) {
|
||||
log.info(`Writing public API doc for plugin ${pluginApi.id}.`);
|
||||
writePluginDocs(outputFolder, { doc: pluginApi, plugin, pluginStats, log });
|
||||
await writePluginDocs(outputFolder, { doc: pluginApi, plugin, pluginStats, log });
|
||||
} else {
|
||||
log.info(`Plugin ${pluginApi.id} has no public API.`);
|
||||
}
|
||||
writeDeprecationDocByPlugin(outputFolder, referencedDeprecations, log);
|
||||
writeDeprecationDueByTeam(outputFolder, referencedDeprecations, plugins, log);
|
||||
writeDeprecationDocByApi(
|
||||
await writeDeprecationDocByPlugin(outputFolder, referencedDeprecations, log);
|
||||
await writeDeprecationDueByTeam(outputFolder, referencedDeprecations, plugins, log);
|
||||
await writeDeprecationDocByApi(
|
||||
outputFolder,
|
||||
referencedDeprecations,
|
||||
unreferencedDeprecations,
|
||||
log
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if (Object.values(pathsOutsideScopes).length > 0) {
|
||||
log.warning(`Found paths outside of normal scope folders:`);
|
||||
|
|
|
@ -6,20 +6,32 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { countEslintDisableLine } from './count_eslint_disable';
|
||||
import { countEslintDisableLines } from './count_eslint_disable';
|
||||
|
||||
/* eslint-disable no-console */
|
||||
|
||||
it('countEsLintDisableLine', async () => {
|
||||
console.log('This is a test');
|
||||
describe('countEslintDisableLines', () => {
|
||||
test('number of "eslint-disable*" in a file', async () => {
|
||||
console.log('This is a test');
|
||||
|
||||
// eslint-disable-next-line prefer-const
|
||||
let test: string = '';
|
||||
// eslint-disable-next-line prefer-const
|
||||
let testVar: string = '';
|
||||
|
||||
const counts = await countEslintDisableLine(__filename);
|
||||
expect(counts.eslintDisableLineCount).toBe(1);
|
||||
expect(counts.eslintDisableFileCount).toBe(1);
|
||||
const counts = await countEslintDisableLines(__filename);
|
||||
expect(counts.eslintDisableLineCount).toBe(1);
|
||||
expect(counts.eslintDisableFileCount).toBe(1);
|
||||
|
||||
// To avoid unused warning.
|
||||
return test;
|
||||
// To avoid unused warning.
|
||||
return testVar;
|
||||
});
|
||||
|
||||
test('number of "eslint-disable*" in a directory', async () => {
|
||||
const counts = await countEslintDisableLines(__dirname);
|
||||
expect(counts).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"eslintDisableFileCount": 3,
|
||||
"eslintDisableLineCount": 8,
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,29 +6,65 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { execSync } from 'child_process';
|
||||
import { asyncMapWithLimit } from '@kbn/std';
|
||||
import Fs from 'fs';
|
||||
import Path from 'path';
|
||||
|
||||
export interface EslintDisableCounts {
|
||||
eslintDisableLineCount: number;
|
||||
eslintDisableFileCount: number;
|
||||
}
|
||||
|
||||
export async function countEslintDisableLine(path: string): Promise<EslintDisableCounts> {
|
||||
const disableCountOutputs = await Promise.all([
|
||||
execSync(`grep -rE 'eslint-disable-next-line|eslint-disable-line' ${path} | wc -l`),
|
||||
execSync(`grep -rE 'eslint-disable ' ${path} | wc -l`),
|
||||
]);
|
||||
const eslintDisableLineCount = Number.parseInt(disableCountOutputs[0].toString(), 10);
|
||||
|
||||
if (eslintDisableLineCount === undefined || isNaN(eslintDisableLineCount)) {
|
||||
throw new Error(`Parsing ${disableCountOutputs[0]} failed to product a valid number`);
|
||||
async function fetchAllFilePaths(path: string): Promise<string[]> {
|
||||
if ((await Fs.promises.stat(path)).isFile()) {
|
||||
return [path];
|
||||
}
|
||||
|
||||
const eslintDisableFileCount = Number.parseInt(disableCountOutputs[1].toString(), 10);
|
||||
|
||||
if (eslintDisableFileCount === undefined || isNaN(eslintDisableFileCount)) {
|
||||
throw new Error(`Parsing ${disableCountOutputs[1]} failed to product a valid number`);
|
||||
const filePaths: string[] = [];
|
||||
const dirContent = await Fs.promises.readdir(path, { withFileTypes: true });
|
||||
for (const item of dirContent) {
|
||||
const itemPath = Path.resolve(path, item.name);
|
||||
if (item.isDirectory()) {
|
||||
filePaths.push(...(await fetchAllFilePaths(itemPath)));
|
||||
} else if (item.isFile()) {
|
||||
filePaths.push(itemPath);
|
||||
}
|
||||
}
|
||||
|
||||
return { eslintDisableFileCount, eslintDisableLineCount };
|
||||
return filePaths;
|
||||
}
|
||||
|
||||
function findOccurrences(fileContent: string, regexp: RegExp): number {
|
||||
// using the flag 'g' returns an array of found occurrences.
|
||||
const matchingResults = fileContent.toString().match(new RegExp(regexp, 'g')) || [];
|
||||
return matchingResults.length;
|
||||
}
|
||||
|
||||
async function countEsLintDisableInFile(path: string): Promise<EslintDisableCounts> {
|
||||
const fileContent = await Fs.promises.readFile(path, { encoding: 'utf8' });
|
||||
|
||||
return {
|
||||
eslintDisableLineCount:
|
||||
findOccurrences(fileContent, /eslint-disable-next-line/) +
|
||||
findOccurrences(fileContent, /eslint-disable-line/),
|
||||
eslintDisableFileCount: findOccurrences(fileContent, /eslint-disable\s/),
|
||||
};
|
||||
}
|
||||
|
||||
export async function countEslintDisableLines(path: string): Promise<EslintDisableCounts> {
|
||||
const filePaths = await fetchAllFilePaths(path);
|
||||
|
||||
const allEslintDisableCounts = await asyncMapWithLimit(filePaths, 100, (filePath) =>
|
||||
countEsLintDisableInFile(filePath)
|
||||
);
|
||||
|
||||
return allEslintDisableCounts.reduce(
|
||||
(acc, fileEslintDisableCounts) => {
|
||||
return {
|
||||
eslintDisableFileCount:
|
||||
acc.eslintDisableFileCount + fileEslintDisableCounts.eslintDisableFileCount,
|
||||
eslintDisableLineCount:
|
||||
acc.eslintDisableLineCount + fileEslintDisableCounts.eslintDisableLineCount,
|
||||
};
|
||||
},
|
||||
{ eslintDisableFileCount: 0, eslintDisableLineCount: 0 }
|
||||
);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
import { ToolingLog } from '@kbn/tooling-log';
|
||||
import { Project } from 'ts-morph';
|
||||
import { getPluginApi } from './get_plugin_api';
|
||||
import {
|
||||
import type {
|
||||
AdoptionTrackedAPIsByPlugin,
|
||||
ApiDeclaration,
|
||||
MissingApiItemMap,
|
||||
PluginApi,
|
||||
|
@ -18,6 +19,7 @@ import {
|
|||
UnreferencedDeprecationsByPlugin,
|
||||
} from './types';
|
||||
import { removeBrokenLinks } from './utils';
|
||||
import { AdoptionTrackedAPIStats } from './types';
|
||||
|
||||
export function getPluginApiMap(
|
||||
project: Project,
|
||||
|
@ -29,10 +31,11 @@ export function getPluginApiMap(
|
|||
missingApiItems: MissingApiItemMap;
|
||||
referencedDeprecations: ReferencedDeprecationsByPlugin;
|
||||
unreferencedDeprecations: UnreferencedDeprecationsByPlugin;
|
||||
adoptionTrackedAPIs: AdoptionTrackedAPIsByPlugin;
|
||||
} {
|
||||
log.debug('Building plugin API map, getting missing comments, and collecting deprecations...');
|
||||
const pluginApiMap: { [key: string]: PluginApi } = {};
|
||||
plugins.map((plugin) => {
|
||||
plugins.forEach((plugin) => {
|
||||
const captureReferences =
|
||||
collectReferences && (!pluginFilter || pluginFilter.indexOf(plugin.manifest.id) >= 0);
|
||||
pluginApiMap[plugin.manifest.id] = getPluginApi(
|
||||
|
@ -47,16 +50,52 @@ export function getPluginApiMap(
|
|||
// Mapping of plugin id to the missing source API id to all the plugin API items that referenced this item.
|
||||
const missingApiItems: { [key: string]: { [key: string]: string[] } } = {};
|
||||
const referencedDeprecations: ReferencedDeprecationsByPlugin = {};
|
||||
|
||||
const unreferencedDeprecations: UnreferencedDeprecationsByPlugin = {};
|
||||
const adoptionTrackedAPIs: AdoptionTrackedAPIsByPlugin = {};
|
||||
|
||||
plugins.forEach((plugin) => {
|
||||
const id = plugin.manifest.id;
|
||||
const pluginApi = pluginApiMap[id];
|
||||
removeBrokenLinks(pluginApi, missingApiItems, pluginApiMap, log);
|
||||
collectDeprecations(pluginApi, referencedDeprecations, unreferencedDeprecations);
|
||||
collectAdoptionTrackedAPIs(pluginApi, adoptionTrackedAPIs);
|
||||
});
|
||||
return { pluginApiMap, missingApiItems, referencedDeprecations, unreferencedDeprecations };
|
||||
return {
|
||||
pluginApiMap,
|
||||
missingApiItems,
|
||||
referencedDeprecations,
|
||||
unreferencedDeprecations,
|
||||
adoptionTrackedAPIs,
|
||||
};
|
||||
}
|
||||
|
||||
function collectAdoptionTrackedAPIs(
|
||||
pluginApi: PluginApi,
|
||||
adoptionTrackedAPIsByPlugin: AdoptionTrackedAPIsByPlugin
|
||||
) {
|
||||
adoptionTrackedAPIsByPlugin[pluginApi.id] = [];
|
||||
(['client', 'common', 'server'] as Array<'client' | 'server' | 'common'>).forEach((scope) => {
|
||||
pluginApi[scope].forEach((api) => {
|
||||
collectAdoptionForApi(api, adoptionTrackedAPIsByPlugin[pluginApi.id]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function collectAdoptionForApi(
|
||||
api: ApiDeclaration,
|
||||
adoptionTrackedAPIs: AdoptionTrackedAPIStats[]
|
||||
) {
|
||||
const { id, label, tags = [], children, references = [] } = api;
|
||||
if (tags.find((tag) => tag === 'track-adoption')) {
|
||||
const uniqueReferences = new Set<string>(references.map(({ plugin }) => plugin));
|
||||
adoptionTrackedAPIs.push({
|
||||
trackedApi: { id, label },
|
||||
references: [...uniqueReferences.values()],
|
||||
});
|
||||
}
|
||||
if (children) {
|
||||
children.forEach((child) => collectAdoptionForApi(child, adoptionTrackedAPIs));
|
||||
}
|
||||
}
|
||||
|
||||
function collectDeprecations(
|
||||
|
|
|
@ -93,7 +93,7 @@ function fnIsCorrect(fn: ApiDeclaration | undefined) {
|
|||
expect(p5?.description?.length).toBe(1);
|
||||
}
|
||||
|
||||
beforeAll(() => {
|
||||
beforeAll(async () => {
|
||||
const tsConfigFilePath = Path.resolve(__dirname, '__fixtures__/src/tsconfig.json');
|
||||
const project = new Project({
|
||||
tsConfigFilePath,
|
||||
|
@ -109,30 +109,34 @@ beforeAll(() => {
|
|||
pluginA.manifest.serviceFolders = ['foo'];
|
||||
const plugins: PluginOrPackage[] = [pluginA, pluginB];
|
||||
|
||||
const { pluginApiMap, missingApiItems, referencedDeprecations } = getPluginApiMap(
|
||||
project,
|
||||
plugins,
|
||||
log,
|
||||
{ collectReferences: false }
|
||||
);
|
||||
const { pluginApiMap, missingApiItems, referencedDeprecations, adoptionTrackedAPIs } =
|
||||
getPluginApiMap(project, plugins, log, { collectReferences: false });
|
||||
|
||||
doc = pluginApiMap.pluginA;
|
||||
|
||||
pluginAStats = collectApiStatsForPlugin(doc, missingApiItems, referencedDeprecations);
|
||||
pluginAStats = collectApiStatsForPlugin(
|
||||
doc,
|
||||
missingApiItems,
|
||||
referencedDeprecations,
|
||||
adoptionTrackedAPIs
|
||||
);
|
||||
pluginBStats = collectApiStatsForPlugin(
|
||||
pluginApiMap.pluginB,
|
||||
missingApiItems,
|
||||
referencedDeprecations
|
||||
referencedDeprecations,
|
||||
adoptionTrackedAPIs
|
||||
);
|
||||
|
||||
mdxOutputFolder = Path.resolve(__dirname, 'snapshots');
|
||||
writePluginDocs(mdxOutputFolder, { doc, plugin: pluginA, pluginStats: pluginAStats, log });
|
||||
writePluginDocs(mdxOutputFolder, {
|
||||
doc: pluginApiMap.pluginB,
|
||||
plugin: pluginB,
|
||||
pluginStats: pluginBStats,
|
||||
log,
|
||||
});
|
||||
await Promise.all([
|
||||
writePluginDocs(mdxOutputFolder, { doc, plugin: pluginA, pluginStats: pluginAStats, log }),
|
||||
writePluginDocs(mdxOutputFolder, {
|
||||
doc: pluginApiMap.pluginB,
|
||||
plugin: pluginB,
|
||||
pluginStats: pluginBStats,
|
||||
log,
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it('Stats', () => {
|
File diff suppressed because it is too large
Load diff
|
@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/pluginA
|
|||
title: "pluginA"
|
||||
image: https://source.unsplash.com/400x175/?github
|
||||
description: API docs for the pluginA plugin
|
||||
date: 2022-08-08
|
||||
date: 2022-09-05
|
||||
tags: ['contributor', 'dev', 'apidocs', 'kibana', 'pluginA']
|
||||
---
|
||||
import pluginAObj from './plugin_a.devdocs.json';
|
|
@ -13,8 +13,9 @@
|
|||
"signature": [
|
||||
"() => void"
|
||||
],
|
||||
"path": "packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/foo/index.ts",
|
||||
"path": "packages/kbn-docs-utils/src/api_docs/integration_tests/__fixtures__/src/plugin_a/public/foo/index.ts",
|
||||
"deprecated": false,
|
||||
"trackAdoption": false,
|
||||
"children": [],
|
||||
"returnComment": [],
|
||||
"initialIsOpen": false
|
||||
|
@ -33,8 +34,9 @@
|
|||
"signature": [
|
||||
"() => \"foo\""
|
||||
],
|
||||
"path": "packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/foo/index.ts",
|
||||
"path": "packages/kbn-docs-utils/src/api_docs/integration_tests/__fixtures__/src/plugin_a/public/foo/index.ts",
|
||||
"deprecated": false,
|
||||
"trackAdoption": false,
|
||||
"returnComment": [],
|
||||
"children": [],
|
||||
"initialIsOpen": false
|
||||
|
@ -66,8 +68,9 @@
|
|||
"signature": [
|
||||
"\"COMMON VAR!\""
|
||||
],
|
||||
"path": "packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/common/foo/index.ts",
|
||||
"path": "packages/kbn-docs-utils/src/api_docs/integration_tests/__fixtures__/src/plugin_a/common/foo/index.ts",
|
||||
"deprecated": false,
|
||||
"trackAdoption": false,
|
||||
"initialIsOpen": false
|
||||
}
|
||||
],
|
|
@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/pluginA-foo
|
|||
title: "pluginA.foo"
|
||||
image: https://source.unsplash.com/400x175/?github
|
||||
description: API docs for the pluginA.foo plugin
|
||||
date: 2022-08-08
|
||||
date: 2022-09-05
|
||||
tags: ['contributor', 'dev', 'apidocs', 'kibana', 'pluginA.foo']
|
||||
---
|
||||
import pluginAFooObj from './plugin_a_foo.devdocs.json';
|
|
@ -29,8 +29,9 @@
|
|||
},
|
||||
"<any>"
|
||||
],
|
||||
"path": "packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_b/public/index.ts",
|
||||
"path": "packages/kbn-docs-utils/src/api_docs/integration_tests/__fixtures__/src/plugin_b/public/index.ts",
|
||||
"deprecated": false,
|
||||
"trackAdoption": false,
|
||||
"children": [
|
||||
{
|
||||
"parentPluginId": "pluginB",
|
||||
|
@ -49,8 +50,9 @@
|
|||
},
|
||||
"<any>"
|
||||
],
|
||||
"path": "packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_b/public/index.ts",
|
||||
"path": "packages/kbn-docs-utils/src/api_docs/integration_tests/__fixtures__/src/plugin_b/public/index.ts",
|
||||
"deprecated": false,
|
||||
"trackAdoption": false,
|
||||
"isRequired": true
|
||||
}
|
||||
],
|
|
@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/pluginB
|
|||
title: "pluginB"
|
||||
image: https://source.unsplash.com/400x175/?github
|
||||
description: API docs for the pluginB plugin
|
||||
date: 2022-08-08
|
||||
date: 2022-09-05
|
||||
tags: ['contributor', 'dev', 'apidocs', 'kibana', 'pluginB']
|
||||
---
|
||||
import pluginBObj from './plugin_b.devdocs.json';
|
|
@ -31,7 +31,7 @@ export function buildPluginDeprecationsTable(
|
|||
|
||||
return `
|
||||
## ${key}
|
||||
|
||||
|
||||
| Deprecated API | Reference location(s) | Remove By |
|
||||
| ---------------|-----------|-----------|
|
||||
${Object.keys(groupedDeprecationReferences)
|
||||
|
@ -50,7 +50,7 @@ export function buildPluginDeprecationsTable(
|
|||
(ref) =>
|
||||
`[${ref.path.substr(
|
||||
ref.path.lastIndexOf(Path.sep) + 1
|
||||
)}](https://github.com/elastic/kibana/tree/master/${
|
||||
)}](https://github.com/elastic/kibana/tree/main/${
|
||||
ref.path
|
||||
}#:~:text=${encodeURIComponent(api.label)})`
|
||||
)
|
||||
|
|
|
@ -11,7 +11,7 @@ import { Project } from 'ts-morph';
|
|||
import { ToolingLog } from '@kbn/tooling-log';
|
||||
|
||||
import { PluginApi, PluginOrPackage } from '../types';
|
||||
import { getKibanaPlatformPlugin } from '../tests/kibana_platform_plugin_mock';
|
||||
import { getKibanaPlatformPlugin } from '../integration_tests/kibana_platform_plugin_mock';
|
||||
import { getPluginApi } from '../get_plugin_api';
|
||||
import { splitApisByFolder } from './write_plugin_split_by_folder';
|
||||
|
||||
|
@ -23,7 +23,10 @@ const log = new ToolingLog({
|
|||
let doc: PluginApi;
|
||||
|
||||
beforeAll(() => {
|
||||
const tsConfigFilePath = Path.resolve(__dirname, '../tests/__fixtures__/src/tsconfig.json');
|
||||
const tsConfigFilePath = Path.resolve(
|
||||
__dirname,
|
||||
'../integration_tests/__fixtures__/src/tsconfig.json'
|
||||
);
|
||||
const project = new Project({
|
||||
tsConfigFilePath,
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import moment from 'moment';
|
||||
import { ToolingLog } from '@kbn/tooling-log';
|
||||
import dedent from 'dedent';
|
||||
import fs from 'fs';
|
||||
import Fsp from 'fs/promises';
|
||||
import Path from 'path';
|
||||
import {
|
||||
ApiReference,
|
||||
|
@ -20,12 +20,12 @@ import {
|
|||
import { AUTO_GENERATED_WARNING } from '../auto_generated_warning';
|
||||
import { getPluginApiDocId } from '../utils';
|
||||
|
||||
export function writeDeprecationDocByApi(
|
||||
export async function writeDeprecationDocByApi(
|
||||
folder: string,
|
||||
deprecationsByPlugin: ReferencedDeprecationsByPlugin,
|
||||
unReferencedDeprecations: UnreferencedDeprecationsByPlugin,
|
||||
log: ToolingLog
|
||||
): void {
|
||||
): Promise<void> {
|
||||
const deprecationReferencesByApi = Object.values(deprecationsByPlugin).reduce(
|
||||
(acc, deprecations) => {
|
||||
deprecations.forEach((deprecation) => {
|
||||
|
@ -111,5 +111,5 @@ ${Object.values(unReferencedDeprecations)
|
|||
|
||||
`);
|
||||
|
||||
fs.writeFileSync(Path.resolve(folder, 'deprecations_by_api.mdx'), mdx);
|
||||
await Fsp.writeFile(Path.resolve(folder, 'deprecations_by_api.mdx'), mdx);
|
||||
}
|
||||
|
|
|
@ -9,17 +9,17 @@
|
|||
import moment from 'moment';
|
||||
import { ToolingLog } from '@kbn/tooling-log';
|
||||
import dedent from 'dedent';
|
||||
import fs from 'fs';
|
||||
import Fsp from 'fs/promises';
|
||||
import Path from 'path';
|
||||
import { ApiDeclaration, ApiReference, ReferencedDeprecationsByPlugin } from '../types';
|
||||
import { AUTO_GENERATED_WARNING } from '../auto_generated_warning';
|
||||
import { getPluginApiDocId } from '../utils';
|
||||
|
||||
export function writeDeprecationDocByPlugin(
|
||||
export async function writeDeprecationDocByPlugin(
|
||||
folder: string,
|
||||
deprecationsByPlugin: ReferencedDeprecationsByPlugin,
|
||||
log: ToolingLog
|
||||
): void {
|
||||
): Promise<void> {
|
||||
const tableMdx = Object.keys(deprecationsByPlugin)
|
||||
.sort()
|
||||
.map((key) => {
|
||||
|
@ -54,7 +54,7 @@ export function writeDeprecationDocByPlugin(
|
|||
(ref) =>
|
||||
`[${ref.path.substr(
|
||||
ref.path.lastIndexOf(Path.sep) + 1
|
||||
)}](https://github.com/elastic/kibana/tree/master/${
|
||||
)}](https://github.com/elastic/kibana/tree/main/${
|
||||
ref.path
|
||||
}#:~:text=${encodeURIComponent(api.label)})`
|
||||
)
|
||||
|
@ -84,5 +84,5 @@ ${tableMdx}
|
|||
|
||||
`);
|
||||
|
||||
fs.writeFileSync(Path.resolve(folder, 'deprecations_by_plugin.mdx'), mdx);
|
||||
await Fsp.writeFile(Path.resolve(folder, 'deprecations_by_plugin.mdx'), mdx);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import moment from 'moment';
|
||||
import { ToolingLog } from '@kbn/tooling-log';
|
||||
import dedent from 'dedent';
|
||||
import fs from 'fs';
|
||||
import Fsp from 'fs/promises';
|
||||
import Path from 'path';
|
||||
import {
|
||||
ApiDeclaration,
|
||||
|
@ -19,12 +19,12 @@ import {
|
|||
import { AUTO_GENERATED_WARNING } from '../auto_generated_warning';
|
||||
import { getPluginApiDocId } from '../utils';
|
||||
|
||||
export function writeDeprecationDueByTeam(
|
||||
export async function writeDeprecationDueByTeam(
|
||||
folder: string,
|
||||
deprecationsByPlugin: ReferencedDeprecationsByPlugin,
|
||||
plugins: PluginOrPackage[],
|
||||
log: ToolingLog
|
||||
): void {
|
||||
): Promise<void> {
|
||||
const groupedByTeam: ReferencedDeprecationsByPlugin = Object.keys(deprecationsByPlugin).reduce(
|
||||
(teamMap: ReferencedDeprecationsByPlugin, pluginId: string) => {
|
||||
const dueDeprecations = deprecationsByPlugin[pluginId].filter(
|
||||
|
@ -80,7 +80,7 @@ export function writeDeprecationDueByTeam(
|
|||
(ref) =>
|
||||
`[${ref.path.substr(
|
||||
ref.path.lastIndexOf(Path.sep) + 1
|
||||
)}](https://github.com/elastic/kibana/tree/master/${
|
||||
)}](https://github.com/elastic/kibana/tree/main/${
|
||||
ref.path
|
||||
}#:~:text=${encodeURIComponent(api.label)})`
|
||||
)
|
||||
|
@ -111,5 +111,5 @@ ${tableMdx}
|
|||
|
||||
`);
|
||||
|
||||
fs.writeFileSync(Path.resolve(folder, 'deprecations_by_team.mdx'), mdx);
|
||||
await Fsp.writeFile(Path.resolve(folder, 'deprecations_by_team.mdx'), mdx);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
import moment from 'moment';
|
||||
import fs from 'fs';
|
||||
import Fsp from 'fs/promises';
|
||||
import Path from 'path';
|
||||
import dedent from 'dedent';
|
||||
import { ToolingLog } from '@kbn/tooling-log';
|
||||
|
@ -31,12 +31,12 @@ interface TotalStats {
|
|||
/**
|
||||
* @param folder The location the mdx file will be written too.
|
||||
*/
|
||||
export function writePluginDirectoryDoc(
|
||||
export async function writePluginDirectoryDoc(
|
||||
folder: string,
|
||||
pluginApiMap: { [key: string]: PluginApi },
|
||||
pluginStatsMap: { [key: string]: PluginMetaInfo },
|
||||
log: ToolingLog
|
||||
): void {
|
||||
): Promise<void> {
|
||||
log.debug(`Writing plugin directory file`);
|
||||
|
||||
const uniqueTeams: string[] = [];
|
||||
|
@ -112,7 +112,7 @@ ${getDirectoryTable(pluginApiMap, pluginStatsMap, false)}
|
|||
|
||||
`) + '\n\n';
|
||||
|
||||
fs.writeFileSync(Path.resolve(folder, 'plugin_directory.mdx'), mdx);
|
||||
await Fsp.writeFile(Path.resolve(folder, 'plugin_directory.mdx'), mdx);
|
||||
}
|
||||
|
||||
function getDirectoryTable(
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
import moment from 'moment';
|
||||
import fs from 'fs';
|
||||
import Fsp from 'fs/promises';
|
||||
import Path from 'path';
|
||||
import dedent from 'dedent';
|
||||
import { PluginApi, ScopeApi } from '../types';
|
||||
|
@ -30,15 +30,15 @@ import { WritePluginDocsOpts } from './types';
|
|||
* @param doc Contains the information of the plugin that will be written into mdx.
|
||||
* @param log Used for logging debug and error information.
|
||||
*/
|
||||
export function writePluginDocs(
|
||||
export async function writePluginDocs(
|
||||
folder: string,
|
||||
{ doc, plugin, pluginStats, log }: WritePluginDocsOpts
|
||||
): void {
|
||||
): Promise<void> {
|
||||
if (doc.serviceFolders) {
|
||||
log.debug(`Splitting plugin ${doc.id}`);
|
||||
writePluginDocSplitByFolder(folder, { doc, log, plugin, pluginStats });
|
||||
await writePluginDocSplitByFolder(folder, { doc, log, plugin, pluginStats });
|
||||
} else {
|
||||
writePluginDoc(folder, { doc, plugin, pluginStats, log });
|
||||
await writePluginDoc(folder, { doc, plugin, pluginStats, log });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,10 +55,10 @@ function hasPublicApi(doc: PluginApi): boolean {
|
|||
* @param doc Contains the information of the plugin that will be written into mdx.
|
||||
* @param log Used for logging debug and error information.
|
||||
*/
|
||||
export function writePluginDoc(
|
||||
export async function writePluginDoc(
|
||||
folder: string,
|
||||
{ doc, log, plugin, pluginStats }: WritePluginDocsOpts
|
||||
): void {
|
||||
): Promise<void> {
|
||||
if (!hasPublicApi(doc)) {
|
||||
log.debug(`${doc.id} does not have a public api. Skipping.`);
|
||||
return;
|
||||
|
@ -113,7 +113,7 @@ ${
|
|||
common: groupPluginApi(doc.common),
|
||||
server: groupPluginApi(doc.server),
|
||||
};
|
||||
fs.writeFileSync(
|
||||
await Fsp.writeFile(
|
||||
Path.resolve(folder, fileName + '.devdocs.json'),
|
||||
JSON.stringify(scopedDoc, null, 2)
|
||||
);
|
||||
|
@ -122,7 +122,7 @@ ${
|
|||
mdx += scopApiToMdx(scopedDoc.server, 'Server', json, 'server');
|
||||
mdx += scopApiToMdx(scopedDoc.common, 'Common', json, 'common');
|
||||
|
||||
fs.writeFileSync(Path.resolve(folder, fileName + '.mdx'), mdx);
|
||||
await Fsp.writeFile(Path.resolve(folder, fileName + '.mdx'), mdx);
|
||||
}
|
||||
|
||||
function getJsonName(name: string): string {
|
||||
|
|
|
@ -10,7 +10,7 @@ import { Project } from 'ts-morph';
|
|||
import { ToolingLog } from '@kbn/tooling-log';
|
||||
import { splitApisByFolder } from './write_plugin_split_by_folder';
|
||||
import { getPluginApi } from '../get_plugin_api';
|
||||
import { getKibanaPlatformPlugin } from '../tests/kibana_platform_plugin_mock';
|
||||
import { getKibanaPlatformPlugin } from '../integration_tests/kibana_platform_plugin_mock';
|
||||
import { PluginOrPackage } from '../types';
|
||||
|
||||
const log = new ToolingLog({
|
||||
|
|
|
@ -6,22 +6,28 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { asyncForEachWithLimit } from '@kbn/std';
|
||||
import { snakeToCamel } from '../utils';
|
||||
import { PluginApi, ApiDeclaration } from '../types';
|
||||
import { writePluginDoc } from './write_plugin_mdx_docs';
|
||||
import { WritePluginDocsOpts } from './types';
|
||||
|
||||
export function writePluginDocSplitByFolder(
|
||||
// There is no science behind this 10.
|
||||
// When it was first introduced, it was using synchronous APIs, so the concurrency was 1.
|
||||
// Feel free to adapt it when more data is gathered.
|
||||
const CONCURRENT_WRITES = 10;
|
||||
|
||||
export async function writePluginDocSplitByFolder(
|
||||
folder: string,
|
||||
{ doc, plugin, pluginStats, log }: WritePluginDocsOpts
|
||||
) {
|
||||
const apisByFolder = splitApisByFolder(doc);
|
||||
|
||||
log.debug(`Split ${doc.id} into ${apisByFolder.length} services`);
|
||||
apisByFolder.forEach((docDef) => {
|
||||
await asyncForEachWithLimit(apisByFolder, CONCURRENT_WRITES, async (docDef) => {
|
||||
// TODO: we should probably see if we can break down these stats by service folder. As it is, they will represent stats for
|
||||
// the entire plugin.
|
||||
writePluginDoc(folder, { doc: docDef, plugin, pluginStats, log });
|
||||
await writePluginDoc(folder, { doc: docDef, plugin, pluginStats, log });
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -7,18 +7,20 @@
|
|||
*/
|
||||
|
||||
import {
|
||||
ApiDeclaration,
|
||||
ApiStats,
|
||||
MissingApiItemMap,
|
||||
PluginApi,
|
||||
ReferencedDeprecationsByPlugin,
|
||||
type AdoptionTrackedAPIsByPlugin,
|
||||
type ApiDeclaration,
|
||||
type ApiStats,
|
||||
type MissingApiItemMap,
|
||||
type PluginApi,
|
||||
type ReferencedDeprecationsByPlugin,
|
||||
TypeKind,
|
||||
} from './types';
|
||||
|
||||
export function collectApiStatsForPlugin(
|
||||
doc: PluginApi,
|
||||
missingApiItems: MissingApiItemMap,
|
||||
deprecations: ReferencedDeprecationsByPlugin
|
||||
deprecations: ReferencedDeprecationsByPlugin,
|
||||
adoptionTrackedAPIs: AdoptionTrackedAPIsByPlugin
|
||||
): ApiStats {
|
||||
const stats: ApiStats = {
|
||||
missingComments: [],
|
||||
|
@ -26,6 +28,9 @@ export function collectApiStatsForPlugin(
|
|||
noReferences: [],
|
||||
deprecatedAPIsReferencedCount: 0,
|
||||
unreferencedDeprecatedApisCount: 0,
|
||||
adoptionTrackedAPIs: [],
|
||||
adoptionTrackedAPIsCount: 0,
|
||||
adoptionTrackedAPIsUnreferencedCount: 0,
|
||||
apiCount: countApiForPlugin(doc),
|
||||
missingExports: Object.values(missingApiItems[doc.id] ?? {}).length,
|
||||
};
|
||||
|
@ -39,9 +44,24 @@ export function collectApiStatsForPlugin(
|
|||
collectStatsForApi(def, stats, doc);
|
||||
});
|
||||
stats.deprecatedAPIsReferencedCount = deprecations[doc.id] ? deprecations[doc.id].length : 0;
|
||||
|
||||
collectAdoptionTrackedAPIStats(doc, stats, adoptionTrackedAPIs);
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
function collectAdoptionTrackedAPIStats(
|
||||
doc: PluginApi,
|
||||
stats: ApiStats,
|
||||
adoptionTrackedAPIs: AdoptionTrackedAPIsByPlugin
|
||||
) {
|
||||
stats.adoptionTrackedAPIs = adoptionTrackedAPIs[doc.id] || [];
|
||||
stats.adoptionTrackedAPIsCount = stats.adoptionTrackedAPIs.length;
|
||||
stats.adoptionTrackedAPIsUnreferencedCount = stats.adoptionTrackedAPIs.filter(
|
||||
({ references }) => references.length === 0
|
||||
).length;
|
||||
}
|
||||
|
||||
function collectStatsForApi(doc: ApiDeclaration, stats: ApiStats, pluginApi: PluginApi): void {
|
||||
const missingComment = doc.description === undefined || doc.description.length === 0;
|
||||
// Ignore all stats coming from third party libraries, we can't fix that!
|
||||
|
|
|
@ -198,6 +198,11 @@ export interface ApiDeclaration {
|
|||
* Is this API deprecated or not?
|
||||
*/
|
||||
deprecated?: boolean;
|
||||
|
||||
/**
|
||||
* Are we interested in tracking adoption of this API?
|
||||
*/
|
||||
trackAdoption?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -234,7 +239,7 @@ export interface ReferencedDeprecationsByPlugin {
|
|||
[key: string]: Array<{ deprecatedApi: ApiDeclaration; ref: ApiReference }>;
|
||||
}
|
||||
|
||||
// A mapping of plugin owner to it's plugin deprecation list.
|
||||
// A mapping of plugin owner to its plugin deprecation list.
|
||||
export interface ReferencedDeprecationsByTeam {
|
||||
// Key is the plugin owner.
|
||||
[key: string]: ReferencedDeprecationsByPlugin;
|
||||
|
@ -245,6 +250,23 @@ export interface UnreferencedDeprecationsByPlugin {
|
|||
[key: string]: ApiDeclaration[];
|
||||
}
|
||||
|
||||
export interface AdoptionTrackedAPIStats {
|
||||
/**
|
||||
* Minimal identifiers for the tracked API.
|
||||
*/
|
||||
trackedApi: { id: string; label: string };
|
||||
/**
|
||||
* List of plugins where the API is used. For stats that is more than enough.
|
||||
*/
|
||||
references: string[];
|
||||
}
|
||||
|
||||
// A mapping of plugin id to a list of every deprecated API it uses, and where it's referenced.
|
||||
export interface AdoptionTrackedAPIsByPlugin {
|
||||
// Key is the plugin id.
|
||||
[key: string]: AdoptionTrackedAPIStats[];
|
||||
}
|
||||
|
||||
// A mapping of deprecated API id to the places that are still referencing it.
|
||||
export interface ReferencedDeprecationsByAPI {
|
||||
[key: string]: { deprecatedApi: ApiDeclaration; references: ApiReference[] };
|
||||
|
@ -258,6 +280,15 @@ export interface ApiStats {
|
|||
missingExports: number;
|
||||
deprecatedAPIsReferencedCount: number;
|
||||
unreferencedDeprecatedApisCount: number;
|
||||
adoptionTrackedAPIs: AdoptionTrackedAPIStats[];
|
||||
/**
|
||||
* Total number of APIs that the plugin wants to track the adoption for.
|
||||
*/
|
||||
adoptionTrackedAPIsCount: number;
|
||||
/**
|
||||
* Number of adoption-tracked APIs that are still not referenced.
|
||||
*/
|
||||
adoptionTrackedAPIsUnreferencedCount: number;
|
||||
}
|
||||
|
||||
export type PluginMetaInfo = ApiStats & {
|
||||
|
|
|
@ -11,7 +11,7 @@ import Path from 'path';
|
|||
import { Project } from 'ts-morph';
|
||||
import { findPlugins } from './find_plugins';
|
||||
import { getPluginApi } from './get_plugin_api';
|
||||
import { getKibanaPlatformPlugin } from './tests/kibana_platform_plugin_mock';
|
||||
import { getKibanaPlatformPlugin } from './integration_tests/kibana_platform_plugin_mock';
|
||||
import { PluginApi, PluginOrPackage } from './types';
|
||||
import { getPluginForPath, getServiceForPath, removeBrokenLinks, getFileName } from './utils';
|
||||
|
||||
|
@ -53,14 +53,17 @@ it('test getServiceForPath', () => {
|
|||
|
||||
expect(
|
||||
getServiceForPath(
|
||||
'/var/lib/jenkins/workspace/elastic+kibana+pipeline-pull-request/kibana/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/foo/index',
|
||||
'/var/lib/jenkins/workspace/elastic+kibana+pipeline-pull-request/kibana/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a'
|
||||
'/var/lib/jenkins/workspace/elastic+kibana+pipeline-pull-request/kibana/packages/kbn-docs-utils/src/api_docs/integration_tests/__fixtures__/src/plugin_a/public/foo/index',
|
||||
'/var/lib/jenkins/workspace/elastic+kibana+pipeline-pull-request/kibana/packages/kbn-docs-utils/src/api_docs/integration_tests/__fixtures__/src/plugin_a'
|
||||
)
|
||||
).toBe('foo');
|
||||
});
|
||||
|
||||
it('test removeBrokenLinks', () => {
|
||||
const tsConfigFilePath = Path.resolve(__dirname, 'tests/__fixtures__/src/tsconfig.json');
|
||||
const tsConfigFilePath = Path.resolve(
|
||||
__dirname,
|
||||
'integration_tests/__fixtures__/src/tsconfig.json'
|
||||
);
|
||||
const project = new Project({
|
||||
tsConfigFilePath,
|
||||
});
|
||||
|
|
|
@ -81,6 +81,8 @@ export interface TelemetryPluginStart {
|
|||
* Resolves `true` if the user has opted into send Elastic usage data.
|
||||
* Resolves `false` if the user explicitly opted out of sending usage data to Elastic
|
||||
* or did not choose to opt-in or out -yet- after a minor or major upgrade (only when previously opted-out).
|
||||
*
|
||||
* @track-adoption
|
||||
*/
|
||||
getIsOptedIn: () => Promise<boolean>;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue