Skip to content

Commit

Permalink
[9.0] [scout] fix playwright configs discovery script and add save
Browse files Browse the repository at this point in the history
…flag for CI (#213147) (#213242)

# Backport

This will backport the following commits from `main` to `9.0`:
- [[scout] fix playwright configs discovery script and add `save` flag
for CI (#213147)](#213147)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Dzmitry
Lemechko","email":"dzmitry.lemechko@elastic.co"},"sourceCommit":{"committedDate":"2025-03-05T13:49:43Z","message":"[scout]
fix playwright configs discovery script and add `save` flag for CI
(#213147)\n\n## Summary\n\nThis PR fixes the search logic to look for
playwright configs in all\npossible & expected locations (`src/*` was
not working), matching one of\n3 regexp:\n```\n
/(x-pack\\/platform\\/plugins\\/(?:private|shared|[^\\/]+)\\/([^\\/]+))\\/ui_tests\\//,\n
/(x-pack\\/solutions\\/[^\\/]+\\/plugins\\/([^\\/]+))\\/ui_tests\\//,\n
/(src\\/platform\\/plugins\\/(?:private|shared)?\\/?([^\\/]+))\\/ui_tests\\//,\n```\n\nFor
each plugin we also have `usesParallelWorkers` prop (`true` if at\nleast
1 config runs with concurrent workers) to decide later, if we
need\nworker with 4 or 8 VCPUs.\n\nThe idea is to run `node
scripts/scout discover-playwright-configs\n--save` on CI and use
generated json as source to build test run\npipeline.\n\nCurrent
output:\n\n```\n{\n \"discover_enhanced\": {\n \"group\":
\"platform\",\n \"pluginPath\":
\"x-pack/platform/plugins/private/discover_enhanced\",\n \"configs\":
[\n
\"x-pack/platform/plugins/private/discover_enhanced/ui_tests/parallel.playwright.config.ts\",\n
\"x-pack/platform/plugins/private/discover_enhanced/ui_tests/playwright.config.ts\"\n
],\n \"usesParallelWorkers\": true\n },\n \"maps\": {\n \"group\":
\"platform\",\n \"pluginPath\":
\"x-pack/platform/plugins/shared/maps\",\n \"configs\": [\n
\"x-pack/platform/plugins/shared/maps/ui_tests/playwright.config.ts\"\n
],\n \"usesParallelWorkers\": false\n },\n \"observability_onboarding\":
{\n \"group\": \"observability\",\n \"pluginPath\":
\"x-pack/solutions/observability/plugins/observability_onboarding\",\n
\"configs\": [\n
\"x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/parallel.playwright.config.ts\",\n
\"x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/playwright.config.ts\"\n
],\n \"usesParallelWorkers\": true\n
}\n}\n```","sha":"1e3bb05734ed5825df802fb32a31b3c07106bee4","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","backport:version","test:scout","v9.1.0","v8.19.0"],"title":"[scout]
fix playwright configs discovery script and add `save` flag for
CI","number":213147,"url":"https://github.com/elastic/kibana/pull/213147","mergeCommit":{"message":"[scout]
fix playwright configs discovery script and add `save` flag for CI
(#213147)\n\n## Summary\n\nThis PR fixes the search logic to look for
playwright configs in all\npossible & expected locations (`src/*` was
not working), matching one of\n3 regexp:\n```\n
/(x-pack\\/platform\\/plugins\\/(?:private|shared|[^\\/]+)\\/([^\\/]+))\\/ui_tests\\//,\n
/(x-pack\\/solutions\\/[^\\/]+\\/plugins\\/([^\\/]+))\\/ui_tests\\//,\n
/(src\\/platform\\/plugins\\/(?:private|shared)?\\/?([^\\/]+))\\/ui_tests\\//,\n```\n\nFor
each plugin we also have `usesParallelWorkers` prop (`true` if at\nleast
1 config runs with concurrent workers) to decide later, if we
need\nworker with 4 or 8 VCPUs.\n\nThe idea is to run `node
scripts/scout discover-playwright-configs\n--save` on CI and use
generated json as source to build test run\npipeline.\n\nCurrent
output:\n\n```\n{\n \"discover_enhanced\": {\n \"group\":
\"platform\",\n \"pluginPath\":
\"x-pack/platform/plugins/private/discover_enhanced\",\n \"configs\":
[\n
\"x-pack/platform/plugins/private/discover_enhanced/ui_tests/parallel.playwright.config.ts\",\n
\"x-pack/platform/plugins/private/discover_enhanced/ui_tests/playwright.config.ts\"\n
],\n \"usesParallelWorkers\": true\n },\n \"maps\": {\n \"group\":
\"platform\",\n \"pluginPath\":
\"x-pack/platform/plugins/shared/maps\",\n \"configs\": [\n
\"x-pack/platform/plugins/shared/maps/ui_tests/playwright.config.ts\"\n
],\n \"usesParallelWorkers\": false\n },\n \"observability_onboarding\":
{\n \"group\": \"observability\",\n \"pluginPath\":
\"x-pack/solutions/observability/plugins/observability_onboarding\",\n
\"configs\": [\n
\"x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/parallel.playwright.config.ts\",\n
\"x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/playwright.config.ts\"\n
],\n \"usesParallelWorkers\": true\n
}\n}\n```","sha":"1e3bb05734ed5825df802fb32a31b3c07106bee4"}},"sourceBranch":"main","suggestedTargetBranches":["9.0","8.x"],"targetPullRequestStates":[{"branch":"9.0","label":"v9.0.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/213147","number":213147,"mergeCommit":{"message":"[scout]
fix playwright configs discovery script and add `save` flag for CI
(#213147)\n\n## Summary\n\nThis PR fixes the search logic to look for
playwright configs in all\npossible & expected locations (`src/*` was
not working), matching one of\n3 regexp:\n```\n
/(x-pack\\/platform\\/plugins\\/(?:private|shared|[^\\/]+)\\/([^\\/]+))\\/ui_tests\\//,\n
/(x-pack\\/solutions\\/[^\\/]+\\/plugins\\/([^\\/]+))\\/ui_tests\\//,\n
/(src\\/platform\\/plugins\\/(?:private|shared)?\\/?([^\\/]+))\\/ui_tests\\//,\n```\n\nFor
each plugin we also have `usesParallelWorkers` prop (`true` if at\nleast
1 config runs with concurrent workers) to decide later, if we
need\nworker with 4 or 8 VCPUs.\n\nThe idea is to run `node
scripts/scout discover-playwright-configs\n--save` on CI and use
generated json as source to build test run\npipeline.\n\nCurrent
output:\n\n```\n{\n \"discover_enhanced\": {\n \"group\":
\"platform\",\n \"pluginPath\":
\"x-pack/platform/plugins/private/discover_enhanced\",\n \"configs\":
[\n
\"x-pack/platform/plugins/private/discover_enhanced/ui_tests/parallel.playwright.config.ts\",\n
\"x-pack/platform/plugins/private/discover_enhanced/ui_tests/playwright.config.ts\"\n
],\n \"usesParallelWorkers\": true\n },\n \"maps\": {\n \"group\":
\"platform\",\n \"pluginPath\":
\"x-pack/platform/plugins/shared/maps\",\n \"configs\": [\n
\"x-pack/platform/plugins/shared/maps/ui_tests/playwright.config.ts\"\n
],\n \"usesParallelWorkers\": false\n },\n \"observability_onboarding\":
{\n \"group\": \"observability\",\n \"pluginPath\":
\"x-pack/solutions/observability/plugins/observability_onboarding\",\n
\"configs\": [\n
\"x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/parallel.playwright.config.ts\",\n
\"x-pack/solutions/observability/plugins/observability_onboarding/ui_tests/playwright.config.ts\"\n
],\n \"usesParallelWorkers\": true\n
}\n}\n```","sha":"1e3bb05734ed5825df802fb32a31b3c07106bee4"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Dzmitry Lemechko <dzmitry.lemechko@elastic.co>
  • Loading branch information
kibanamachine and dmlemeshko authored Mar 5, 2025
1 parent 202020f commit 1fd3c6b
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 34 deletions.
31 changes: 23 additions & 8 deletions src/platform/packages/shared/kbn-scout/src/cli/config_discovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import fs from 'fs';
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 { measurePerformance } from '../common';

Expand All @@ -21,29 +24,41 @@ export const discoverPlaywrightConfigs: Command<void> = {
Common usage:
node scripts/scout discover-playwright-configs --searchPaths <search_paths>
node scripts/scout discover-playwright-configs --save
node scripts/scout discover-playwright-configs
`,
flags: {
string: ['searchPaths'],
default: { searchPaths: DEFAULT_TEST_PATH_PATTERNS },
boolean: ['save'],
default: { searchPaths: DEFAULT_TEST_PATH_PATTERNS, save: false },
},
run: ({ flagsReader, log }) => {
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);
});

const finalMessage =
plugins.size === 0
? 'No playwright config files found'
: `Found playwright config files in '${plugins.size}' plugins`;
pluginsMap.size === 0
? 'No Playwright config files found'
: `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);

plugins.forEach((files, plugin) => {
log.info(`[${plugin}] plugin:`);
files.forEach((file) => {
pluginsMap.forEach((data, plugin) => {
log.info(`${data.group} / [${plugin}] plugin:`);
data.configs.map((file) => {
log.info(`- ${file}`);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,36 @@ describe('getScoutPlaywrightConfigs', () => {

it('should correctly extract plugin names and group config files', () => {
(fastGlob.sync as jest.Mock).mockReturnValue([
'x-pack/platform/plugins/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/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',
'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.get('plugin_a')).toEqual([
'x-pack/platform/plugins/plugin_a/ui_tests/playwright.config.ts',
'x-pack/platform/plugins/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',
]);
expect(plugins.size).toBe(3);
expect(plugins.get('plugin_a')).toEqual({
configs: [
'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',
],
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', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,78 @@ import { ToolingLog } from '@kbn/tooling-log';

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) => {
const patterns = searchPaths.map((basePath) =>
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}`));
log.info(''); // Add a newline for better readability

const files = patterns.flatMap((pattern) => fastGlob.sync(pattern, { onlyFiles: true }));

// Group config files by plugin
const plugins = files.reduce((acc: Map<string, string[]>, filePath: string) => {
const match = filePath.match(
/(?:src\/platform\/plugins|x-pack\/.*?\/plugins)\/(?:.*?\/)?([^\/]+)\/ui_tests\//
);
const pluginName = match ? match[1] : null;
const typeMappings: Record<string, string> = {
'x-pack/solutions/security': 'security',
'x-pack/solutions/search': 'search',
'x-pack/solutions/observability': 'observability',
'x-pack/platform/plugins': 'platform',
'src/platform/plugins': 'platform',
};

const matchPluginPath = (filePath: string): { pluginPath: string; pluginName: string } | null => {
const regexes = [
/(x-pack\/platform\/plugins\/(?:private|shared|[^\/]+)\/([^\/]+))\/ui_tests\//,
/(x-pack\/solutions\/[^\/]+\/plugins\/([^\/]+))\/ui_tests\//,
/(src\/platform\/plugins\/(?:private|shared)?\/?([^\/]+))\/ui_tests\//,
];

if (pluginName) {
if (!acc.has(pluginName)) {
acc.set(pluginName, []);
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}`);
return;
}

return acc;
}, new Map<string, string[]>());
const { pluginPath, pluginName } = matchResult;
const group =
Object.entries(typeMappings).find(([key]) => filePath.includes(key))?.[1] || 'unknown';

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 plugins;
return pluginsWithConfigs;
};

0 comments on commit 1fd3c6b

Please sign in to comment.