Skip to content

Commit

Permalink
Dependency Ownership CLI (elastic#201773)
Browse files Browse the repository at this point in the history
## Summary

1. Show all packages owned by a specific team
```
node scripts/dependency_ownership -o <owner>
```
2. Identify owners of a specific dependency
```
node scripts/dependency_ownership -d <dependency>
```

3. List dependencies without an owner
```
node scripts/dependency_ownership --missing-owner
```

4. Generate a full dependency ownership report
```
node scripts/dependency_ownership
```

### Checklist

- [x]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)


__Closes: https://github.com/elastic/kibana/issues/196767__

---------

Co-authored-by: Elastic Machine <[email protected]>
Co-authored-by: kibanamachine <[email protected]>
  • Loading branch information
3 people authored Nov 29, 2024
1 parent 8084bd6 commit 976b94f
Show file tree
Hide file tree
Showing 19 changed files with 960 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -2027,6 +2027,13 @@ module.exports = {
'@kbn/imports/uniform_imports': 'off',
},
},
{
files: ['packages/kbn-dependency-ownership/**/*.{ts,tsx}'],
rules: {
// disabling it since package is a CLI tool
'no-console': 'off',
},
},
],
};

Expand Down
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ packages/kbn-data-service @elastic/kibana-visualizations @elastic/kibana-data-di
packages/kbn-data-stream-adapter @elastic/security-threat-hunting
packages/kbn-data-view-utils @elastic/kibana-data-discovery
packages/kbn-datemath @elastic/kibana-data-discovery
packages/kbn-dependency-ownership @elastic/kibana-security
packages/kbn-dependency-usage @elastic/kibana-security
packages/kbn-dev-cli-errors @elastic/kibana-operations
packages/kbn-dev-cli-runner @elastic/kibana-operations
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1430,6 +1430,7 @@
"@kbn/core-ui-settings-server-mocks": "link:packages/core/ui-settings/core-ui-settings-server-mocks",
"@kbn/core-usage-data-server-mocks": "link:packages/core/usage-data/core-usage-data-server-mocks",
"@kbn/cypress-config": "link:packages/kbn-cypress-config",
"@kbn/dependency-ownership": "link:packages/kbn-dependency-ownership",
"@kbn/dependency-usage": "link:packages/kbn-dependency-usage",
"@kbn/dev-cli-errors": "link:packages/kbn-dev-cli-errors",
"@kbn/dev-cli-runner": "link:packages/kbn-dev-cli-runner",
Expand Down
166 changes: 166 additions & 0 deletions packages/kbn-dependency-ownership/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# @kbn/dependency-ownership

A CLI tool for analyzing package ownership.

---

## Table of Contents
1. [Show all packages owned by a specific team](#show-all-packages-owned-by-a-specific-team)
2. [Show who owns specific dependency](#show-who-owns-specific-dependency)
3. [List all dependencies with without owner](#list-all-dependencies-with-without-owner)
4. [Generate dependency ownership report](#generate-dependency-ownership-report)

---


### 1. Show all packages owned by a specific team

Use this command to list all packages or plugins within a directory that use a specified dependency.

```sh
node scripts/dependency_ownership -o <owner>
```
or
```sh
node scripts/dependency_ownership --owner <owner>
```

**Example**:
```sh
node scripts/dependency_ownership -o @elastic/kibana-core
```

- `-o @elastic/kibana-core`: Specifies the team.

**Output**: Lists dev and prod dependencies.

```json
{
"prodDependencies": [
"<dependency_1>",
"<dependency_2>",
"<dependency_3>",
//...
],
"devDependencies": [
"<dependency_1>",
"<dependency_2>",
//...
]
}
```

---

### 2. Show who owns specific dependency

Get the owner for a specific dependency.

```sh
node scripts/dependency_ownership -d <dependency>
```
or
```sh
node scripts/dependency_ownership --dependency <dependency>
```

**Example**:
```sh
node scripts/dependency_ownership -d rxjs
```

- `-d rxjs`: Specifies the dependency.

**Output**: Lists owners for `rxjs`.
```json
[
"@elastic/kibana-core"
]
```
---

### 3. List all dependencies with without owner

To display all dependencies that do not have owner defined.

```sh
node scripts/dependency_ownership --missing-owner
```

**Example**:
```sh
node scripts/dependency_ownership --missing-owner
```

**Output**: Lists all dev and prod dependencies without owner.

```json
{
"prodDependencies": [
"<dependency_1>",
"<dependency_2>",
//...
],
"devDependencies": [
"<dependency_1>",
"<dependency_2>",
//...
]
}
```

---

### 4. Generate dependency ownership report

Generates a comprehensive report with all dependencies with and without owner.

```sh
node scripts/dependency_ownership --missing-owner
```

**Example**:
```sh
node scripts/dependency_ownership --missing-owner
```

**Output**: Lists all covered dev and prod dependencies, uncovered dev and prod dependencies, dependencies aggregated by owner.

```json
{
"coveredProdDependencies": [ // Prod dependencies with owner
"<dependency_1>",
"<dependency_2>",
//...
],
"coveredDevDependencies": [ // Dev dependencies with owner
"<dependency_1>",
"<dependency_2>",
//...
],
"uncoveredProdDependencies": [ // Prod dependencies without owner
"<dependency_1>",
"<dependency_2>",
//...
],
"uncoveredDevDependencies": [ // Dev dependencies without owner
"<dependency_1>",
"<dependency_2>",
//...
],
"prodDependenciesByOwner": { // Prod dependencies aggregated by owner
"@elastic/team_1": ["<dependency_1>"],
"@elastic/team_2": ["<dependency_1>"],
},
"devDependenciesByOwner": { // Dev dependencies aggregated by owner
"@elastic/team_1": ["<dependency_1>"],
"@elastic/team_2": ["<dependency_1>"],
},
}
```


---

For further information on additional flags and options, refer to the script's help command.

18 changes: 18 additions & 0 deletions packages/kbn-dependency-ownership/bin/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env node

/*
* 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".
*/

// eslint-disable-next-line import/no-extraneous-dependencies
require('@babel/register')({
extensions: ['.ts', '.js'],
presets: [['@babel/preset-env', { targets: { node: 'current' } }], '@babel/preset-typescript'],
});

require('../src/cli');
14 changes: 14 additions & 0 deletions packages/kbn-dependency-ownership/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* 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".
*/

module.exports = {
preset: '@kbn/test',
rootDir: '../..',
roots: ['<rootDir>/packages/kbn-dependency-ownership'],
};
6 changes: 6 additions & 0 deletions packages/kbn-dependency-ownership/kibana.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "shared-common",
"id": "@kbn/dependency-ownership",
"owner": "@elastic/kibana-security",
"devOnly": true
}
6 changes: 6 additions & 0 deletions packages/kbn-dependency-ownership/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "@kbn/dependency-ownership",
"private": true,
"version": "1.0.0",
"license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0"
}
119 changes: 119 additions & 0 deletions packages/kbn-dependency-ownership/src/cli.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* 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".
*/

import { configureYargs } from './cli';
import { identifyDependencyOwnership } from './dependency_ownership';

jest.mock('chalk', () => ({
green: jest.fn((str) => str),
yellow: jest.fn((str) => str),
cyan: jest.fn((str) => str),
magenta: jest.fn((str) => str),
blue: jest.fn((str) => str),
bold: { magenta: jest.fn((str) => str), blue: jest.fn((str) => str) },
}));

jest.mock('./dependency_ownership', () => ({
identifyDependencyOwnership: jest.fn(),
}));

jest.mock('./cli', () => ({
...jest.requireActual('./cli'),
runCLI: jest.fn(),
}));

describe('dependency-ownership CLI', () => {
const parser = configureYargs()
.fail((message: string) => {
throw new Error(message);
})
.exitProcess(false);

beforeEach(() => {
jest.spyOn(console, 'log').mockImplementation(() => {});
});

afterEach(() => {
jest.resetAllMocks();
});

it('should parse the dependency option correctly', () => {
const argv = parser.parse(['--dependency', 'lodash']);
expect(argv).toMatchObject({
dependency: 'lodash',
});

expect(identifyDependencyOwnership).toHaveBeenCalledWith(
expect.objectContaining({ dependency: 'lodash' })
);
});

it('should parse the owner option correctly', () => {
const argv = parser.parse(['--owner', '@elastic/kibana-core']);
expect(argv).toMatchObject({
owner: '@elastic/kibana-core',
});

expect(identifyDependencyOwnership).toHaveBeenCalledWith(
expect.objectContaining({ owner: '@elastic/kibana-core' })
);
});

it('should parse the missing-owner option correctly', () => {
const argv = parser.parse(['--missing-owner']);
expect(argv).toMatchObject({
missingOwner: true,
});

expect(identifyDependencyOwnership).toHaveBeenCalledWith(
expect.objectContaining({ missingOwner: true })
);
});

it('should parse the output-path option correctly', () => {
const argv = parser.parse([
'--output-path',
'./output.json',
'--owner',
'@elastic/kibana-core',
]);

expect(argv).toMatchObject({
owner: '@elastic/kibana-core',
outputPath: './output.json',
});

expect(identifyDependencyOwnership).toHaveBeenCalledWith(
expect.objectContaining({ owner: '@elastic/kibana-core' })
);
});

it('should support aliases for options', () => {
const argv1 = parser.parse(['-d', 'lodash', '-f', './out.json']);
expect(argv1).toMatchObject({
dependency: 'lodash',
outputPath: './out.json',
});

const argv2 = parser.parse(['-o', '@elastic/kibana-core', '-f', './out.json']);

expect(argv2).toMatchObject({
owner: '@elastic/kibana-core',
outputPath: './out.json',
});
});

it('should throw an error for invalid flag combinations', () => {
expect(() => {
parser.parse(['--dependency', 'lodash', '--missing-owner']);
}).toThrow('You must provide either a dependency, owner, or missingOwner flag to search for');

expect(identifyDependencyOwnership).not.toHaveBeenCalled();
});
});
Loading

0 comments on commit 976b94f

Please sign in to comment.