diff --git a/packages/kbn-code-owners/index.ts b/packages/kbn-code-owners/index.ts index df85bb6d9c624..dd68409299f0e 100644 --- a/packages/kbn-code-owners/index.ts +++ b/packages/kbn-code-owners/index.ts @@ -14,3 +14,9 @@ export { findCodeOwnersEntryForPath, getOwningTeamsForPath, } from './src/code_owners'; +export { + type CodeOwnerArea, + CODE_OWNER_AREAS, + CODE_OWNER_AREA_MAPPINGS, + findAreaForCodeOwner, +} from './src/code_owner_areas'; diff --git a/packages/kbn-code-owners/src/cli.ts b/packages/kbn-code-owners/src/cli.ts index 9e7a839e0546c..b8cc102101235 100644 --- a/packages/kbn-code-owners/src/cli.ts +++ b/packages/kbn-code-owners/src/cli.ts @@ -40,6 +40,7 @@ export async function findCodeOwnersForPath() { log.write(`Matching pattern: ${codeOwnersEntry.pattern}`); log.write('Teams:', codeOwnersEntry.teams); + log.write('Areas:', codeOwnersEntry.areas); }, { description: `Find code owners for a given path in this local Kibana repository`, diff --git a/packages/kbn-code-owners/src/code_owner_areas.ts b/packages/kbn-code-owners/src/code_owner_areas.ts new file mode 100644 index 0000000000000..fc961fd6d463e --- /dev/null +++ b/packages/kbn-code-owners/src/code_owner_areas.ts @@ -0,0 +1,98 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +/** + * Code owner area names + */ +export const CODE_OWNER_AREAS = ['platform', 'search', 'observability', 'security'] as const; +export type CodeOwnerArea = (typeof CODE_OWNER_AREAS)[number]; + +/** + * Area mappings for code owners + */ +export const CODE_OWNER_AREA_MAPPINGS: { [area in CodeOwnerArea]: string[] } = { + platform: [ + 'elastic/appex-ai-infra', + 'elastic/appex-qa', + 'elastic/appex-sharedux', + 'elastic/docs', + 'elastic/eui-team', + 'elastic/fleet', + 'elastic/kibana-core', + 'elastic/kibana-data-discovery', + 'elastic/kibana-design', + 'elastic/kibana-esql', + 'elastic/kibana-localization', + 'elastic/kibana-management', + 'elastic/kibana-operations', + 'elastic/kibana-performance-testing', + 'elastic/kibana-presentation', + 'elastic/kibana-qa', + 'elastic/kibana-reporting-services', + 'elastic/kibana-security', + 'elastic/kibana-tech-leads', + 'elastic/kibana-visualizations', + 'elastic/logstash', + 'elastic/ml-ui', + 'elastic/platform-docs', + 'elastic/response-ops', + 'elastic/stack-monitoring', + ], + search: ['elastic/search-design', 'elastic/search-kibana'], + observability: [ + 'elastic/obs-ai-assistant', + 'elastic/obs-cloudnative-monitoring', + 'elastic/obs-docs', + 'elastic/obs-entities', + 'elastic/obs-knowledge-team', + 'elastic/obs-ux-infra_services-team', + 'elastic/obs-ux-logs-team', + 'elastic/obs-ux-management-team', + 'elastic/obs-ux-onboarding-team', + 'elastic/observability-design', + 'elastic/observability-ui', + 'elastic/observablt-robots', + 'elastic/streams-program-team', + ], + security: [ + 'elastic/kibana-cloud-security-posture', + 'elastic/security-asset-management', + 'elastic/security-data-analytics', + 'elastic/security-defend-workflows', + 'elastic/security-design', + 'elastic/security-detection-engine', + 'elastic/security-detection-rule-management', + 'elastic/security-detections-response', + 'elastic/security-engineering-productivity', + 'elastic/security-entity-analytics', + 'elastic/security-generative-ai', + 'elastic/security-scalability', + 'elastic/security-service-integrations', + 'elastic/security-solution', + 'elastic/security-threat-hunting', + 'elastic/security-threat-hunting-explore', + 'elastic/security-threat-hunting-investigations', + ], +}; + +/** + * Find what area a code owner belongs to + * + * @param owner Owner to find an area name + * @returns The code owner area if a match for the given owner is found + */ +export function findAreaForCodeOwner(owner: string): CodeOwnerArea | undefined { + for (const area of CODE_OWNER_AREAS) { + const owners = CODE_OWNER_AREA_MAPPINGS[area]; + + if (owners.includes(owner)) { + return area; + } + } +} diff --git a/packages/kbn-code-owners/src/code_owners.ts b/packages/kbn-code-owners/src/code_owners.ts index 47aa2a67171c0..88e9772a76cc4 100644 --- a/packages/kbn-code-owners/src/code_owners.ts +++ b/packages/kbn-code-owners/src/code_owners.ts @@ -13,11 +13,13 @@ import path from 'node:path'; import ignore, { Ignore } from 'ignore'; import { CODE_OWNERS_FILE, throwIfPathIsMissing, throwIfPathNotInRepo } from './path'; +import { CodeOwnerArea, findAreaForCodeOwner } from './code_owner_areas'; export interface CodeOwnersEntry { pattern: string; matcher: Ignore; teams: string[]; + areas: CodeOwnerArea[]; comment?: string; } @@ -64,9 +66,19 @@ export function getCodeOwnersEntries(): CodeOwnersEntry[] { const pathPattern = rawPathPattern.replace(/\/$/, ''); + const teams = rawTeams.map((team) => team.replace('@', '')).filter((team) => team.length > 0); + const areas: CodeOwnerArea[] = []; + + for (const team of teams) { + const area = findAreaForCodeOwner(team); + if (area === undefined || areas.includes(area)) continue; + areas.push(area); + } + entries.push({ pattern: pathPattern, - teams: rawTeams.map((t) => t.replace('@', '')).filter((t) => t.length > 0), + teams, + areas, comment, // Register code owner entry with the `ignores` lib for easy pattern matching later on @@ -85,7 +97,7 @@ export function getCodeOwnersEntries(): CodeOwnersEntry[] { * * Tip: * If you're making a lot of calls to this function, fetch the code owner paths once using - * `getCodeOwnersEntries` and pass it in the `getCodeOwnersEntries` parameter to speed up your queries.. + * `getCodeOwnersEntries` and pass it in the `getCodeOwnersEntries` parameter to speed up your queries. * * @param searchPath The path to find code owners for * @param codeOwnersEntries Pre-defined list of code owner paths to search in