@ovh-ux/manager-static-analysis-kit 0.10.0 โ 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/README.md +166 -24
- package/bin/cli-path-config.js +41 -2
- package/bin/code-duplication-cli.js +14 -16
- package/bin/code-duplication-tests-cli.js +43 -6
- package/bin/lint-cli.js +99 -54
- package/bin/perf-budgets-cli.js +15 -15
- package/bin/perf-budgets-tests-cli.js +36 -3
- package/bin/static-dynamic-quality-checks.js +2 -2
- package/bin/tests-coverage-cli-tests.js +44 -6
- package/bin/tests-coverage-cli.js +35 -27
- package/bin/types-coverage-cli.js +8 -11
- package/bin/types-coverage-tests-cli.js +44 -7
- package/bin/utils/args-parse-utils.js +69 -106
- package/bin/utils/module-utils.js +121 -0
- package/bin/utils/runner-utils.js +117 -22
- package/bin/utils/turbo-utils.js +1 -71
- package/dist/adapters/perf-budgets/helpers/perfs-bundle-analysis-helper.d.ts.map +1 -1
- package/dist/adapters/perf-budgets/helpers/perfs-bundle-analysis-helper.js +8 -4
- package/dist/configs/shared-exclusion-patterns.d.ts.map +1 -1
- package/dist/configs/shared-exclusion-patterns.js +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -2
- package/bin/utils/apps-utils.js +0 -64
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,28 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [0.11.1](https://github.com/ovh/manager/compare/@ovh-ux/manager-static-analysis-kit@0.11.0...@ovh-ux/manager-static-analysis-kit@0.11.1) (2025-10-12)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @ovh-ux/manager-static-analysis-kit
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# [0.11.0](https://github.com/ovh/manager/compare/@ovh-ux/manager-static-analysis-kit@0.10.0...@ovh-ux/manager-static-analysis-kit@0.11.0) (2025-10-07)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* extends static kit to analyse react libraries ([8c2845c](https://github.com/ovh/manager/commit/8c2845cdc3abc13734831fab312d8ad012b30b16)), closes [#MANAGER-19743](https://github.com/ovh/manager/issues/MANAGER-19743)
|
|
20
|
+
* improve documentation ([4141218](https://github.com/ovh/manager/commit/4141218c63abcab05edc5d4db2eb44f7701c04c7)), closes [#MANAGER-19743](https://github.com/ovh/manager/issues/MANAGER-19743)
|
|
21
|
+
* include mrc on new metrics analysis ([456d311](https://github.com/ovh/manager/commit/456d3118a7d9017d63f19e907b45f2833e4a0348)), closes [#MANAGER-19743](https://github.com/ovh/manager/issues/MANAGER-19743)
|
|
22
|
+
* update documentation ([3b37b1b](https://github.com/ovh/manager/commit/3b37b1b51bd9ff06e23e4d2169511f05b4aec345)), closes [#MANAGER-19743](https://github.com/ovh/manager/issues/MANAGER-19743)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
6
28
|
# [0.10.0](https://github.com/ovh/manager/compare/@ovh-ux/manager-static-analysis-kit@0.9.0...@ovh-ux/manager-static-analysis-kit@0.10.0) (2025-10-02)
|
|
7
29
|
|
|
8
30
|
|
package/README.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# ๐งช static-analysis-kit
|
|
2
2
|
|
|
3
|
-
A modular, extensible, and future-ready toolkit for defining, adapting, and sharing static analysis rules across projects in the
|
|
3
|
+
A modular, extensible, and future-ready toolkit for defining, adapting, and sharing static and dynamic analysis rules across projects in the **Manager monorepo**.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
## ๐ What Is It?
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
`@ovh-ux/manager-static-analysis-kit` provides a unified framework for **code quality automation** across all applications, libraries, and modules โ covering both **static** (lint, duplication, type coverage) and **dynamic** (tests, performance) checks.
|
|
10
10
|
|
|
11
|
-
It separates semantic rule definitions from tool-specific
|
|
11
|
+
It separates semantic rule definitions from tool-specific adapters to ensure configurability, reusability, and long-term consistency across the monorepo.
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
@@ -33,34 +33,108 @@ Coming soon:
|
|
|
33
33
|
> - [Performance Budgets](src/adapters/perf-budgets/README.md)
|
|
34
34
|
> - [Tests Coverage](src/adapters/tests-coverage/README.md)
|
|
35
35
|
> - [Types Coverage](src/adapters/types-coverage/README.md)
|
|
36
|
-
> - [HTML
|
|
37
|
-
> - [
|
|
36
|
+
> - [HTML Validation](src/adapters/html-w3c-validation/README.md)
|
|
37
|
+
> - [Accessibility Validation](src/adapters/html-a11y-validation/README.md)
|
|
38
38
|
|
|
39
39
|
---
|
|
40
40
|
|
|
41
41
|
## ๐งโ๐ป Combined Quality Checks
|
|
42
42
|
|
|
43
|
-
The kit also provides a **single entrypoint** for running all static & dynamic quality checks
|
|
43
|
+
The kit also provides a **single entrypoint** for running all static & dynamic quality checks:
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
46
|
# Run all quality checks
|
|
47
47
|
yarn manager-static-dynamic-quality-checks
|
|
48
48
|
|
|
49
|
-
# Run only
|
|
49
|
+
# Run only test-related checks
|
|
50
50
|
yarn manager-static-dynamic-quality-checks --tests
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## ๐ง Launch Modes
|
|
56
|
+
|
|
57
|
+
Each CLI (e.g. `manager-code-duplication`, `manager-types-coverage`) supports **flexible launch modes** for targeting different scopes within the monorepo.
|
|
58
|
+
|
|
59
|
+
| Flag | Target | Path Resolution |
|
|
60
|
+
|------|---------|----------------|
|
|
61
|
+
| `--apps` / `--app` | Manager applications | `manager/apps/*` |
|
|
62
|
+
| `--packages` / `--package` | Package-level analysis | Resolves via `package.json` |
|
|
63
|
+
| `--libraries` / `--library` | Internal libraries | `packages/manager/core`, `packages/manager/modules`, `packages/components` |
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
### Analyze specific apps (by folder name)
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
yarn manager-types-coverage --apps zimbra,container
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
or single app:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
yarn manager-types-coverage --app zimbra
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
> Here you provide **app folders** located under `manager/apps`.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
### Analyze specific packages (by `package.json` name)
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
yarn manager-types-coverage --packages @ovh-ux/manager-container-app,@ovh-ux/manager-zimbra-app
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
or single package:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
yarn manager-types-coverage --package @ovh-ux/manager-container-app
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
> In this mode:
|
|
96
|
+
> - The CLI resolves the package names to their corresponding **apps**.
|
|
97
|
+
> - Reports are generated per **app folder**.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
### Analyze specific libraries (by `package.json` name)
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
yarn manager-types-coverage --libraries @ovh-ux/manager-wiki,@ovh-ux/manager-react-components
|
|
105
|
+
```
|
|
54
106
|
|
|
55
|
-
|
|
107
|
+
or single library:
|
|
56
108
|
|
|
57
109
|
```bash
|
|
58
|
-
yarn manager-
|
|
59
|
-
yarn manager-perf-budgets
|
|
60
|
-
yarn manager-tests-coverage
|
|
61
|
-
yarn manager-types-coverage
|
|
110
|
+
yarn manager-types-coverage --library @ovh-ux/manager-react-components
|
|
62
111
|
```
|
|
63
112
|
|
|
113
|
+
> In this mode:
|
|
114
|
+
> - The CLI resolves the library names to their corresponding **folders** inside configured library roots:
|
|
115
|
+
> - `packages/manager-react-components/*`
|
|
116
|
+
> - `packages/manager-wiki/*`
|
|
117
|
+
> - Reports are generated per **library folder**.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## โ ๏ธ Important Requirements
|
|
122
|
+
|
|
123
|
+
โ ๏ธ **Important:**
|
|
124
|
+
|
|
125
|
+
These analysis tools only process **React-based applications and libraries** โ **Angular or legacy frameworks are not supported**.
|
|
126
|
+
|
|
127
|
+
Each analysis type has specific requirements to run successfully:
|
|
128
|
+
|
|
129
|
+
| Analysis Type | Required Configuration | Description |
|
|
130
|
+
|----------------|-------------------------|--------------|
|
|
131
|
+
| **Type Coverage** | `tsconfig.json` | The tool analyzes only TypeScript projects with a valid configuration file. |
|
|
132
|
+
| **Tests Coverage** | Vitest or Jest setup | Requires test files (`*.test.ts[x]`, `*.spec.ts[x]`) and a working Vitest/Jest config. |
|
|
133
|
+
| **Performance Budgets** | `vite.config.ts` or `vite.config.js` | Requires a Vite-based build configuration to extract bundle metrics. |
|
|
134
|
+
| **Code Duplication** | React source files (`.js`, `.ts`, `.tsx`) | Automatically skips non-React or invalid modules. |
|
|
135
|
+
|
|
136
|
+
> Modules that don't meet these conditions are **skipped automatically with a warning**, but the CLI will still analyze all valid React apps and libraries to ensure partial success in mixed environments.
|
|
137
|
+
|
|
64
138
|
---
|
|
65
139
|
|
|
66
140
|
## ๐งฑ Structure Overview
|
|
@@ -68,16 +142,26 @@ yarn manager-types-coverage
|
|
|
68
142
|
```
|
|
69
143
|
static-analysis-kit/
|
|
70
144
|
โโโ src/
|
|
71
|
-
โ โโโ code-analysis.ts # Central
|
|
72
|
-
โ โโโ configs/ # Tool-agnostic
|
|
145
|
+
โ โโโ code-analysis.ts # Central export point
|
|
146
|
+
โ โโโ configs/ # Tool-agnostic rule definitions
|
|
73
147
|
โ โโโ adapters/ # Tool integrations
|
|
74
148
|
โ โโโ eslint/
|
|
75
|
-
โ โโโ code-duplication/
|
|
76
|
-
โ โโโ perf-budgets/
|
|
77
|
-
โ โโโ tests-coverage/
|
|
78
|
-
โ โโโ types-coverage/
|
|
79
|
-
โ โโโ
|
|
80
|
-
โ
|
|
149
|
+
โ โโโ code-duplication/
|
|
150
|
+
โ โโโ perf-budgets/
|
|
151
|
+
โ โโโ tests-coverage/
|
|
152
|
+
โ โโโ types-coverage/
|
|
153
|
+
โ โโโ ts-config/
|
|
154
|
+
โ โโโ html-a11y-validation/
|
|
155
|
+
โ โโโ html-w3c-validation/
|
|
156
|
+
โ โโโ architecture-analysis/ # Coming soon
|
|
157
|
+
โโโ bin/
|
|
158
|
+
โ โโโ utils/ # Shared CLI utilities
|
|
159
|
+
โ โ โโโ args-parse-utils.js # CLI flags parsing (apps/libs/packages)
|
|
160
|
+
โ โ โโโ module-utils.js # Discovery and resolution logic
|
|
161
|
+
โ โ โโโ file-utils.js # JSON read/write helpers
|
|
162
|
+
โ โ โโโ log-utils.js # Colored CLI logging
|
|
163
|
+
โ โโโ cli-path-config.js # Centralized base paths & root dirs
|
|
164
|
+
โโโ README.md
|
|
81
165
|
```
|
|
82
166
|
|
|
83
167
|
---
|
|
@@ -91,8 +175,66 @@ static-analysis-kit/
|
|
|
91
175
|
|
|
92
176
|
---
|
|
93
177
|
|
|
94
|
-
##
|
|
178
|
+
## ๐งช Validation & CLI Testing
|
|
179
|
+
|
|
180
|
+
Each CLI in the Static Analysis Kit (e.g., `manager-code-duplication`, `manager-perf-budgets`, `manager-tests-coverage`, `manager-types-coverage`) includes automated validation suites that ensure correct argument parsing, module discovery, and exit-code semantics.
|
|
181
|
+
|
|
182
|
+
These tests simulate **real-world usage** across apps, packages, and libraries โ both valid and invalid โ to guarantee stability and predictable CLI behavior.
|
|
183
|
+
|
|
184
|
+
To execute these tests, from the root run:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
yarn static-dynamic-quality-check-tests
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
### ๐งญ Test Matrix
|
|
193
|
+
|
|
194
|
+
| Category | Example Command | Expected Exit |
|
|
195
|
+
|-----------|----------------|----------------|
|
|
196
|
+
| **Single app** | `yarn manager-code-duplication --app zimbra` | โ
`0` |
|
|
197
|
+
| **Multiple apps** | `yarn manager-code-duplication --apps container,zimbra` | โ
`0` |
|
|
198
|
+
| **Single package** | `yarn manager-code-duplication --package @ovh-ux/manager-container-app` | โ
`0` |
|
|
199
|
+
| **Multiple packages** | `yarn manager-code-duplication --packages @ovh-ux/manager-zimbra-app,@ovh-ux/manager-pci-workflow-app` | โ
`0` |
|
|
200
|
+
| **Single library (static)** | `yarn manager-code-duplication --library manager-react-components` | โ
`0` |
|
|
201
|
+
| **Single library (dynamic)** | `yarn manager-code-duplication --library shell-client` | โ
`0` |
|
|
202
|
+
| **Multiple libraries** | `yarn manager-code-duplication --libraries manager-wiki,manager-react-components,shell-client` | โ
`0` |
|
|
203
|
+
| **Mixed valid + invalid apps** | `yarn manager-code-duplication --apps zimbra,unknown-app,container` | โ
`0` |
|
|
204
|
+
| **All invalid apps** | `yarn manager-code-duplication --apps doesnotexist1,doesnotexist2` | โ `1` |
|
|
205
|
+
| **Turbo build simulation** | `yarn manager-code-duplication --app pci-ai-tools` | โ
`0` |
|
|
206
|
+
|
|
207
|
+
> ๐งฉ Each case asserts CLI correctness, exit codes, and resilience against unknown modules.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
### ๐งฐ Supported CLIs
|
|
212
|
+
|
|
213
|
+
| CLI | Purpose |
|
|
214
|
+
|-----|----------|
|
|
215
|
+
| `manager-code-duplication` | Detects duplicated code across apps and libs |
|
|
216
|
+
| `manager-perf-budgets` | Evaluates bundle and asset sizes |
|
|
217
|
+
| `manager-tests-coverage` | Aggregates Jest/Vitest coverage reports |
|
|
218
|
+
| `manager-types-coverage` | Reports TypeScript type coverage |
|
|
219
|
+
|
|
220
|
+
Each CLI supports:
|
|
221
|
+
- `--apps` / `--app`
|
|
222
|
+
- `--packages` / `--package`
|
|
223
|
+
- `--libraries` / `--library`
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## ๐ฌ Feedback & Contributions
|
|
95
228
|
|
|
96
|
-
The
|
|
229
|
+
The **Static Analysis Kit** aims to become the central standard for static and dynamic quality assurance across all OVHcloud Manager projects.
|
|
230
|
+
|
|
231
|
+
We welcome contributions that:
|
|
232
|
+
- Add new analyzers or integrations
|
|
233
|
+
- Improve performance or modularity
|
|
234
|
+
- Enhance developer experience or CI/CD compatibility
|
|
235
|
+
|
|
236
|
+
๐ก **Goal:** A composable, maintainable, and organization-wide framework for modern code quality governance.
|
|
237
|
+
|
|
238
|
+
---
|
|
97
239
|
|
|
98
|
-
|
|
240
|
+
ยฉ 2025 OVHcloud โ Manager Engineering Team
|
package/bin/cli-path-config.js
CHANGED
|
@@ -4,23 +4,40 @@ import { fileURLToPath } from 'node:url';
|
|
|
4
4
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
5
5
|
|
|
6
6
|
export const rootDir = path.resolve(__dirname, '../../..');
|
|
7
|
-
export const outputRootDir = path.resolve(__dirname, '../../../../static-dynamic-quality-reports');
|
|
8
7
|
|
|
9
|
-
export const appsDir = path.join(
|
|
8
|
+
export const appsDir = path.join('.', 'packages/manager/apps');
|
|
9
|
+
|
|
10
|
+
export const librariesBasePaths = [
|
|
11
|
+
path.join('.', 'packages/manager/core'),
|
|
12
|
+
path.join('.', 'packages/manager/modules'),
|
|
13
|
+
path.join('.', 'packages/components'),
|
|
14
|
+
];
|
|
10
15
|
|
|
11
16
|
export const bundleAnalyzerBinPath = path.resolve(__dirname, '../node_modules/.bin/analyze');
|
|
12
17
|
export const perfBudgetsReportDirName = 'perf-budgets-reports';
|
|
13
18
|
export const perfBudgetCombinedJsonReportName = 'perf-budgets-combined-report.json';
|
|
14
19
|
export const perfBudgetCombinedHtmlReportName = 'perf-budgets-combined-report.html';
|
|
20
|
+
export const perfBudgetOutputRootDir = path.resolve(
|
|
21
|
+
__dirname,
|
|
22
|
+
'../../../../static-dynamic-quality-reports',
|
|
23
|
+
);
|
|
15
24
|
|
|
16
25
|
export const jscpdBinPath = path.resolve(__dirname, '../node_modules/.bin/jscpd');
|
|
17
26
|
export const codeDupReportsRootDirName = 'code-duplication-reports';
|
|
18
27
|
export const codeDupCombinedJsonReportName = 'code-duplication-combined-report.json';
|
|
19
28
|
export const codeDupCombinedHtmlReportName = 'code-duplication-combined-report.html';
|
|
29
|
+
export const codeDupOutputRootDir = path.resolve(
|
|
30
|
+
__dirname,
|
|
31
|
+
'../../../../static-dynamic-quality-reports',
|
|
32
|
+
);
|
|
20
33
|
|
|
21
34
|
export const testsCoverageReportsRootDirName = 'tests-coverage-reports';
|
|
22
35
|
export const testsCoverageCombinedJsonReportName = 'tests-coverage-combined-report.json';
|
|
23
36
|
export const testsCoverageCombinedHtmlReportName = 'tests-coverage-combined-report.html';
|
|
37
|
+
export const testsCoverageOutputRootDir = path.resolve(
|
|
38
|
+
__dirname,
|
|
39
|
+
'../../../../static-dynamic-quality-reports',
|
|
40
|
+
);
|
|
24
41
|
|
|
25
42
|
export const tsTypesCoverageBin = path.resolve(
|
|
26
43
|
__dirname,
|
|
@@ -29,3 +46,25 @@ export const tsTypesCoverageBin = path.resolve(
|
|
|
29
46
|
export const typesCoverageReportsRootDirName = 'types-coverage-reports';
|
|
30
47
|
export const typesCoverageCombinedJsonReportName = 'types-coverage-combined-report.json';
|
|
31
48
|
export const typesCoverageCombinedHtmlReportName = 'types-coverage-combined-report.html';
|
|
49
|
+
export const typesCoverageOutputRootDir = path.resolve(
|
|
50
|
+
__dirname,
|
|
51
|
+
'../../../../static-dynamic-quality-reports',
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
export const combinedReportOutputRootDir = path.resolve(
|
|
55
|
+
__dirname,
|
|
56
|
+
'../../../../static-dynamic-quality-reports',
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
export const staticDiscoveredLibraries = [
|
|
60
|
+
{
|
|
61
|
+
fullPath: 'packages/manager-react-components',
|
|
62
|
+
shortPath: 'manager-react-components',
|
|
63
|
+
packageName: '@ovh-ux/manager-react-components',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
fullPath: 'packages/manager-wiki',
|
|
67
|
+
shortPath: 'manager-wiki',
|
|
68
|
+
packageName: '@ovh-ux/manager-wiki',
|
|
69
|
+
},
|
|
70
|
+
];
|
|
@@ -8,16 +8,15 @@ import {
|
|
|
8
8
|
generateCodeDuplicationHtml,
|
|
9
9
|
} from '../dist/adapters/code-duplication/helpers/code-duplication-analysis-helper.js';
|
|
10
10
|
import {
|
|
11
|
-
appsDir,
|
|
12
11
|
codeDupCombinedHtmlReportName,
|
|
13
12
|
codeDupCombinedJsonReportName,
|
|
13
|
+
codeDupOutputRootDir,
|
|
14
14
|
codeDupReportsRootDirName,
|
|
15
15
|
jscpdBinPath,
|
|
16
|
-
outputRootDir,
|
|
17
16
|
} from './cli-path-config.js';
|
|
18
17
|
import { buildCodeDuplicationArgs, parseCliTargets } from './utils/args-parse-utils.js';
|
|
19
18
|
import { logError, logInfo, logWarn } from './utils/log-utils.js';
|
|
20
|
-
import { ensureBinExists,
|
|
19
|
+
import { ensureBinExists, runCommand, runModulesAnalysis } from './utils/runner-utils.js';
|
|
21
20
|
|
|
22
21
|
/**
|
|
23
22
|
* Run `jscpd` code duplication analysis for a single app.
|
|
@@ -28,16 +27,17 @@ import { ensureBinExists, runAppsAnalysis, runCommand } from './utils/runner-uti
|
|
|
28
27
|
*/
|
|
29
28
|
function runAppCodeDuplication(appDir, appShortName) {
|
|
30
29
|
try {
|
|
31
|
-
const absoluteOutputDir = path.join(
|
|
30
|
+
const absoluteOutputDir = path.join(
|
|
31
|
+
codeDupOutputRootDir,
|
|
32
|
+
codeDupReportsRootDirName,
|
|
33
|
+
appShortName,
|
|
34
|
+
);
|
|
32
35
|
fs.mkdirSync(absoluteOutputDir, { recursive: true });
|
|
33
36
|
|
|
34
|
-
// Relative output path from the app dir (keeps paths clean inside HTML reports)
|
|
35
|
-
const relativeOutputDir = path.relative(appDir, absoluteOutputDir);
|
|
36
|
-
|
|
37
37
|
logInfo(`Running jscpd for ${appShortName} โ ${absoluteOutputDir}`);
|
|
38
38
|
|
|
39
|
-
const args = [...buildCodeDuplicationArgs(
|
|
40
|
-
const ok = runCommand(jscpdBinPath, args,
|
|
39
|
+
const args = [...buildCodeDuplicationArgs(absoluteOutputDir), appDir];
|
|
40
|
+
const ok = runCommand(jscpdBinPath, args, '.');
|
|
41
41
|
|
|
42
42
|
// Validate expected reports
|
|
43
43
|
const jsonReport = path.join(absoluteOutputDir, 'jscpd-report.json');
|
|
@@ -72,20 +72,18 @@ function main() {
|
|
|
72
72
|
try {
|
|
73
73
|
ensureBinExists(jscpdBinPath, 'jscpd');
|
|
74
74
|
|
|
75
|
-
const
|
|
75
|
+
const modules = parseCliTargets();
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
appFolders,
|
|
80
|
-
requireReact: true,
|
|
77
|
+
runModulesAnalysis({
|
|
78
|
+
modules,
|
|
81
79
|
binaryLabel: 'Code duplication',
|
|
82
|
-
|
|
80
|
+
analysisRunner: runAppCodeDuplication,
|
|
83
81
|
reportsRootDirName: codeDupReportsRootDirName,
|
|
84
82
|
combinedJson: codeDupCombinedJsonReportName,
|
|
85
83
|
combinedHtml: codeDupCombinedHtmlReportName,
|
|
86
84
|
collectFn: collectCodeDuplication,
|
|
87
85
|
generateHtmlFn: generateCodeDuplicationHtml,
|
|
88
|
-
outputRootDir,
|
|
86
|
+
outputRootDir: codeDupOutputRootDir,
|
|
89
87
|
});
|
|
90
88
|
} catch (err) {
|
|
91
89
|
logError(`Fatal error: ${err.stack || err.message}`);
|
|
@@ -5,13 +5,10 @@ import { logError, logInfo } from './utils/log-utils.js';
|
|
|
5
5
|
|
|
6
6
|
// Define the set of validation test cases for code-duplication CLI
|
|
7
7
|
const cases = [
|
|
8
|
-
// Debug only โ very slow, runs across all apps
|
|
9
|
-
// { name: 'Auto-discovery (all apps)', cmd: 'yarn manager-code-duplication', expect: 0 },
|
|
10
|
-
|
|
11
8
|
{ name: 'Single app (zimbra)', cmd: 'yarn manager-code-duplication --app zimbra', expect: 0 },
|
|
12
9
|
{
|
|
13
|
-
name: 'Multiple apps (container,zimbra
|
|
14
|
-
cmd: 'yarn manager-code-duplication --apps container,zimbra
|
|
10
|
+
name: 'Multiple apps (container,zimbra)',
|
|
11
|
+
cmd: 'yarn manager-code-duplication --apps container,zimbra',
|
|
15
12
|
expect: 0,
|
|
16
13
|
},
|
|
17
14
|
{
|
|
@@ -24,6 +21,36 @@ const cases = [
|
|
|
24
21
|
cmd: 'yarn manager-code-duplication --packages @ovh-ux/manager-zimbra-app,@ovh-ux/manager-pci-workflow-app',
|
|
25
22
|
expect: 0,
|
|
26
23
|
},
|
|
24
|
+
{
|
|
25
|
+
name: 'Single library static path by folder name (manager-react-components)',
|
|
26
|
+
cmd: 'yarn manager-code-duplication --library manager-react-components',
|
|
27
|
+
expect: 0,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: 'Single library static path by package name (manager-react-components)',
|
|
31
|
+
cmd: 'yarn manager-code-duplication --library @ovh-ux/manager-react-components',
|
|
32
|
+
expect: 0,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'Single library dynamic path by folder name (shell-client)',
|
|
36
|
+
cmd: 'yarn manager-code-duplication --library shell-client',
|
|
37
|
+
expect: 0,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'Single library static path by package name (shell-client)',
|
|
41
|
+
cmd: 'yarn manager-code-duplication --library @ovh-ux/manager-react-shell-client',
|
|
42
|
+
expect: 0,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'Multiple libraries by folder names (manager-wiki,manager-react-components,shell-client,logs-to-customer)',
|
|
46
|
+
cmd: 'yarn manager-code-duplication --libraries manager-wiki,manager-react-components,shell-client,logs-to-customer',
|
|
47
|
+
expect: 0,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: 'Multiple libraries by package names (manager-wiki,manager-react-components,shell-client,logs-to-customer)',
|
|
51
|
+
cmd: 'yarn manager-code-duplication --libraries @ovh-ux/manager-wiki,@ovh-ux/manager-react-components,@ovh-ux/manager-react-shell-client,@ovh-ux/logs-to-customer',
|
|
52
|
+
expect: 0,
|
|
53
|
+
},
|
|
27
54
|
{
|
|
28
55
|
name: 'Mixed valid+invalid apps',
|
|
29
56
|
cmd: 'yarn manager-code-duplication --apps zimbra,unknown-app,container',
|
|
@@ -31,7 +58,12 @@ const cases = [
|
|
|
31
58
|
},
|
|
32
59
|
{
|
|
33
60
|
name: 'Mixed valid+invalid packages',
|
|
34
|
-
cmd: 'yarn manager-code-duplication --packages @ovh-ux/manager-
|
|
61
|
+
cmd: 'yarn manager-code-duplication --packages @ovh-ux/manager-wiki,manager-react-components,@ovh-ux/manager-ghost-app',
|
|
62
|
+
expect: 0,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'Mixed valid+invalid libraries',
|
|
66
|
+
cmd: 'yarn manager-code-duplication --libraries @ovh-ux/manager-zimbra-app,@ovh-ux/manager-ghost-app',
|
|
35
67
|
expect: 0,
|
|
36
68
|
},
|
|
37
69
|
{
|
|
@@ -44,6 +76,11 @@ const cases = [
|
|
|
44
76
|
cmd: 'yarn manager-code-duplication --packages @ovh-ux/manager-ghost-app,@ovh-ux/manager-missing-app',
|
|
45
77
|
expect: 1,
|
|
46
78
|
},
|
|
79
|
+
{
|
|
80
|
+
name: 'Turbo build failure simulation (pci-ai-tools)',
|
|
81
|
+
cmd: 'yarn manager-code-duplication --app pci-ai-tools',
|
|
82
|
+
expect: 0,
|
|
83
|
+
},
|
|
47
84
|
];
|
|
48
85
|
|
|
49
86
|
let failed = 0;
|
package/bin/lint-cli.js
CHANGED
|
@@ -2,74 +2,119 @@
|
|
|
2
2
|
import { spawn } from 'node:child_process';
|
|
3
3
|
import { existsSync } from 'node:fs';
|
|
4
4
|
import { dirname, join, resolve } from 'node:path';
|
|
5
|
-
import process, { cwd } from 'node:process';
|
|
6
|
-
import { fileURLToPath
|
|
5
|
+
import process, { cwd, execPath } from 'node:process';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { createRequire } from 'node:module';
|
|
7
8
|
|
|
8
9
|
import { logError, logInfo } from './utils/log-utils.js';
|
|
9
10
|
|
|
11
|
+
/**
|
|
12
|
+
* manager-lint
|
|
13
|
+
* - Uses ESLint's real JS entry (no platform-specific .bin)
|
|
14
|
+
* - Auto-picks config: --config arg > local eslint.config.* > shared default
|
|
15
|
+
* - Supports TS flat config by preloading tsx only when needed
|
|
16
|
+
*/
|
|
17
|
+
|
|
10
18
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
const require = createRequire(import.meta.url);
|
|
11
20
|
const userCwd = cwd();
|
|
12
|
-
const eslintBin = resolve(__dirname, '../node_modules/.bin/eslint');
|
|
13
21
|
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Resolve ESLint CLI entry (avoid .bin shims)
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
let eslintCli;
|
|
26
|
+
try {
|
|
27
|
+
eslintCli = resolve(require.resolve('eslint/package.json'), '../bin/eslint.js');
|
|
28
|
+
} catch {
|
|
29
|
+
logError('[manager-lint] Could not resolve "eslint". Is it installed in this package?');
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Args & config
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
14
36
|
const args = process.argv.slice(2);
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
|
|
38
|
+
const hasFlag = (name) => args.includes(name);
|
|
39
|
+
const getFlagValue = (name) => {
|
|
40
|
+
const i = args.indexOf(name);
|
|
41
|
+
return i >= 0 ? args[i + 1] : undefined;
|
|
42
|
+
};
|
|
43
|
+
const firstNonFlag = () => args.find((a) => !a.startsWith('--'));
|
|
44
|
+
|
|
45
|
+
const hasExplicitConfig = hasFlag('--config');
|
|
46
|
+
const localConfigCandidates = [
|
|
47
|
+
'eslint.config.ts', 'eslint.config.mts', 'eslint.config.cts',
|
|
48
|
+
'eslint.config.mjs', 'eslint.config.cjs', 'eslint.config.js',
|
|
49
|
+
];
|
|
50
|
+
const localConfigPath = localConfigCandidates
|
|
51
|
+
.map((f) => join(userCwd, f))
|
|
52
|
+
.find((p) => existsSync(p));
|
|
53
|
+
|
|
54
|
+
const sharedDefaultPath = resolve(__dirname, '../dist/adapters/eslint/config/eslint-shared-config.js');
|
|
55
|
+
|
|
56
|
+
const configPath = hasExplicitConfig ? getFlagValue('--config') : (localConfigPath ?? sharedDefaultPath);
|
|
57
|
+
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// Node preload for TS configs
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
const needsTsx = /\.(?:mts|cts|ts)$/i.test(configPath || '');
|
|
62
|
+
const nodeMajor = Number(process.versions.node.split('.')[0]);
|
|
63
|
+
|
|
64
|
+
if (needsTsx) {
|
|
65
|
+
// Fail fast with a clear message if tsx isn't available
|
|
66
|
+
try {
|
|
67
|
+
require.resolve('tsx');
|
|
68
|
+
} catch {
|
|
69
|
+
logError('[manager-lint] A TypeScript eslint config was detected, but "tsx" is not installed.');
|
|
70
|
+
logError('Install it in @ovh-ux/manager-static-analysis-kit (or the invoking package) and retry.');
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const nodePreload = needsTsx
|
|
76
|
+
? (nodeMajor >= 20 ? ['--import', 'tsx'] : ['--loader', 'tsx'])
|
|
77
|
+
: [];
|
|
78
|
+
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// Build final ESLint argv
|
|
81
|
+
// - If the user didnโt pass --config, inject our chosen config
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
const forwarded = hasExplicitConfig ? args : ['--config', configPath, ...args];
|
|
84
|
+
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
// Runner
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
function run(procArgs) {
|
|
89
|
+
return new Promise((resolveCode) => {
|
|
90
|
+
const child = spawn(execPath, procArgs, {
|
|
91
|
+
cwd: userCwd,
|
|
34
92
|
stdio: 'inherit',
|
|
35
|
-
|
|
36
|
-
shell: true,
|
|
93
|
+
shell: false,
|
|
37
94
|
});
|
|
38
|
-
|
|
39
95
|
child.on('error', (err) => {
|
|
40
96
|
logError('[manager-lint] Failed to run ESLint');
|
|
41
97
|
logError(err);
|
|
42
|
-
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
child.on('close', (code) => {
|
|
46
|
-
resolve(code ?? 1);
|
|
98
|
+
resolveCode(1);
|
|
47
99
|
});
|
|
100
|
+
child.on('close', (code) => resolveCode(code ?? 1));
|
|
48
101
|
});
|
|
49
102
|
}
|
|
50
103
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
logError(err);
|
|
63
|
-
process.exit(1);
|
|
64
|
-
}
|
|
65
|
-
process.exit(0);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Construct full args
|
|
69
|
-
const fullArgs =
|
|
70
|
-
hasExplicitConfigArg || hasLocalConfig ? args : ['--config', sharedDefaultPath, ...args];
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// --print-config (delegate to ESLint)
|
|
106
|
+
// ESLint requires a target file after --print-config. Use the first non-flag
|
|
107
|
+
// argument or default to "." if none was provided.
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
if (hasFlag('--print-config')) {
|
|
110
|
+
const target = firstNonFlag() ?? '.';
|
|
111
|
+
logInfo('[manager-lint] Using config:', configPath);
|
|
112
|
+
const code = await run([...nodePreload, eslintCli, '--config', configPath, '--print-config', target]);
|
|
113
|
+
process.exit(code);
|
|
114
|
+
}
|
|
71
115
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
// Normal run
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
const code = await run([...nodePreload, eslintCli, ...forwarded]);
|
|
120
|
+
process.exit(code);
|