From 12f2e506a49592dbbb777623d441fb8f5e6c3e7b Mon Sep 17 00:00:00 2001 From: Tre' Seymour Date: Mon, 27 Jul 2020 16:50:54 -0600 Subject: [PATCH] [QA] Canonical Code Coverage Teams and CODEOWNERS Assignment Add the first draft of the TEAMS assignments, including defaults for code coverage and teams. After this PR, we will add a CI check to verify all defined paths have CODEOWNERship, and possibly code coverage teams. Resovles https://github.com/elastic/kibana/issues/72692 --- .ci/Jenkinsfile_coverage | 7 +- scripts/canonical_codeowners.js | 21 ++ .../ingest_coverage/__tests__/maybe.test.js | 42 +++ .../code_coverage/ingest_coverage/either.js | 4 + .../code_coverage/ingest_coverage/maybe.js | 9 +- .../code_owners/__tests__/code_owners.test.js | 34 ++ src/dev/code_owners/flush.js | 37 +++ src/dev/code_owners/helpers.js | 47 +++ src/dev/code_owners/index.js | 37 +++ src/dev/code_owners/owners_source_of_truth.js | 300 ++++++++++++++++++ src/dev/code_owners/parse.js | 63 ++++ .../shell_scripts/define_code_owners.sh | 12 + vars/kibanaTeamAssign.groovy | 10 + 13 files changed, 617 insertions(+), 6 deletions(-) create mode 100644 scripts/canonical_codeowners.js create mode 100644 src/dev/code_coverage/ingest_coverage/__tests__/maybe.test.js create mode 100644 src/dev/code_owners/__tests__/code_owners.test.js create mode 100644 src/dev/code_owners/flush.js create mode 100644 src/dev/code_owners/helpers.js create mode 100644 src/dev/code_owners/index.js create mode 100644 src/dev/code_owners/owners_source_of_truth.js create mode 100644 src/dev/code_owners/parse.js create mode 100644 src/dev/code_owners/shell_scripts/define_code_owners.sh diff --git a/.ci/Jenkinsfile_coverage b/.ci/Jenkinsfile_coverage index ebb9c3dc86dd2..371e381d74fdb 100644 --- a/.ci/Jenkinsfile_coverage +++ b/.ci/Jenkinsfile_coverage @@ -12,9 +12,10 @@ kibanaPipeline(timeoutMinutes: 240) { ]) { workers.base(name: 'coverage-worker', size: 'l', ramDisk: false, bootstrapped: false) { catchError { - kibanaCoverage.runTests() - kibanaTeamAssign.load('team_assignment', "### Upload Team Assignment JSON") - handleIngestion(TIME_STAMP) +// kibanaCoverage.runTests() +// kibanaTeamAssign.load('team_assignment', "### Upload Team Assignment JSON") +// handleIngestion(TIME_STAMP) + kibanaTeamAssign.defineCodeOwners('.github/draft_CODEOWNERS', "### Define CODEOWNERS") } handleFail() } diff --git a/scripts/canonical_codeowners.js b/scripts/canonical_codeowners.js new file mode 100644 index 0000000000000..83f13c83db10c --- /dev/null +++ b/scripts/canonical_codeowners.js @@ -0,0 +1,21 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +require('../src/setup_node_env'); +require('../src/dev/code_owners').defineCodeOwners(); diff --git a/src/dev/code_coverage/ingest_coverage/__tests__/maybe.test.js b/src/dev/code_coverage/ingest_coverage/__tests__/maybe.test.js new file mode 100644 index 0000000000000..2dbd776a12289 --- /dev/null +++ b/src/dev/code_coverage/ingest_coverage/__tests__/maybe.test.js @@ -0,0 +1,42 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { fromNullable } from '../maybe'; + +describe(`maybe algebraic datatype functions`, () => { + const pluck = (x) => (obj) => obj[x]; + const attempt = (obj) => fromNullable(obj).map(pluck('detail')); + describe(`helpers`, () => { + it(`'fromNullable' should be a fn`, () => { + expect(typeof fromNullable).toBe('function'); + }); + }); + describe(`'fromNullable`, () => { + it(`should continue processing if a truthy is calculated`, () => { + expect(attempt({ detail: 'x' }).value()).toBe('x'); + }); + it(`should drop processing if a falsey is calculated`, () => { + const obj = { + a: 'abc', + }; + + expect(fromNullable(obj.b).inspect()).toBe('[Nothing]'); + }); + }); +}); diff --git a/src/dev/code_coverage/ingest_coverage/either.js b/src/dev/code_coverage/ingest_coverage/either.js index eeb48893f18d8..302fcf0550dc6 100644 --- a/src/dev/code_coverage/ingest_coverage/either.js +++ b/src/dev/code_coverage/ingest_coverage/either.js @@ -20,11 +20,14 @@ /* eslint new-cap: 0 */ /* eslint no-unused-vars: 0 */ +import { pretty } from './utils'; + export const Right = (x) => ({ chain: (f) => f(x), map: (f) => Right(f(x)), fold: (leftFn, rightFn) => rightFn(x), inspect: () => `Right(${x})`, + inspectPretty: () => `Right(${pretty(x)})`, }); Right.of = function of(x) { @@ -40,6 +43,7 @@ export const Left = (x) => ({ map: (f) => Left(x), fold: (leftFn, rightFn) => leftFn(x), inspect: () => `Left(${x})`, + inspectPretty: () => `Left(${pretty(x)})`, }); Left.of = function of(x) { diff --git a/src/dev/code_coverage/ingest_coverage/maybe.js b/src/dev/code_coverage/ingest_coverage/maybe.js index 89936d6fc4b0e..4a55fdff1df8a 100644 --- a/src/dev/code_coverage/ingest_coverage/maybe.js +++ b/src/dev/code_coverage/ingest_coverage/maybe.js @@ -20,6 +20,8 @@ /* eslint new-cap: 0 */ /* eslint no-unused-vars: 0 */ +import { pretty } from './utils'; + /** * Just monad used for valid values */ @@ -29,6 +31,7 @@ export function Just(x) { map: (f) => Maybe.of(f(x)), isJust: () => true, inspect: () => `Just(${x})`, + inspectPretty: () => `Just(${pretty(x)})`, }; } Just.of = function of(x) { @@ -48,6 +51,7 @@ export function Maybe(x) { chain: (f) => f(x), map: (f) => Maybe(f(x)), inspect: () => `Maybe(${x})`, + inspectPretty: () => `Maybe(${pretty(x)})`, nothing: () => Nothing(), isNothing: () => false, isJust: () => false, @@ -60,9 +64,8 @@ Maybe.of = function of(x) { export function maybe(x) { return Maybe.of(x); } -export function fromNullable(x) { - return x !== null && x !== undefined && x !== false && x !== 'undefined' ? just(x) : nothing(); -} +export const fromNullable = (x) => + x !== null && x !== undefined && x !== false && x !== 'undefined' ? just(x) : nothing(); /** * Nothing wraps undefined or null values and prevents errors diff --git a/src/dev/code_owners/__tests__/code_owners.test.js b/src/dev/code_owners/__tests__/code_owners.test.js new file mode 100644 index 0000000000000..5d4092c98c04f --- /dev/null +++ b/src/dev/code_owners/__tests__/code_owners.test.js @@ -0,0 +1,34 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import expect from '@kbn/expect'; +import { hasPath } from '../'; + +describe(`Code Owners`, () => { + describe(`hasPath predicate fn`, () => { + const iterable = new Map(); + iterable.set('a', 'b'); + it(`should return true if the iterable has the path`, () => { + expect(hasPath('a')(iterable)).to.be(true); + }); + it(`should return false if the iterable does not have the path`, () => { + expect(hasPath('b')(iterable)).to.be(false); + }); + }); +}); diff --git a/src/dev/code_owners/flush.js b/src/dev/code_owners/flush.js new file mode 100644 index 0000000000000..ab153b69f2bf0 --- /dev/null +++ b/src/dev/code_owners/flush.js @@ -0,0 +1,37 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { createWriteStream } from 'fs'; + +const preamble = `# GitHub CODEOWNERS definition +# Identify which groups will be pinged by changes to different parts of the codebase. +# For more info, see https://help.github.com/articles/about-codeowners/\n\n`; + +export const flush = (codeOwnersPath) => (log) => (ownersMap) => { + log.info(`\n### Flushing to codeOwnersPath: \n\t${codeOwnersPath}`); + const file = createWriteStream(codeOwnersPath); + + file.write(preamble); + + ownersMap.forEach(({ owners /* review, teams */ }, key) => { + file.write(`${key} ${owners.join(' ')}\n`); + }); + + file.end(); +}; diff --git a/src/dev/code_owners/helpers.js b/src/dev/code_owners/helpers.js new file mode 100644 index 0000000000000..3eb6dfea5c525 --- /dev/null +++ b/src/dev/code_owners/helpers.js @@ -0,0 +1,47 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { pretty } from '../code_coverage/ingest_coverage/utils'; + +export function teamName(githubHandle) { + const prefix = /elastic\//; + const dropElastic = dropPrefix(prefix); + const prefixedWithES = prefixed(prefix); + + return prefixedWithES(githubHandle) ? dropElastic(githubHandle) : githubHandle; +} + +export function hasPath(path) { + return (iterable) => !!iterable.has(path); +} + +function prefixed(prefix) { + return (x) => prefix.test(x); +} + +function dropPrefix(prefix) { + return (x) => x.replace(prefix, ''); +} +export function hasOverrides(xs) { + return !!Array.isArray(xs[0]); +} + +export function printMap(map) { + map.forEach((value, key) => console.log(key + ' -> ' + pretty(value))); +} diff --git a/src/dev/code_owners/index.js b/src/dev/code_owners/index.js new file mode 100644 index 0000000000000..9bfa51ddcc18c --- /dev/null +++ b/src/dev/code_owners/index.js @@ -0,0 +1,37 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { resolve } from 'path'; +import { run } from '@kbn/dev-utils'; +import { parseSourceOfTruth } from './parse'; +import { sourceOfTruth as sot } from './owners_source_of_truth'; +import { flush } from './flush'; + +const ROOT = resolve(__dirname, '../../..'); +const resolveFromRoot = resolve.bind(null, ROOT); +const codeownersPath = process.env.CODEOWNERS_PATH || resolveFromRoot('.github/draft_CODEOWNERS'); +const description = ` + +Create .github/CODEOWNERS file from authoritative source + +`; + +export const defineCodeOwners = () => { + run(({ log }) => flush(codeownersPath)(log)(parseSourceOfTruth(log)(sot)), { description }); +}; diff --git a/src/dev/code_owners/owners_source_of_truth.js b/src/dev/code_owners/owners_source_of_truth.js new file mode 100644 index 0000000000000..1cac72936bc61 --- /dev/null +++ b/src/dev/code_owners/owners_source_of_truth.js @@ -0,0 +1,300 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export const sourceOfTruth = [ + { + title: 'App', + githubHandle: 'elastic/kibana-app', + pathPatterns: [ + '/x-pack/plugins/dashboard_enhanced/', + '/x-pack/plugins/discover_enhanced/', + '/x-pack/plugins/lens/', + '/x-pack/plugins/graph/', + '/src/legacy/core_plugins/kibana/public/local_application_service/', + '/src/plugins/dashboard/', + '/src/plugins/discover/', + '/src/plugins/input_control_vis/', + '/src/plugins/kibana_legacy/', + '/src/plugins/vis_default_editor/', + '/src/plugins/vis_type_markdown/', + '/src/plugins/vis_type_metric/', + '/src/plugins/vis_type_table/', + '/src/plugins/vis_type_tagcloud/', + '/src/plugins/vis_type_timelion/', + '/src/plugins/vis_type_timeseries/', + '/src/plugins/vis_type_vega/', + '/src/plugins/vis_type_vislib/', + '/src/plugins/vis_type_xy/', + '/src/plugins/visualize/', + ], + }, + { + title: 'App Architecture', + githubHandle: 'elastic/kibana-app-arch', + pathPatterns: [ + '/examples/bfetch_explorer/', + '/examples/dashboard_embeddable_examples/', + '/examples/demo_search/', + '/examples/developer_examples/', + '/examples/embeddable_examples/', + '/examples/embeddable_explorer/', + '/examples/state_container_examples/', + '/examples/ui_actions_examples/', + '/examples/ui_actions_explorer/', + '/examples/url_generators_examples/', + '/examples/url_generators_explorer/', + '/packages/elastic-datemath/', + '/packages/kbn-interpreter/', + '/src/plugins/advanced_settings/', + '/src/plugins/bfetch/', + '/src/plugins/data/', + '/src/plugins/embeddable/', + '/src/plugins/expressions/', + '/src/plugins/inspector/', + '/src/plugins/kibana_react/', + '/src/plugins/kibana_utils/', + '/src/plugins/management/', + '/src/plugins/navigation/', + '/src/plugins/share/', + '/src/plugins/ui_actions/', + '/src/plugins/visualizations/', + '/x-pack/examples/ui_actions_enhanced_examples/', + '/x-pack/plugins/data_enhanced/', + '/x-pack/plugins/embeddable_enhanced/', + '/x-pack/plugins/ui_actions_enhanced/', + ], + }, + { + title: 'APM', + githubHandle: 'elastic/apm-ui', + pathPatterns: [ + '/x-pack/plugins/apm/', + '/x-pack/test/functional/apps/apm/', + '/src/legacy/core_plugins/apm_oss/', + '/src/plugins/apm_oss/', + ], + }, + { + title: 'Thomas Watson', + githubHandle: 'watson', + pathPatterns: ['/src/apm.js'], + review: false, + }, + { + title: 'Vignesh Shanmugam', + githubHandle: 'vigneshshanmugam', + pathPatterns: ['/src/apm.js'], + review: false, + }, + { + title: 'Quality Assurance', + githubHandle: 'elastic/kibana-qa', + pathPatterns: [ + '/src/dev/code_coverage/', + '/test/functional/services/common/', + '/test/functional/services/lib/', + '/test/functional/services/remote/', + ], + }, + { + title: 'Platform', + githubHandle: 'elastic/kibana-platform', + pathPatterns: [ + '/src/core/', + '/config/kibana.yml', + '/x-pack/plugins/features/', + '/x-pack/plugins/licensing/', + '/x-pack/plugins/global_search/', + '/x-pack/plugins/cloud/', + '/x-pack/test/saved_objects_field_count/', + '/packages/kbn-config-schema/', + '/src/legacy/server/config/', + '/src/legacy/server/http/', + '/src/legacy/server/logging/', + '/src/legacy/server/saved_objects/ ', + '/src/legacy/server/status/', + '/src/plugins/status_page/', + '/src/plugins/saved_objects_management/', + '/src/dev/run_check_published_api_changes.ts', + '/src/core/server/csp/', + ], + }, + { + title: 'Security', + githubHandle: 'elastic/kibana-security', + pathPatterns: [ + '/src/core/server/csp/', + '/x-pack/legacy/plugins/security/', + '/x-pack/legacy/plugins/spaces/', + '/x-pack/plugins/spaces/', + '/x-pack/plugins/encrypted_saved_objects/', + '/x-pack/plugins/security/', + '/x-pack/test/api_integration/apis/security/', + ], + }, + { + title: 'Kibana Localization', + githubHandle: 'elastic/kibana-localization', + pathPatterns: [ + '/src/dev/i18n/', + '/src/legacy/server/i18n/', + '/src/core/public/i18n/', + '/packages/kbn-i18n/', + ], + }, + { + title: 'Kibana Telemetry', + githubHandle: 'elastic/kibana-telemetry', + pathPatterns: [ + '/packages/kbn-analytics/', + '/packages/kbn-telemetry-tools/', + '/src/plugins/kibana_usage_collection/', + '/src/plugins/newsfeed/', + '/src/plugins/telemetry/', + '/src/plugins/telemetry_collection_manager/', + '/src/plugins/telemetry_management_section/', + '/src/plugins/usage_collection/', + '/x-pack/plugins/telemetry_collection_xpack/', + '/.telemetryrc.json', + '/x-pack/.telemetryrc.json', + 'src/plugins/telemetry/schema/legacy_oss_plugins.json', + 'src/plugins/telemetry/schema/oss_plugins.json', + 'x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json', + ], + }, + { + title: 'Kibana Alerting Services', + githubHandle: 'elastic/kibana-alerting-services', + pathPatterns: [ + '/x-pack/plugins/alerts/', + '/x-pack/plugins/actions/', + '/x-pack/plugins/event_log/', + '/x-pack/plugins/task_manager/', + '/x-pack/test/alerting_api_integration/', + '/x-pack/test/plugin_api_integration/plugins/task_manager/', + '/x-pack/test/plugin_api_integration/test_suites/task_manager/', + '/x-pack/plugins/triggers_actions_ui/', + '/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/', + '/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/', + ], + }, + { + title: 'Design', + githubHandle: 'elastic/kibana-design', + pathPatterns: ['**/*.scss'], + }, + { + title: 'App Search Frontend', + githubHandle: 'elastic/app-search-frontend', + pathPatterns: [ + // Enterprise Search + '/x-pack/plugins/enterprise_search/', + '/x-pack/test/functional_enterprise_search/', + ], + }, + { + title: 'Workplace Search Frontend', + githubHandle: 'elastic/workplace-search-frontend', + pathPatterns: [ + // Enterprise Search + '/x-pack/plugins/enterprise_search/', + '/x-pack/test/functional_enterprise_search/', + ], + }, + { + title: 'Enterprise Search Design', + githubHandle: 'elastic/ent-search-design', + pathPatterns: [ + // Enterprise Search + '/x-pack/plugins/enterprise_search/**/*.scss', + ], + }, + { + title: 'Elasticsearch UI', + githubHandle: 'elastic/es-ui', + pathPatterns: [ + '/src/plugins/dev_tools/', + '/src/plugins/console/', + '/src/plugins/es_ui_shared/', + '/x-pack/legacy/plugins/cross_cluster_replication/', + '/x-pack/plugins/index_lifecycle_management/', + '/x-pack/legacy/plugins/index_management/', + '/x-pack/legacy/plugins/license_management/', + '/x-pack/legacy/plugins/rollup/', + '/x-pack/legacy/plugins/snapshot_restore/', + '/x-pack/legacy/plugins/upgrade_assistant/', + '/x-pack/plugins/console_extensions/', + '/x-pack/plugins/es_ui_shared/', + '/x-pack/plugins/grokdebugger/', + '/x-pack/plugins/index_management/', + '/x-pack/plugins/license_management/', + '/x-pack/plugins/painless_lab/', + '/x-pack/plugins/remote_clusters/', + '/x-pack/plugins/rollup/', + '/x-pack/plugins/searchprofiler/', + '/x-pack/plugins/snapshot_restore/', + '/x-pack/plugins/upgrade_assistant/', + '/x-pack/plugins/watcher/', + '/x-pack/plugins/ingest_pipelines/', + ], + }, + { + title: 'Endpoint App Team', + githubHandle: 'elastic/endpoint-app-team', + pathPatterns: [ + '/x-pack/plugins/endpoint/', + '/x-pack/test/api_integration/apis/endpoint/', + '/x-pack/test/endpoint_api_integration_no_ingest/', + '/x-pack/test/security_solution_endpoint/', + '/x-pack/test/functional/es_archives/endpoint/', + '/x-pack/test/plugin_functional/plugins/resolver_test/', + '/x-pack/test/plugin_functional/test_suites/resolver/', + '/x-pack/plugins/security_solution/', + '/x-pack/test/detection_engine_api_integration', + '/x-pack/test/api_integration/apis/security_solution', + '/x-pack/plugins/case', + '/x-pack/plugins/lists', + ], + }, + { + title: 'SIEM', + githubHandle: 'elastic/siem', + pathPatterns: [ + '/x-pack/plugins/endpoint/', + '/x-pack/test/api_integration/apis/endpoint/', + '/x-pack/test/endpoint_api_integration_no_ingest/', + '/x-pack/test/security_solution_endpoint/', + '/x-pack/test/functional/es_archives/endpoint/', + '/x-pack/test/plugin_functional/plugins/resolver_test/', + '/x-pack/test/plugin_functional/test_suites/resolver/', + '/x-pack/plugins/security_solution/', + '/x-pack/test/detection_engine_api_integration', + '/x-pack/test/api_integration/apis/security_solution', + '/x-pack/plugins/case', + '/x-pack/plugins/lists', + ], + }, + { + title: 'Security Intelligence And Analytics', + githubHandle: 'elastic/security-intelligence-analytics', + pathPatterns: [ + '/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules', + ], + }, +]; diff --git a/src/dev/code_owners/parse.js b/src/dev/code_owners/parse.js new file mode 100644 index 0000000000000..1f7deb2039a38 --- /dev/null +++ b/src/dev/code_owners/parse.js @@ -0,0 +1,63 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { left, right } from '../code_coverage/ingest_coverage/either'; +import { teamName, hasPath } from './helpers'; + +export const parseSourceOfTruth = (log) => (sourceOfTruth) => { + const init = new Map(); + + const owners = sourceOfTruth.reduce( + (acc, { title, githubHandle, pathPatterns, review = true }) => { + const handle = `@${githubHandle}`; + const team = teamName(githubHandle); + + pathPatterns.forEach((path) => { + log.info(`\n### Parsing path: \n${path}`); + const whetherHasPath = hasPath(path)(acc) ? right(acc) : left(acc); + + const mutateOwnersAndTeams = (path) => (accObj) => { + const { owners: currOwners, teams: currTeams } = accObj.get(path); + + accObj.set(path, { + owners: currOwners.concat(handle), + teams: currTeams.concat(team), + title, + review, + }); + }; + + const addNew = (path) => (accObj) => + accObj.set(path, { + owners: [handle], + teams: [team], + title, + review, + }); + + whetherHasPath.fold(addNew(path), mutateOwnersAndTeams(path)); + }); + + return acc; + }, + init + ); + + return owners; +}; diff --git a/src/dev/code_owners/shell_scripts/define_code_owners.sh b/src/dev/code_owners/shell_scripts/define_code_owners.sh new file mode 100644 index 0000000000000..92c935080cb32 --- /dev/null +++ b/src/dev/code_owners/shell_scripts/define_code_owners.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +echo "### Define Code Owners" +echo "" + +CODEOWNERS_PATH=$1 +export CODEOWNERS_PATH + +node scripts/canonical_codeowners.js --verbose + +echo "### Define Code Owners - Complete" +echo "" diff --git a/vars/kibanaTeamAssign.groovy b/vars/kibanaTeamAssign.groovy index e2298ed43d408..378f5d2f7eafc 100644 --- a/vars/kibanaTeamAssign.groovy +++ b/vars/kibanaTeamAssign.groovy @@ -22,4 +22,14 @@ def load(ingestionPipelineName, title) { loadWithVault(ingestionPipelineName, title) } +def defineCodeOwners(destination, title) { + kibanaPipeline.bash(""" + source src/dev/ci_setup/setup_env.sh + yarn kbn bootstrap --prefer-offline + + . src/dev/code_owners/shell_scripts/define_code_owners.sh' ${destination}' + cat '${destination}' + """, title) +} + return this