mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[scout] fix playwright configs discovery script and add save
flag for CI (#213147)
## Summary This PR fixes the search logic to look for playwright configs in all possible & expected locations (`src/*` was not working), matching one of 3 regexp: ``` /(x-pack\/platform\/plugins\/(?:private|shared|[^\/]+)\/([^\/]+))\/ui_tests\//, /(x-pack\/solutions\/[^\/]+\/plugins\/([^\/]+))\/ui_tests\//, /(src\/platform\/plugins\/(?:private|shared)?\/?([^\/]+))\/ui_tests\//, ``` For each plugin we also have `usesParallelWorkers` prop (`true` if at least 1 config runs with concurrent workers) to decide later, if we need worker with 4 or 8 VCPUs. The idea is to run `node scripts/scout discover-playwright-configs --save` on CI and use generated json as source to build test run pipeline. Current output: ``` { "discover_enhanced": { "group": "platform", "pluginPath": "x-pack/platform/plugins/private/discover_enhanced", "configs": [ "x-pack/platform/plugins/private/discover_enhanced/ui_tests/parallel.playwright.config.ts", "x-pack/platform/plugins/private/discover_enhanced/ui_tests/playwright.config.ts" ], "usesParallelWorkers": true }, "maps": { "group": "platform", "pluginPath": "x-pack/platform/plugins/shared/maps", "configs": [ "x-pack/platform/plugins/shared/maps/ui_tests/playwright.config.ts" ], "usesParallelWorkers": false }, "observability_onboarding": { "group": "observability", "pluginPath": "x-pack/solutions/observability/plugins/observability_onboarding", "configs": [ "x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/parallel.playwright.config.ts", "x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/playwright.config.ts" ], "usesParallelWorkers": true } } ```
This commit is contained in:
parent
75f9c6113d
commit
1e3bb05734
3 changed files with 107 additions and 34 deletions
|
@ -7,7 +7,10 @@
|
||||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import fs from 'fs';
|
||||||
import { Command } from '@kbn/dev-cli-runner';
|
import { Command } from '@kbn/dev-cli-runner';
|
||||||
|
import { SCOUT_OUTPUT_ROOT } from '@kbn/scout-info';
|
||||||
|
import { resolve } from 'path';
|
||||||
import { getScoutPlaywrightConfigs, DEFAULT_TEST_PATH_PATTERNS } from '../config';
|
import { getScoutPlaywrightConfigs, DEFAULT_TEST_PATH_PATTERNS } from '../config';
|
||||||
import { measurePerformance } from '../common';
|
import { measurePerformance } from '../common';
|
||||||
|
|
||||||
|
@ -21,29 +24,41 @@ export const discoverPlaywrightConfigs: Command<void> = {
|
||||||
|
|
||||||
Common usage:
|
Common usage:
|
||||||
node scripts/scout discover-playwright-configs --searchPaths <search_paths>
|
node scripts/scout discover-playwright-configs --searchPaths <search_paths>
|
||||||
|
node scripts/scout discover-playwright-configs --save
|
||||||
node scripts/scout discover-playwright-configs
|
node scripts/scout discover-playwright-configs
|
||||||
`,
|
`,
|
||||||
flags: {
|
flags: {
|
||||||
string: ['searchPaths'],
|
string: ['searchPaths'],
|
||||||
default: { searchPaths: DEFAULT_TEST_PATH_PATTERNS },
|
boolean: ['save'],
|
||||||
|
default: { searchPaths: DEFAULT_TEST_PATH_PATTERNS, save: false },
|
||||||
},
|
},
|
||||||
run: ({ flagsReader, log }) => {
|
run: ({ flagsReader, log }) => {
|
||||||
const searchPaths = flagsReader.arrayOfStrings('searchPaths')!;
|
const searchPaths = flagsReader.arrayOfStrings('searchPaths')!;
|
||||||
|
|
||||||
const plugins = measurePerformance(log, 'Discovering playwright config files', () => {
|
const pluginsMap = measurePerformance(log, 'Discovering playwright config files', () => {
|
||||||
return getScoutPlaywrightConfigs(searchPaths, log);
|
return getScoutPlaywrightConfigs(searchPaths, log);
|
||||||
});
|
});
|
||||||
|
|
||||||
const finalMessage =
|
const finalMessage =
|
||||||
plugins.size === 0
|
pluginsMap.size === 0
|
||||||
? 'No playwright config files found'
|
? 'No Playwright config files found'
|
||||||
: `Found playwright config files in '${plugins.size}' plugins`;
|
: `Found Playwright config files in '${pluginsMap.size}' plugins`;
|
||||||
|
|
||||||
|
if (pluginsMap.size > 0 && flagsReader.boolean('save')) {
|
||||||
|
const scoutConfigsFilePath = resolve(SCOUT_OUTPUT_ROOT, 'scout_playwright_configs.json');
|
||||||
|
fs.writeFileSync(
|
||||||
|
scoutConfigsFilePath,
|
||||||
|
JSON.stringify(Object.fromEntries(pluginsMap), null, 2)
|
||||||
|
);
|
||||||
|
log.info(`${finalMessage}. Saved to '${scoutConfigsFilePath}'`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
log.info(finalMessage);
|
log.info(finalMessage);
|
||||||
|
|
||||||
plugins.forEach((files, plugin) => {
|
pluginsMap.forEach((data, plugin) => {
|
||||||
log.info(`[${plugin}] plugin:`);
|
log.info(`${data.group} / [${plugin}] plugin:`);
|
||||||
files.forEach((file) => {
|
data.configs.map((file) => {
|
||||||
log.info(`- ${file}`);
|
log.info(`- ${file}`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -35,21 +35,36 @@ describe('getScoutPlaywrightConfigs', () => {
|
||||||
|
|
||||||
it('should correctly extract plugin names and group config files', () => {
|
it('should correctly extract plugin names and group config files', () => {
|
||||||
(fastGlob.sync as jest.Mock).mockReturnValue([
|
(fastGlob.sync as jest.Mock).mockReturnValue([
|
||||||
'x-pack/platform/plugins/plugin_a/ui_tests/playwright.config.ts',
|
'x-pack/platform/plugins/private/plugin_a/ui_tests/playwright.config.ts',
|
||||||
'x-pack/platform/plugins/plugin_a/ui_tests/parallel.playwright.config.ts',
|
'x-pack/platform/plugins/private/plugin_a/ui_tests/parallel.playwright.config.ts',
|
||||||
'x-pack/solutions/security/plugins/plugin_b/ui_tests/playwright.config.ts',
|
'x-pack/solutions/security/plugins/plugin_b/ui_tests/playwright.config.ts',
|
||||||
|
'src/platform/plugins/shared/plugin_c/ui_tests/playwright.config.ts',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const plugins = getScoutPlaywrightConfigs(['x-pack/'], mockLog);
|
const plugins = getScoutPlaywrightConfigs(['x-pack/', 'src/'], mockLog);
|
||||||
|
|
||||||
expect(plugins.size).toBe(2);
|
expect(plugins.size).toBe(3);
|
||||||
expect(plugins.get('plugin_a')).toEqual([
|
expect(plugins.get('plugin_a')).toEqual({
|
||||||
'x-pack/platform/plugins/plugin_a/ui_tests/playwright.config.ts',
|
configs: [
|
||||||
'x-pack/platform/plugins/plugin_a/ui_tests/parallel.playwright.config.ts',
|
'x-pack/platform/plugins/private/plugin_a/ui_tests/playwright.config.ts',
|
||||||
]);
|
'x-pack/platform/plugins/private/plugin_a/ui_tests/parallel.playwright.config.ts',
|
||||||
expect(plugins.get('plugin_b')).toEqual([
|
],
|
||||||
'x-pack/solutions/security/plugins/plugin_b/ui_tests/playwright.config.ts',
|
usesParallelWorkers: true,
|
||||||
]);
|
group: 'platform',
|
||||||
|
pluginPath: 'x-pack/platform/plugins/private/plugin_a',
|
||||||
|
});
|
||||||
|
expect(plugins.get('plugin_b')).toEqual({
|
||||||
|
configs: ['x-pack/solutions/security/plugins/plugin_b/ui_tests/playwright.config.ts'],
|
||||||
|
usesParallelWorkers: false,
|
||||||
|
group: 'security',
|
||||||
|
pluginPath: 'x-pack/solutions/security/plugins/plugin_b',
|
||||||
|
});
|
||||||
|
expect(plugins.get('plugin_c')).toEqual({
|
||||||
|
configs: ['src/platform/plugins/shared/plugin_c/ui_tests/playwright.config.ts'],
|
||||||
|
usesParallelWorkers: false,
|
||||||
|
group: 'platform',
|
||||||
|
pluginPath: 'src/platform/plugins/shared/plugin_c',
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should log a warning if a file path does not match the expected pattern', () => {
|
it('should log a warning if a file path does not match the expected pattern', () => {
|
||||||
|
|
|
@ -13,35 +13,78 @@ import { ToolingLog } from '@kbn/tooling-log';
|
||||||
|
|
||||||
export const DEFAULT_TEST_PATH_PATTERNS = ['src/platform/plugins', 'x-pack/**/plugins'];
|
export const DEFAULT_TEST_PATH_PATTERNS = ['src/platform/plugins', 'x-pack/**/plugins'];
|
||||||
|
|
||||||
|
interface PluginScoutConfig {
|
||||||
|
group: string;
|
||||||
|
pluginPath: string;
|
||||||
|
usesParallelWorkers: boolean;
|
||||||
|
configs: string[];
|
||||||
|
}
|
||||||
|
|
||||||
export const getScoutPlaywrightConfigs = (searchPaths: string[], log: ToolingLog) => {
|
export const getScoutPlaywrightConfigs = (searchPaths: string[], log: ToolingLog) => {
|
||||||
const patterns = searchPaths.map((basePath) =>
|
const patterns = searchPaths.map((basePath) =>
|
||||||
path.join(basePath, '**/ui_tests/{playwright.config.ts,parallel.playwright.config.ts}')
|
path.join(basePath, '**/ui_tests/{playwright.config.ts,parallel.playwright.config.ts}')
|
||||||
);
|
);
|
||||||
|
|
||||||
log.info('Searching for playwright config files in the following paths:');
|
log.info('Searching for Playwright config files in the following paths:');
|
||||||
patterns.forEach((pattern) => log.info(`- ${pattern}`));
|
patterns.forEach((pattern) => log.info(`- ${pattern}`));
|
||||||
log.info(''); // Add a newline for better readability
|
log.info(''); // Add a newline for better readability
|
||||||
|
|
||||||
const files = patterns.flatMap((pattern) => fastGlob.sync(pattern, { onlyFiles: true }));
|
const files = patterns.flatMap((pattern) => fastGlob.sync(pattern, { onlyFiles: true }));
|
||||||
|
|
||||||
// Group config files by plugin
|
const typeMappings: Record<string, string> = {
|
||||||
const plugins = files.reduce((acc: Map<string, string[]>, filePath: string) => {
|
'x-pack/solutions/security': 'security',
|
||||||
const match = filePath.match(
|
'x-pack/solutions/search': 'search',
|
||||||
/(?:src\/platform\/plugins|x-pack\/.*?\/plugins)\/(?:.*?\/)?([^\/]+)\/ui_tests\//
|
'x-pack/solutions/observability': 'observability',
|
||||||
);
|
'x-pack/platform/plugins': 'platform',
|
||||||
const pluginName = match ? match[1] : null;
|
'src/platform/plugins': 'platform',
|
||||||
|
};
|
||||||
|
|
||||||
if (pluginName) {
|
const matchPluginPath = (filePath: string): { pluginPath: string; pluginName: string } | null => {
|
||||||
if (!acc.has(pluginName)) {
|
const regexes = [
|
||||||
acc.set(pluginName, []);
|
/(x-pack\/platform\/plugins\/(?:private|shared|[^\/]+)\/([^\/]+))\/ui_tests\//,
|
||||||
|
/(x-pack\/solutions\/[^\/]+\/plugins\/([^\/]+))\/ui_tests\//,
|
||||||
|
/(src\/platform\/plugins\/(?:private|shared)?\/?([^\/]+))\/ui_tests\//,
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const regex of regexes) {
|
||||||
|
const match = filePath.match(regex);
|
||||||
|
if (match) {
|
||||||
|
return { pluginPath: match[1], pluginName: match[2] };
|
||||||
}
|
}
|
||||||
acc.get(pluginName)!.push(filePath);
|
}
|
||||||
} else {
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const pluginsWithConfigs = new Map<string, PluginScoutConfig>();
|
||||||
|
|
||||||
|
files.forEach((filePath) => {
|
||||||
|
const matchResult = matchPluginPath(filePath);
|
||||||
|
if (!matchResult) {
|
||||||
log.warning(`Unable to extract plugin name from path: ${filePath}`);
|
log.warning(`Unable to extract plugin name from path: ${filePath}`);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return acc;
|
const { pluginPath, pluginName } = matchResult;
|
||||||
}, new Map<string, string[]>());
|
const group =
|
||||||
|
Object.entries(typeMappings).find(([key]) => filePath.includes(key))?.[1] || 'unknown';
|
||||||
|
|
||||||
return plugins;
|
if (!pluginsWithConfigs.has(pluginName)) {
|
||||||
|
pluginsWithConfigs.set(pluginName, {
|
||||||
|
group,
|
||||||
|
pluginPath,
|
||||||
|
configs: [],
|
||||||
|
usesParallelWorkers: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const pluginData = pluginsWithConfigs.get(pluginName)!;
|
||||||
|
if (!pluginData.configs.includes(filePath)) {
|
||||||
|
pluginData.configs.push(filePath);
|
||||||
|
if (filePath.endsWith('parallel.playwright.config.ts')) {
|
||||||
|
pluginData.usesParallelWorkers = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return pluginsWithConfigs;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue