fg-devkit 1.12.13 → 1.14.2
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/README.md +13 -4
- package/configs/dependency-policy.vue-workspace.json +15 -15
- package/package.json +15 -8
- package/scaffold/vue/package.json +3 -4
- package/scripts/audit-override-commit.mjs +25 -14
- package/scripts/fg-devkit.mjs +14 -9
- package/scripts/fleet-bump-fg-devkit.mjs +59 -20
- package/scripts/fleet-vulns.mjs +24 -2
- package/scripts/policy-upgrade-commit.mjs +42 -13
- package/scripts/policy-upgrade.mjs +87 -5
- package/scripts/repo-vulns.mjs +71 -14
- package/scripts/resolve-dependency-policy-path.mjs +4 -2
- package/scripts/sync-dependency-policy-commit.mjs +154 -0
package/README.md
CHANGED
|
@@ -102,7 +102,7 @@ Check vulnerabilities for all policy packages together (including transitive dep
|
|
|
102
102
|
pnpm exec fgd policy-vulns
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
-
Check vulnerabilities for all dependencies in the current repo:
|
|
105
|
+
Check vulnerabilities for all dependencies in the current repo (and nested packages with their own `pnpm-lock.yaml`):
|
|
106
106
|
|
|
107
107
|
```bash
|
|
108
108
|
pnpm exec fgd repo-vulns
|
|
@@ -126,19 +126,28 @@ If npm audit is rate-limited (429), slow the scan down:
|
|
|
126
126
|
pnpm exec fgd fleet-vulns --delay-ms=8000
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
-
Upgrade policy versions interactively
|
|
129
|
+
Upgrade policy versions interactively and auto-commit
|
|
130
|
+
(`dep(package): bump to version`, or `dep(): bump N packages` with a body listing each bump):
|
|
130
131
|
|
|
131
132
|
```bash
|
|
132
133
|
pnpm exec fgd policy-upgrade
|
|
133
134
|
```
|
|
134
135
|
|
|
135
|
-
|
|
136
|
+
Sync dependency policy, run pnpm install, and auto-commit (`chore(repo): sync dependency policy`):
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
pnpm exec fgd sync-deps-commit
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Upgrade one or more package.json dependencies and auto-commit
|
|
143
|
+
(`dep(package): bump to version`, or `dep(): bump N packages` with a body listing each bump):
|
|
136
144
|
|
|
137
145
|
```bash
|
|
138
146
|
pnpm exec fgd policy-upgrade-commit
|
|
139
147
|
```
|
|
140
148
|
|
|
141
|
-
Fix one vulnerability
|
|
149
|
+
Fix one or more vulnerability overrides interactively and auto-commit
|
|
150
|
+
(`vuln(package): override version`, or `vuln(): override N packages` with a body listing each change):
|
|
142
151
|
|
|
143
152
|
```bash
|
|
144
153
|
pnpm exec fgd audit-override-commit
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"toolchain": {
|
|
3
|
-
"packageManager": "pnpm@11.
|
|
3
|
+
"packageManager": "pnpm@11.21.0",
|
|
4
4
|
"node": {
|
|
5
5
|
"nvmrc": "22",
|
|
6
6
|
"engines": ">=22.13.0",
|
|
@@ -10,16 +10,17 @@
|
|
|
10
10
|
},
|
|
11
11
|
"managedDependencies": {
|
|
12
12
|
"dependencies": {
|
|
13
|
+
"@e965/xlsx": "0.20.3",
|
|
13
14
|
"@element-plus/icons-vue": "2.3.2",
|
|
14
15
|
"@lexical/html": "0.49.0",
|
|
15
16
|
"@lexical/list": "0.49.0",
|
|
16
17
|
"@lexical/rich-text": "0.49.0",
|
|
18
|
+
"@lexical/link": "0.49.0",
|
|
17
19
|
"@piwikpro/vue-piwik-pro": "1.7.1",
|
|
18
|
-
"@sentry/browser": "10.
|
|
20
|
+
"@sentry/browser": "10.70.0",
|
|
19
21
|
"@sentry/tracing": "7.120.4",
|
|
20
|
-
"@sentry/vue": "10.
|
|
21
|
-
"@sentry/wasm": "10.
|
|
22
|
-
"@tailwindcss/postcss": "4.3.3",
|
|
22
|
+
"@sentry/vue": "10.70.0",
|
|
23
|
+
"@sentry/wasm": "10.70.0",
|
|
23
24
|
"@tanstack/vue-query": "5.101.4",
|
|
24
25
|
"@types/leaflet": "1.9.22",
|
|
25
26
|
"@unhead/vue": "2.0.5",
|
|
@@ -31,7 +32,7 @@
|
|
|
31
32
|
"chart.js": "4.5.1",
|
|
32
33
|
"content-disposition-header": "0.6.0",
|
|
33
34
|
"date-fns": "4.4.0",
|
|
34
|
-
"element-plus": "2.14.
|
|
35
|
+
"element-plus": "2.14.4",
|
|
35
36
|
"fds-vue-core": "8.4.3",
|
|
36
37
|
"imask": "7.6.1",
|
|
37
38
|
"leaflet": "1.9.4",
|
|
@@ -60,11 +61,11 @@
|
|
|
60
61
|
"@eslint/js": "9.39.1",
|
|
61
62
|
"@intlify/unplugin-vue-i18n": "11.2.4",
|
|
62
63
|
"@playwright/test": "1.62.1",
|
|
63
|
-
"@storybook/addon-a11y": "10.5.
|
|
64
|
-
"@storybook/addon-docs": "10.5.
|
|
65
|
-
"@storybook/addon-vitest": "10.5.
|
|
66
|
-
"@storybook/vue3": "10.5.
|
|
67
|
-
"@storybook/vue3-vite": "10.5.
|
|
64
|
+
"@storybook/addon-a11y": "10.5.7",
|
|
65
|
+
"@storybook/addon-docs": "10.5.7",
|
|
66
|
+
"@storybook/addon-vitest": "10.5.7",
|
|
67
|
+
"@storybook/vue3": "10.5.7",
|
|
68
|
+
"@storybook/vue3-vite": "10.5.7",
|
|
68
69
|
"@tanstack/vue-query-devtools": "6.1.38",
|
|
69
70
|
"@tsconfig/node22": "22.0.5",
|
|
70
71
|
"@types/lodash-es": "4.17.12",
|
|
@@ -76,13 +77,12 @@
|
|
|
76
77
|
"@vue/test-utils": "2.4.11",
|
|
77
78
|
"arg": "5.0.2",
|
|
78
79
|
"babel-eslint": "10.1.0",
|
|
79
|
-
"eslint-plugin-storybook": "10.5.
|
|
80
|
+
"eslint-plugin-storybook": "10.5.7",
|
|
80
81
|
"globals": "15.11.0",
|
|
81
82
|
"jsdom": "26.1.0",
|
|
82
|
-
"postcss": "8.5.26",
|
|
83
83
|
"sass": "1.102.0",
|
|
84
|
-
"storybook": "10.5.
|
|
85
|
-
"tsx": "4.23.
|
|
84
|
+
"storybook": "10.5.7",
|
|
85
|
+
"tsx": "4.23.12",
|
|
86
86
|
"vega": "6.3.1",
|
|
87
87
|
"vite-plugin-dts": "4.5.4",
|
|
88
88
|
"vite-plugin-vue-devtools": "8.2.1",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fg-devkit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.2",
|
|
4
4
|
"description": "Shared configs, scripts, and DX tooling for Vue / TypeScript frontend repos",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"./scripts/audit-override-commit.mjs": "./scripts/audit-override-commit.mjs",
|
|
57
57
|
"./scripts/check-dependency-policy.mjs": "./scripts/check-dependency-policy.mjs",
|
|
58
58
|
"./scripts/sync-dependency-policy.mjs": "./scripts/sync-dependency-policy.mjs",
|
|
59
|
+
"./scripts/sync-dependency-policy-commit.mjs": "./scripts/sync-dependency-policy-commit.mjs",
|
|
59
60
|
"./scripts/resolve-dependency-policy-path.mjs": "./scripts/resolve-dependency-policy-path.mjs",
|
|
60
61
|
"./scripts/refresh-dependency-policy-from-repos.mjs": "./scripts/refresh-dependency-policy-from-repos.mjs",
|
|
61
62
|
"./scripts/sync-scaffold-vue-deps.mjs": "./scripts/sync-scaffold-vue-deps.mjs",
|
|
@@ -106,13 +107,13 @@
|
|
|
106
107
|
"@inquirer/input": "5.1.2",
|
|
107
108
|
"@inquirer/select": "5.2.1",
|
|
108
109
|
"@intlify/eslint-plugin-vue-i18n": "4.5.1",
|
|
109
|
-
"@typescript-eslint/eslint-plugin": "8.
|
|
110
|
-
"@typescript-eslint/parser": "8.
|
|
111
|
-
"@vitest/eslint-plugin": "1.6.
|
|
110
|
+
"@typescript-eslint/eslint-plugin": "8.67.0",
|
|
111
|
+
"@typescript-eslint/parser": "8.67.0",
|
|
112
|
+
"@vitest/eslint-plugin": "1.6.27",
|
|
112
113
|
"@vue/eslint-config-prettier": "10.2.0",
|
|
113
114
|
"@vue/eslint-config-typescript": "14.9.0",
|
|
114
115
|
"@vue/tsconfig": "0.9.1",
|
|
115
|
-
"eslint": "10.8.
|
|
116
|
+
"eslint": "10.8.1",
|
|
116
117
|
"eslint-plugin-prettier": "5.5.6",
|
|
117
118
|
"eslint-plugin-vue": "10.10.0",
|
|
118
119
|
"fallow": "2.101.0",
|
|
@@ -120,13 +121,19 @@
|
|
|
120
121
|
"lefthook": "2.1.10",
|
|
121
122
|
"npm-check-updates": "22.2.7",
|
|
122
123
|
"prettier": "3.9.6",
|
|
123
|
-
"tsx": "4.23.
|
|
124
|
+
"tsx": "4.23.12",
|
|
124
125
|
"typescript": "5.9.3",
|
|
125
126
|
"vue-eslint-parser": "10.4.1",
|
|
126
127
|
"vue-tsc": "3.3.9"
|
|
127
128
|
},
|
|
128
129
|
"devDependencies": {
|
|
129
|
-
"cz-git": "1.13.
|
|
130
|
-
"czg": "1.13.
|
|
130
|
+
"cz-git": "1.13.2",
|
|
131
|
+
"czg": "1.13.2"
|
|
132
|
+
},
|
|
133
|
+
"scripts": {
|
|
134
|
+
"maintainer-ui": "pnpm --dir electron/maintainer-ui start",
|
|
135
|
+
"maintainer-ui:install": "pnpm --dir electron/maintainer-ui install",
|
|
136
|
+
"fgd-ui": "pnpm --dir electron/maintainer-ui start",
|
|
137
|
+
"fgd-ui:install": "pnpm --dir electron/maintainer-ui install"
|
|
131
138
|
}
|
|
132
139
|
}
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
"poeditor:upload": "pnpm exec fg-devkit poeditor-upload"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@tailwindcss/postcss": "4.3.3",
|
|
19
18
|
"@tailwindcss/vite": "4.3.3",
|
|
20
19
|
"@tanstack/vue-query": "5.101.4",
|
|
21
20
|
"axios": "1.19.0",
|
|
@@ -34,12 +33,12 @@
|
|
|
34
33
|
"@tanstack/vue-query-devtools": "6.1.38",
|
|
35
34
|
"@types/node": "22.16.5",
|
|
36
35
|
"@vitejs/plugin-vue": "6.0.8",
|
|
37
|
-
"fg-devkit": "1.
|
|
36
|
+
"fg-devkit": "1.14.2",
|
|
38
37
|
"tailwindcss": "4.3.3",
|
|
39
|
-
"tsx": "4.23.
|
|
38
|
+
"tsx": "4.23.12",
|
|
40
39
|
"vite": "7.3.5"
|
|
41
40
|
},
|
|
42
|
-
"packageManager": "pnpm@11.
|
|
41
|
+
"packageManager": "pnpm@11.21.0",
|
|
43
42
|
"engines": {
|
|
44
43
|
"node": ">=22.13.0"
|
|
45
44
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Fix one
|
|
3
|
+
* Fix one or more vulnerabilities via `pnpm audit --fix override -i`, install, then auto-commit.
|
|
4
4
|
*
|
|
5
5
|
* Usage:
|
|
6
6
|
* pnpm exec fg-devkit audit-override-commit [pnpm-audit-args...]
|
|
@@ -150,14 +150,11 @@ function main() {
|
|
|
150
150
|
console.log('[audit-override-commit] No override changes detected.')
|
|
151
151
|
process.exit(0)
|
|
152
152
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
console.log('[audit-override-commit] Auto-commit supports exactly one override change. Commit manually.')
|
|
160
|
-
process.exit(1)
|
|
153
|
+
|
|
154
|
+
console.log('[audit-override-commit] Override changes detected:')
|
|
155
|
+
for (const item of changed) {
|
|
156
|
+
const fromLabel = item.from ?? '(missing)'
|
|
157
|
+
console.log(` - ${item.name}: ${fromLabel} -> ${item.to}`)
|
|
161
158
|
}
|
|
162
159
|
|
|
163
160
|
const installExitCode = runPnpm(['install'])
|
|
@@ -165,16 +162,30 @@ function main() {
|
|
|
165
162
|
process.exit(installExitCode)
|
|
166
163
|
}
|
|
167
164
|
|
|
168
|
-
const [only] = changed
|
|
169
165
|
const stageExitCode = stageExistingFiles(['package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml'])
|
|
170
166
|
if (stageExitCode !== 0) {
|
|
171
167
|
process.exit(stageExitCode)
|
|
172
168
|
}
|
|
173
169
|
|
|
174
|
-
const
|
|
175
|
-
console.log(`[audit-override-commit]
|
|
176
|
-
|
|
177
|
-
|
|
170
|
+
const { subject, body } = buildCommitMessage(changed)
|
|
171
|
+
console.log(`[audit-override-commit] Auto-committing: ${subject}`)
|
|
172
|
+
if (body) {
|
|
173
|
+
console.log(body)
|
|
174
|
+
}
|
|
175
|
+
const commitArgs = body ? ['commit', '-m', subject, '-m', body] : ['commit', '-m', subject]
|
|
176
|
+
process.exit(runGit(commitArgs))
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function buildCommitMessage(changed) {
|
|
180
|
+
if (changed.length === 1) {
|
|
181
|
+
const only = changed[0]
|
|
182
|
+
return { subject: `vuln(${only.name}): override ${only.to}`, body: '' }
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const body = changed
|
|
186
|
+
.map((item) => `- ${item.name}: ${item.from ?? '(missing)'} -> ${item.to}`)
|
|
187
|
+
.join('\n')
|
|
188
|
+
return { subject: `vuln(): override ${changed.length} packages`, body }
|
|
178
189
|
}
|
|
179
190
|
|
|
180
191
|
main()
|
package/scripts/fg-devkit.mjs
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Non-interactive (for scripts and automation):
|
|
6
6
|
* pnpm exec fg-devkit check-deps [policy-file]
|
|
7
7
|
* pnpm exec fg-devkit sync-deps [policy-file]
|
|
8
|
+
* pnpm exec fg-devkit sync-deps-commit [policy-file]
|
|
8
9
|
* pnpm exec fg-devkit policy-outdated [policy-file]
|
|
9
10
|
* pnpm exec fg-devkit policy-vulns [policy-file]
|
|
10
11
|
* pnpm exec fg-devkit repo-vulns
|
|
@@ -458,6 +459,7 @@ function runSyncConfigTarget(target) {
|
|
|
458
459
|
const DIRECT_COMMANDS = {
|
|
459
460
|
'check-deps': 'check-dependency-policy.mjs',
|
|
460
461
|
'sync-deps': 'sync-dependency-policy.mjs',
|
|
462
|
+
'sync-deps-commit': 'sync-dependency-policy-commit.mjs',
|
|
461
463
|
'policy-outdated': 'policy-outdated.mjs',
|
|
462
464
|
'policy-vulns': 'policy-vulns.mjs',
|
|
463
465
|
'repo-vulns': 'repo-vulns.mjs',
|
|
@@ -498,9 +500,10 @@ function printHelp() {
|
|
|
498
500
|
Commands:
|
|
499
501
|
check-deps [policy-file] Validate package.json + pins + toolchain against policy
|
|
500
502
|
sync-deps [policy-file] Align declared versions, packageManager, and Node toolchain to policy
|
|
503
|
+
sync-deps-commit [policy-file] Sync dependency policy, pnpm install, then auto-commit
|
|
501
504
|
policy-outdated [policy-file] Show outdated policy packages via pnpm outdated
|
|
502
505
|
policy-vulns [policy-file] Check all policy packages together (including transitives) via pnpm audit
|
|
503
|
-
repo-vulns Check
|
|
506
|
+
repo-vulns Check repo + nested lockfile packages via pnpm audit
|
|
504
507
|
fleet-vulns [projects-root] [--summary-only] [--delay-ms=<ms>]
|
|
505
508
|
Run pnpm audit across Vue repos (full output + combined summary)
|
|
506
509
|
fleet-bump-fg-devkit [projects-root] [--dry-run]
|
|
@@ -532,11 +535,11 @@ Commands:
|
|
|
532
535
|
Maintainer: discard tracked git changes in chosen repositories
|
|
533
536
|
Options: --dry-run, --fg-devkit-only, --pick, --all, --only=a,b
|
|
534
537
|
policy-upgrade [policy-file] [ncu-args...]
|
|
535
|
-
Upgrade policy packages via
|
|
538
|
+
Upgrade policy packages via ncu (interactive) and auto-commit
|
|
536
539
|
policy-upgrade-commit [ncu-args...]
|
|
537
|
-
Upgrade one consumer package.json
|
|
540
|
+
Upgrade one or more consumer package.json packages and auto-commit
|
|
538
541
|
audit-override-commit [pnpm-audit-args...]
|
|
539
|
-
Fix one vulnerability
|
|
542
|
+
Fix one or more vulnerability overrides via pnpm audit and auto-commit
|
|
540
543
|
sync-project-configs VS Code + tooling sync (overwrites config files)
|
|
541
544
|
sync-tooling-configs Tooling sync only (overwrites config files)
|
|
542
545
|
sync-vscode-settings Copy shared VS Code settings into .vscode/settings.json
|
|
@@ -781,9 +784,9 @@ async function runInteractiveMenu() {
|
|
|
781
784
|
message: 'Dependecy policy',
|
|
782
785
|
choices: [
|
|
783
786
|
{ name: 'Check', value: 'check' },
|
|
784
|
-
{ name: 'Sync', value: 'sync' },
|
|
785
|
-
{ name: 'Upgrade
|
|
786
|
-
{ name: 'Fix
|
|
787
|
+
{ name: 'Sync and auto-commit', value: 'sync-commit' },
|
|
788
|
+
{ name: 'Upgrade package.json packages and auto-commit', value: 'upgrade-commit' },
|
|
789
|
+
{ name: 'Fix vulnerability overrides and auto-commit', value: 'audit-override-commit' },
|
|
787
790
|
{ name: 'Cancel', value: 'cancel' },
|
|
788
791
|
],
|
|
789
792
|
default: 'check',
|
|
@@ -791,7 +794,9 @@ async function runInteractiveMenu() {
|
|
|
791
794
|
})
|
|
792
795
|
if (choice === 'cancel') continue
|
|
793
796
|
if (choice === 'check') return runSelectedAction(() => runNode('check-dependency-policy.mjs'))
|
|
794
|
-
if (choice === 'sync')
|
|
797
|
+
if (choice === 'sync-commit') {
|
|
798
|
+
return runSelectedAction(() => runNode('sync-dependency-policy-commit.mjs'))
|
|
799
|
+
}
|
|
795
800
|
if (choice === 'audit-override-commit') {
|
|
796
801
|
return runSelectedAction(() => runNode('audit-override-commit.mjs'))
|
|
797
802
|
}
|
|
@@ -852,7 +857,7 @@ async function runInteractiveMenu() {
|
|
|
852
857
|
message: 'Maintainer',
|
|
853
858
|
choices: [
|
|
854
859
|
{ name: 'Show outdated dependency policy packages', value: 'm1' },
|
|
855
|
-
{ name: 'Upgrade dependency policy (interactive)', value: 'm2' },
|
|
860
|
+
{ name: 'Upgrade dependency policy (interactive) and auto-commit', value: 'm2' },
|
|
856
861
|
{ name: 'Refresh dependency policy from repos (and scaffold/vue package.json)', value: 'm3' },
|
|
857
862
|
{ name: 'Check policy vulnerabilities (audit)', value: 'm4' },
|
|
858
863
|
{ name: 'Check fg-devkit repo vulnerabilities', value: 'm5' },
|
|
@@ -3,47 +3,86 @@
|
|
|
3
3
|
* Bumps fg-devkit to latest in Vue repositories, syncs dependency policy, and runs pnpm install.
|
|
4
4
|
*
|
|
5
5
|
* Usage:
|
|
6
|
-
* pnpm exec fg-devkit fleet-bump-fg-devkit [projects-root] [
|
|
6
|
+
* pnpm exec fg-devkit fleet-bump-fg-devkit [projects-root] [options]
|
|
7
|
+
*
|
|
8
|
+
* Options:
|
|
9
|
+
* --dry-run Print planned bumps without changing files or installing
|
|
10
|
+
* --all Run on all matching Vue repos (default when not picking)
|
|
11
|
+
* --fg-devkit-only No-op for this command (fg-devkit is not a consumer of itself)
|
|
12
|
+
* --pick Interactive checkbox (TTY); prefer --only= from automation/UI
|
|
13
|
+
* --only=a,b Run only on matching repos (basename or path under projects root)
|
|
7
14
|
*/
|
|
8
15
|
|
|
16
|
+
import fs from 'node:fs'
|
|
9
17
|
import path from 'node:path'
|
|
10
18
|
import { spawnSync } from 'node:child_process'
|
|
11
19
|
import { fileURLToPath } from 'node:url'
|
|
12
20
|
|
|
13
21
|
import { collectFleetVueRepos } from './fleet-vue-repos.mjs'
|
|
22
|
+
import { parseFleetSelectionFlags, resolveFleetRepos } from './fleet-repo-picker.mjs'
|
|
14
23
|
|
|
15
24
|
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
|
|
16
25
|
const cliArgs = process.argv.slice(2)
|
|
17
26
|
const dryRun = cliArgs.includes('--dry-run')
|
|
18
|
-
const
|
|
19
|
-
const
|
|
27
|
+
const fgDevkitOnly = cliArgs.includes('--fg-devkit-only')
|
|
28
|
+
const { pick, all, only, filteredArgs: positionalArgs } = parseFleetSelectionFlags(cliArgs)
|
|
29
|
+
const projectsRootArg = positionalArgs.find((a) => !a.startsWith('-'))
|
|
30
|
+
const projectsRoot = projectsRootArg
|
|
31
|
+
? path.resolve(process.cwd(), projectsRootArg)
|
|
32
|
+
: path.resolve(scriptDir, '../..')
|
|
33
|
+
|
|
34
|
+
const LOG_PREFIX = '[fleet-bump-fg-devkit]'
|
|
35
|
+
|
|
36
|
+
if (fgDevkitOnly) {
|
|
37
|
+
console.log(
|
|
38
|
+
`${LOG_PREFIX} Nothing to do for fg-devkit only — bump targets Vue consumer repos that depend on fg-devkit.`,
|
|
39
|
+
)
|
|
40
|
+
process.exit(0)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (!fs.existsSync(projectsRoot)) {
|
|
44
|
+
console.error(`${LOG_PREFIX} projects root not found: ${projectsRoot}`)
|
|
45
|
+
process.exit(1)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const allRepos = collectFleetVueRepos(projectsRoot)
|
|
49
|
+
if (allRepos.length === 0) {
|
|
50
|
+
console.log(`${LOG_PREFIX} No Vue repositories with fg-devkit found under ${projectsRoot}`)
|
|
51
|
+
process.exit(0)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const uniqueRepos = await resolveFleetRepos(allRepos, projectsRoot, {
|
|
55
|
+
pick,
|
|
56
|
+
only,
|
|
57
|
+
all: all || (!pick && !only),
|
|
58
|
+
message: 'Select Vue repositories to bump fg-devkit',
|
|
59
|
+
})
|
|
20
60
|
|
|
21
|
-
const uniqueRepos = collectFleetVueRepos(projectsRoot)
|
|
22
61
|
if (uniqueRepos.length === 0) {
|
|
23
|
-
console.log(
|
|
62
|
+
console.log(`${LOG_PREFIX} No repositories selected.`)
|
|
24
63
|
process.exit(0)
|
|
25
64
|
}
|
|
26
65
|
|
|
27
|
-
console.log(
|
|
28
|
-
console.log(
|
|
66
|
+
console.log(`${LOG_PREFIX} projectsRoot=${projectsRoot}`)
|
|
67
|
+
console.log(`${LOG_PREFIX} repositories=${uniqueRepos.length}`)
|
|
29
68
|
|
|
30
69
|
let failures = 0
|
|
31
70
|
let updated = 0
|
|
32
71
|
|
|
33
72
|
for (const repoDir of uniqueRepos) {
|
|
34
|
-
const repoName = path.basename(repoDir)
|
|
73
|
+
const repoName = path.relative(projectsRoot, repoDir).split(path.sep).join('/') || path.basename(repoDir)
|
|
35
74
|
const bumpArgs = ['up', 'fg-devkit@latest']
|
|
36
75
|
const syncDepsArgs = ['exec', 'fg-devkit', 'sync-deps']
|
|
37
76
|
const installArgs = ['install']
|
|
38
77
|
|
|
39
78
|
if (dryRun) {
|
|
40
|
-
console.log(
|
|
41
|
-
console.log(
|
|
42
|
-
console.log(
|
|
79
|
+
console.log(`${LOG_PREFIX} DRY RUN ${repoName}: pnpm ${bumpArgs.join(' ')}`)
|
|
80
|
+
console.log(`${LOG_PREFIX} DRY RUN ${repoName}: pnpm ${syncDepsArgs.join(' ')}`)
|
|
81
|
+
console.log(`${LOG_PREFIX} DRY RUN ${repoName}: pnpm ${installArgs.join(' ')}`)
|
|
43
82
|
continue
|
|
44
83
|
}
|
|
45
84
|
|
|
46
|
-
console.log(`\n
|
|
85
|
+
console.log(`\n${LOG_PREFIX} Updating ${repoName}`)
|
|
47
86
|
const bump = spawnSync('pnpm', bumpArgs, {
|
|
48
87
|
cwd: repoDir,
|
|
49
88
|
stdio: 'inherit',
|
|
@@ -56,14 +95,14 @@ for (const repoDir of uniqueRepos) {
|
|
|
56
95
|
|
|
57
96
|
if (bump.error) {
|
|
58
97
|
failures += 1
|
|
59
|
-
console.error(
|
|
98
|
+
console.error(`${LOG_PREFIX} FAIL ${repoName}: ${bump.error.message}`)
|
|
60
99
|
continue
|
|
61
100
|
}
|
|
62
101
|
|
|
63
102
|
const bumpStatus = bump.status ?? 1
|
|
64
103
|
if (bumpStatus !== 0) {
|
|
65
104
|
failures += 1
|
|
66
|
-
console.error(
|
|
105
|
+
console.error(`${LOG_PREFIX} FAIL ${repoName}: pnpm up exited with code ${bumpStatus}`)
|
|
67
106
|
continue
|
|
68
107
|
}
|
|
69
108
|
|
|
@@ -79,14 +118,14 @@ for (const repoDir of uniqueRepos) {
|
|
|
79
118
|
|
|
80
119
|
if (syncDeps.error) {
|
|
81
120
|
failures += 1
|
|
82
|
-
console.error(
|
|
121
|
+
console.error(`${LOG_PREFIX} FAIL ${repoName}: ${syncDeps.error.message}`)
|
|
83
122
|
continue
|
|
84
123
|
}
|
|
85
124
|
|
|
86
125
|
const syncDepsStatus = syncDeps.status ?? 1
|
|
87
126
|
if (syncDepsStatus !== 0) {
|
|
88
127
|
failures += 1
|
|
89
|
-
console.error(
|
|
128
|
+
console.error(`${LOG_PREFIX} FAIL ${repoName}: sync-deps exited with code ${syncDepsStatus}`)
|
|
90
129
|
continue
|
|
91
130
|
}
|
|
92
131
|
|
|
@@ -102,20 +141,20 @@ for (const repoDir of uniqueRepos) {
|
|
|
102
141
|
|
|
103
142
|
if (install.error) {
|
|
104
143
|
failures += 1
|
|
105
|
-
console.error(
|
|
144
|
+
console.error(`${LOG_PREFIX} FAIL ${repoName}: ${install.error.message}`)
|
|
106
145
|
continue
|
|
107
146
|
}
|
|
108
147
|
|
|
109
148
|
const status = install.status ?? 1
|
|
110
149
|
if (status !== 0) {
|
|
111
150
|
failures += 1
|
|
112
|
-
console.error(
|
|
151
|
+
console.error(`${LOG_PREFIX} FAIL ${repoName}: pnpm install exited with code ${status}`)
|
|
113
152
|
continue
|
|
114
153
|
}
|
|
115
154
|
|
|
116
155
|
updated += 1
|
|
117
|
-
console.log(
|
|
156
|
+
console.log(`${LOG_PREFIX} OK ${repoName}`)
|
|
118
157
|
}
|
|
119
158
|
|
|
120
|
-
console.log(`\n
|
|
159
|
+
console.log(`\n${LOG_PREFIX} Done: updated=${updated}, failed=${failures}`)
|
|
121
160
|
process.exit(failures > 0 ? 1 : 0)
|
package/scripts/fleet-vulns.mjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* pnpm audit output and a combined summary.
|
|
5
5
|
*
|
|
6
6
|
* Usage:
|
|
7
|
-
* pnpm exec fg-devkit fleet-vulns [projects-root] [--summary-only] [--delay-ms=<ms>]
|
|
7
|
+
* pnpm exec fg-devkit fleet-vulns [projects-root] [--summary-only] [--delay-ms=<ms>] [--dry-run] [--only=a,b]
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import fs from 'node:fs'
|
|
@@ -12,10 +12,13 @@ import path from 'node:path'
|
|
|
12
12
|
import { spawnSync } from 'node:child_process'
|
|
13
13
|
import { fileURLToPath } from 'node:url'
|
|
14
14
|
import { isFgDevkitRepoDir } from './fleet-project-repos.mjs'
|
|
15
|
+
import { filterReposByOnly, parseFleetOnlyArg } from './fleet-repo-picker.mjs'
|
|
15
16
|
|
|
16
17
|
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
|
|
17
18
|
const cliArgs = process.argv.slice(2)
|
|
18
19
|
const summaryOnly = cliArgs.includes('--summary-only')
|
|
20
|
+
const dryRun = cliArgs.includes('--dry-run')
|
|
21
|
+
const only = parseFleetOnlyArg(cliArgs)
|
|
19
22
|
const projectsRootArg = cliArgs.find((a) => !a.startsWith('-'))
|
|
20
23
|
const projectsRoot = projectsRootArg ? path.resolve(process.cwd(), projectsRootArg) : path.resolve(scriptDir, '../..')
|
|
21
24
|
const delayArg = cliArgs.find((a) => a.startsWith('--delay-ms='))
|
|
@@ -63,7 +66,16 @@ for (const packageJsonPath of packageJsonFiles) {
|
|
|
63
66
|
}
|
|
64
67
|
}
|
|
65
68
|
|
|
66
|
-
const
|
|
69
|
+
const uniqueReposAll = [...new Set(repos)].sort((a, b) => a.localeCompare(b))
|
|
70
|
+
let uniqueRepos = uniqueReposAll
|
|
71
|
+
if (only?.length) {
|
|
72
|
+
uniqueRepos = filterReposByOnly(uniqueReposAll, projectsRoot, only)
|
|
73
|
+
if (uniqueRepos.length === 0) {
|
|
74
|
+
console.error(`[fleet-vulns] No repositories matched --only=${only.join(',')}`)
|
|
75
|
+
process.exit(1)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
67
79
|
if (uniqueRepos.length === 0) {
|
|
68
80
|
console.log(`[fleet-vulns] No pnpm repositories found under ${projectsRoot}`)
|
|
69
81
|
process.exit(0)
|
|
@@ -72,6 +84,16 @@ if (uniqueRepos.length === 0) {
|
|
|
72
84
|
console.log(`[fleet-vulns] projectsRoot=${projectsRoot}`)
|
|
73
85
|
console.log(`[fleet-vulns] repositories=${uniqueRepos.length}`)
|
|
74
86
|
|
|
87
|
+
if (dryRun) {
|
|
88
|
+
console.log('[fleet-vulns] DRY RUN — would audit:')
|
|
89
|
+
for (const repoDir of uniqueRepos) {
|
|
90
|
+
const rel = path.relative(projectsRoot, repoDir).split(path.sep).join('/') || path.basename(repoDir)
|
|
91
|
+
const hasLock = fs.existsSync(path.join(repoDir, 'pnpm-lock.yaml'))
|
|
92
|
+
console.log(` - ${rel}${hasLock ? '' : ' (missing pnpm-lock.yaml → skip)'}`)
|
|
93
|
+
}
|
|
94
|
+
process.exit(0)
|
|
95
|
+
}
|
|
96
|
+
|
|
75
97
|
const results = []
|
|
76
98
|
let hasFailures = false
|
|
77
99
|
let hasVulnerabilities = false
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Upgrade one
|
|
3
|
+
* Upgrade one or more packages in the consumer package.json, then auto-commit.
|
|
4
4
|
*
|
|
5
5
|
* Usage:
|
|
6
6
|
* pnpm exec fg-devkit policy-upgrade-commit [ncu-args...]
|
|
@@ -87,6 +87,21 @@ function collectPackageVersionChanges(beforePackage, afterPackage) {
|
|
|
87
87
|
return changed
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
/** ncu can upgrade package.json `packageManager` (e.g. pnpm@x.y.z); treat as one bump. */
|
|
91
|
+
function collectPackageManagerChange(beforePackage, afterPackage) {
|
|
92
|
+
const before = beforePackage.packageManager
|
|
93
|
+
const after = afterPackage.packageManager
|
|
94
|
+
if (after === undefined || after === before) {
|
|
95
|
+
return null
|
|
96
|
+
}
|
|
97
|
+
const match = typeof after === 'string' ? after.match(/^pnpm@(.+)$/i) : null
|
|
98
|
+
return {
|
|
99
|
+
name: 'pnpm',
|
|
100
|
+
from: before ?? '(missing)',
|
|
101
|
+
to: match ? match[1] : after,
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
90
105
|
function main() {
|
|
91
106
|
if (!fs.existsSync(packageJsonPath)) {
|
|
92
107
|
console.error(`[policy-upgrade-commit] package.json not found at ${packageJsonPath}`)
|
|
@@ -115,29 +130,43 @@ function main() {
|
|
|
115
130
|
}
|
|
116
131
|
|
|
117
132
|
const changed = collectPackageVersionChanges(beforePackage, afterPackage)
|
|
133
|
+
const packageManagerChange = collectPackageManagerChange(beforePackage, afterPackage)
|
|
134
|
+
if (packageManagerChange) {
|
|
135
|
+
changed.push(packageManagerChange)
|
|
136
|
+
}
|
|
137
|
+
|
|
118
138
|
if (changed.length === 0) {
|
|
119
139
|
console.log('[policy-upgrade-commit] No package version changes detected in package.json.')
|
|
120
140
|
process.exit(0)
|
|
121
141
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
console.log('[policy-upgrade-commit] Auto-commit supports exactly one changed package. Commit manually.')
|
|
128
|
-
process.exit(1)
|
|
142
|
+
|
|
143
|
+
console.log('[policy-upgrade-commit] Package version changes detected in package.json:')
|
|
144
|
+
for (const item of changed) {
|
|
145
|
+
console.log(` - ${item.name}: ${item.from} -> ${item.to}`)
|
|
129
146
|
}
|
|
130
147
|
|
|
131
|
-
const [only] = changed
|
|
132
148
|
const stageExitCode = stageExistingFiles(['package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml'])
|
|
133
149
|
if (stageExitCode !== 0) {
|
|
134
150
|
process.exit(stageExitCode)
|
|
135
151
|
}
|
|
136
152
|
|
|
137
|
-
const
|
|
138
|
-
console.log(`[policy-upgrade-commit]
|
|
139
|
-
|
|
140
|
-
|
|
153
|
+
const { subject, body } = buildCommitMessage(changed)
|
|
154
|
+
console.log(`[policy-upgrade-commit] Auto-committing: ${subject}`)
|
|
155
|
+
if (body) {
|
|
156
|
+
console.log(body)
|
|
157
|
+
}
|
|
158
|
+
const commitArgs = body ? ['commit', '-m', subject, '-m', body] : ['commit', '-m', subject]
|
|
159
|
+
process.exit(runGit(commitArgs))
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function buildCommitMessage(changed) {
|
|
163
|
+
if (changed.length === 1) {
|
|
164
|
+
const only = changed[0]
|
|
165
|
+
return { subject: `dep(${only.name}): bump to ${only.to}`, body: '' }
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const body = changed.map((item) => `- ${item.name}: ${item.from} -> ${item.to}`).join('\n')
|
|
169
|
+
return { subject: `dep(): bump ${changed.length} packages`, body }
|
|
141
170
|
}
|
|
142
171
|
|
|
143
172
|
main()
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Upgrades dependency policy package versions through npm-check-updates.
|
|
4
|
-
* It projects the policy into a temporary package.json, runs ncu,
|
|
5
|
-
*
|
|
3
|
+
* Upgrades dependency policy package versions through npm-check-updates, then auto-commits.
|
|
4
|
+
* It projects the policy into a temporary package.json, runs ncu, writes selected versions
|
|
5
|
+
* back to the policy file, syncs scaffold, and commits.
|
|
6
6
|
*
|
|
7
7
|
* Usage:
|
|
8
8
|
* pnpm exec fg-devkit policy-upgrade [policy-file] [ncu-args...]
|
|
@@ -22,6 +22,7 @@ import { syncScaffoldVueDepsFromPolicy } from './sync-scaffold-vue-deps.mjs'
|
|
|
22
22
|
|
|
23
23
|
const require = createRequire(import.meta.url)
|
|
24
24
|
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
|
|
25
|
+
const fgDevkitRoot = path.resolve(scriptDir, '..')
|
|
25
26
|
|
|
26
27
|
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
27
28
|
console.log(`Usage:
|
|
@@ -42,7 +43,60 @@ function readJson(p) {
|
|
|
42
43
|
return JSON.parse(fs.readFileSync(p, 'utf8'))
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
function collectPolicyVersions(policy) {
|
|
47
|
+
return {
|
|
48
|
+
...(policy.managedDependencies?.dependencies ?? {}),
|
|
49
|
+
...(policy.managedDependencies?.devDependencies ?? {}),
|
|
50
|
+
...(policy.managedAnywhere ?? {}),
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function collectVersionChanges(before, after) {
|
|
55
|
+
const changed = []
|
|
56
|
+
for (const [name, newVersion] of Object.entries(after)) {
|
|
57
|
+
const previousVersion = before[name]
|
|
58
|
+
if (previousVersion !== undefined && previousVersion !== newVersion) {
|
|
59
|
+
changed.push({ name, from: previousVersion, to: newVersion })
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return changed
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function buildCommitMessage(changed) {
|
|
66
|
+
if (changed.length === 1) {
|
|
67
|
+
const only = changed[0]
|
|
68
|
+
return { subject: `dep(${only.name}): bump to ${only.to}`, body: '' }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const body = changed.map((item) => `- ${item.name}: ${item.from} -> ${item.to}`).join('\n')
|
|
72
|
+
return { subject: `dep(): bump ${changed.length} packages`, body }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function runGit(args) {
|
|
76
|
+
const result = spawnSync('git', args, {
|
|
77
|
+
stdio: 'inherit',
|
|
78
|
+
cwd: fgDevkitRoot,
|
|
79
|
+
env: process.env,
|
|
80
|
+
})
|
|
81
|
+
if (result.error) {
|
|
82
|
+
console.error('[policy-upgrade]', result.error.message)
|
|
83
|
+
return 1
|
|
84
|
+
}
|
|
85
|
+
return result.status ?? 1
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function stageExistingFiles(files) {
|
|
89
|
+
const existingFiles = files.filter((filePath) => fs.existsSync(path.join(fgDevkitRoot, filePath)))
|
|
90
|
+
if (existingFiles.length === 0) return 0
|
|
91
|
+
return runGit(['add', '--', ...existingFiles])
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function toRepoRelative(absolutePath) {
|
|
95
|
+
return path.relative(fgDevkitRoot, absolutePath)
|
|
96
|
+
}
|
|
97
|
+
|
|
45
98
|
const policy = readJson(policyPath)
|
|
99
|
+
const beforeVersions = collectPolicyVersions(policy)
|
|
46
100
|
|
|
47
101
|
const depNames = new Set(Object.keys(policy.managedDependencies?.dependencies ?? {}))
|
|
48
102
|
const devNames = new Set(Object.keys(policy.managedDependencies?.devDependencies ?? {}))
|
|
@@ -115,6 +169,34 @@ for (const [name, version] of Object.entries(updatedDevDeps)) {
|
|
|
115
169
|
}
|
|
116
170
|
|
|
117
171
|
fs.writeFileSync(policyPath, `${JSON.stringify(policy, null, 2)}\n`, 'utf8')
|
|
118
|
-
const fgDevkitRoot = path.resolve(scriptDir, '..')
|
|
119
172
|
syncScaffoldVueDepsFromPolicy({ fgDevkitRoot, policyPath })
|
|
120
|
-
|
|
173
|
+
|
|
174
|
+
const afterPolicy = readJson(policyPath)
|
|
175
|
+
const changed = collectVersionChanges(beforeVersions, collectPolicyVersions(afterPolicy))
|
|
176
|
+
|
|
177
|
+
if (changed.length === 0) {
|
|
178
|
+
console.log('[policy-upgrade] No package version changes detected in dependency policy.')
|
|
179
|
+
process.exit(0)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
console.log('[policy-upgrade] Package version changes detected in dependency policy:')
|
|
183
|
+
for (const item of changed) {
|
|
184
|
+
console.log(` - ${item.name}: ${item.from} -> ${item.to}`)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const stageExitCode = stageExistingFiles([
|
|
188
|
+
toRepoRelative(policyPath),
|
|
189
|
+
'scaffold/vue/package.json',
|
|
190
|
+
'scaffold/vue/Dockerfile.local',
|
|
191
|
+
])
|
|
192
|
+
if (stageExitCode !== 0) {
|
|
193
|
+
process.exit(stageExitCode)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const { subject, body } = buildCommitMessage(changed)
|
|
197
|
+
console.log(`[policy-upgrade] Auto-committing: ${subject}`)
|
|
198
|
+
if (body) {
|
|
199
|
+
console.log(body)
|
|
200
|
+
}
|
|
201
|
+
const commitArgs = body ? ['commit', '-m', subject, '-m', body] : ['commit', '-m', subject]
|
|
202
|
+
process.exit(runGit(commitArgs))
|
package/scripts/repo-vulns.mjs
CHANGED
|
@@ -1,26 +1,83 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* Checks vulnerabilities for the full dependency graph in the current repository
|
|
4
|
-
* by running `pnpm audit` in the working directory
|
|
4
|
+
* by running `pnpm audit` in the working directory and any nested packages that
|
|
5
|
+
* have their own pnpm-lock.yaml (e.g. electron/maintainer-ui in fg-devkit).
|
|
5
6
|
*
|
|
6
7
|
* Usage:
|
|
7
8
|
* pnpm exec fg-devkit repo-vulns
|
|
8
9
|
*/
|
|
9
10
|
|
|
11
|
+
import fs from 'node:fs'
|
|
12
|
+
import path from 'node:path'
|
|
10
13
|
import { spawnSync } from 'node:child_process'
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
const root = process.cwd()
|
|
16
|
+
|
|
17
|
+
const SKIP_DIR_NAMES = new Set([
|
|
18
|
+
'node_modules',
|
|
19
|
+
'.git',
|
|
20
|
+
'.next',
|
|
21
|
+
'dist',
|
|
22
|
+
'build',
|
|
23
|
+
'coverage',
|
|
24
|
+
'storybook-static',
|
|
25
|
+
])
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {string} dir
|
|
29
|
+
* @param {string[]} [acc]
|
|
30
|
+
* @returns {string[]}
|
|
31
|
+
*/
|
|
32
|
+
function findNestedLockfileDirs(dir, acc = []) {
|
|
33
|
+
for (const item of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
34
|
+
if (!item.isDirectory()) continue
|
|
35
|
+
if (SKIP_DIR_NAMES.has(item.name) || item.name.startsWith('.')) continue
|
|
36
|
+
const child = path.join(dir, item.name)
|
|
37
|
+
if (
|
|
38
|
+
fs.existsSync(path.join(child, 'pnpm-lock.yaml')) &&
|
|
39
|
+
fs.existsSync(path.join(child, 'package.json'))
|
|
40
|
+
) {
|
|
41
|
+
acc.push(child)
|
|
42
|
+
}
|
|
43
|
+
findNestedLockfileDirs(child, acc)
|
|
44
|
+
}
|
|
45
|
+
return acc
|
|
21
46
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @param {string} dir
|
|
50
|
+
* @param {string} label
|
|
51
|
+
* @returns {number}
|
|
52
|
+
*/
|
|
53
|
+
function auditDir(dir, label) {
|
|
54
|
+
console.log(`\n[repo-vulns] Auditing ${label}`)
|
|
55
|
+
console.log(`[repo-vulns] cwd=${dir}`)
|
|
56
|
+
const audit = spawnSync('pnpm', ['audit'], {
|
|
57
|
+
cwd: dir,
|
|
58
|
+
stdio: 'inherit',
|
|
59
|
+
env: process.env,
|
|
60
|
+
})
|
|
61
|
+
if (audit.error) {
|
|
62
|
+
console.error('[repo-vulns]', audit.error.message)
|
|
63
|
+
return 1
|
|
64
|
+
}
|
|
65
|
+
return audit.status ?? 1
|
|
25
66
|
}
|
|
26
|
-
|
|
67
|
+
|
|
68
|
+
const nested = findNestedLockfileDirs(root).sort((a, b) => a.localeCompare(b))
|
|
69
|
+
const targets = [root, ...nested]
|
|
70
|
+
|
|
71
|
+
console.log(`[repo-vulns] packages=${targets.length}`)
|
|
72
|
+
|
|
73
|
+
let worstFailure = 0
|
|
74
|
+
|
|
75
|
+
for (const dir of targets) {
|
|
76
|
+
const label = dir === root ? '.' : path.relative(root, dir).split(path.sep).join('/')
|
|
77
|
+
const code = auditDir(dir, label)
|
|
78
|
+
// pnpm audit returns exit code 1 when vulnerabilities are found — treat as ok.
|
|
79
|
+
if (code === 0 || code === 1) continue
|
|
80
|
+
worstFailure = code || 1
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
process.exit(worstFailure)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Resolves which dependency policy JSON file check/sync scripts should load.
|
|
3
3
|
*
|
|
4
4
|
* Used by check-dependency-policy.mjs and sync-dependency-policy.mjs so both tools share one rule:
|
|
5
|
-
* optional argv[2] override, otherwise the packaged default
|
|
5
|
+
* optional argv[2] override (ignored when it looks like a CLI flag), otherwise the packaged default.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import fs from 'node:fs'
|
|
@@ -17,8 +17,10 @@ const DEFAULT_POLICY = 'dependency-policy.vue-workspace.json'
|
|
|
17
17
|
* - Relative path: if it exists under cwd, use it; else fg-devkit/configs/<arg>
|
|
18
18
|
*/
|
|
19
19
|
export function resolveDependencyPolicyPath(scriptDir, cwd, argv) {
|
|
20
|
+
// Optional policy path is argv[2] only when it is not an option flag
|
|
21
|
+
// (e.g. `policy-upgrade --interactive` must use the default policy file).
|
|
20
22
|
const arg = argv[2]
|
|
21
|
-
if (!arg) {
|
|
23
|
+
if (!arg || arg.startsWith('-')) {
|
|
22
24
|
return path.resolve(scriptDir, '../configs', DEFAULT_POLICY)
|
|
23
25
|
}
|
|
24
26
|
if (path.isAbsolute(arg)) {
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Sync dependency policy into the consumer repo, run pnpm install, then auto-commit.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* pnpm exec fg-devkit sync-deps-commit [policy-file]
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import fs from 'node:fs'
|
|
10
|
+
import path from 'node:path'
|
|
11
|
+
import { fileURLToPath } from 'node:url'
|
|
12
|
+
import { spawnSync } from 'node:child_process'
|
|
13
|
+
|
|
14
|
+
const cwd = process.cwd()
|
|
15
|
+
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
|
|
16
|
+
const syncScriptPath = path.join(scriptDir, 'sync-dependency-policy.mjs')
|
|
17
|
+
const commitMessage = 'chore(repo): sync dependency policy'
|
|
18
|
+
|
|
19
|
+
function runSync(args) {
|
|
20
|
+
const result = spawnSync(process.execPath, [syncScriptPath, ...args], {
|
|
21
|
+
encoding: 'utf8',
|
|
22
|
+
cwd,
|
|
23
|
+
env: process.env,
|
|
24
|
+
})
|
|
25
|
+
if (result.stdout) process.stdout.write(result.stdout)
|
|
26
|
+
if (result.stderr) process.stderr.write(result.stderr)
|
|
27
|
+
if (result.error) {
|
|
28
|
+
console.error('[sync-deps-commit]', result.error.message)
|
|
29
|
+
return { status: 1, stdout: '' }
|
|
30
|
+
}
|
|
31
|
+
return { status: result.status ?? 1, stdout: result.stdout ?? '' }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function runPnpm(args) {
|
|
35
|
+
const result = spawnSync('pnpm', args, {
|
|
36
|
+
stdio: 'inherit',
|
|
37
|
+
cwd,
|
|
38
|
+
env: process.env,
|
|
39
|
+
})
|
|
40
|
+
if (result.error) {
|
|
41
|
+
console.error('[sync-deps-commit]', result.error.message)
|
|
42
|
+
return 1
|
|
43
|
+
}
|
|
44
|
+
return result.status ?? 1
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function runGit(args, options = {}) {
|
|
48
|
+
const result = spawnSync('git', args, {
|
|
49
|
+
stdio: options.capture ? 'pipe' : 'inherit',
|
|
50
|
+
encoding: options.capture ? 'utf8' : undefined,
|
|
51
|
+
cwd,
|
|
52
|
+
env: process.env,
|
|
53
|
+
})
|
|
54
|
+
if (result.error) {
|
|
55
|
+
console.error('[sync-deps-commit]', result.error.message)
|
|
56
|
+
return { status: 1, stdout: '' }
|
|
57
|
+
}
|
|
58
|
+
return { status: result.status ?? 1, stdout: result.stdout ?? '' }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function listTrackedFiles() {
|
|
62
|
+
const result = runGit(['ls-files', '-z'], { capture: true })
|
|
63
|
+
if (result.status !== 0) return []
|
|
64
|
+
return result.stdout.split('\0').filter(Boolean)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function isSyncRelatedPath(filePath) {
|
|
68
|
+
const base = path.basename(filePath)
|
|
69
|
+
if (
|
|
70
|
+
base === 'package.json' ||
|
|
71
|
+
base === 'pnpm-lock.yaml' ||
|
|
72
|
+
base === 'pnpm-workspace.yaml' ||
|
|
73
|
+
base === '.nvmrc' ||
|
|
74
|
+
base === '.node-version' ||
|
|
75
|
+
base === 'Dockerfile' ||
|
|
76
|
+
base === 'Dockerfile.local' ||
|
|
77
|
+
base === 'Jenkinsfile'
|
|
78
|
+
) {
|
|
79
|
+
return true
|
|
80
|
+
}
|
|
81
|
+
if (filePath.includes(`${path.sep}.github${path.sep}workflows${path.sep}`) || filePath.startsWith('.github/workflows/')) {
|
|
82
|
+
return /\.(ya?ml)$/i.test(base)
|
|
83
|
+
}
|
|
84
|
+
return base.endsWith('.sh')
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function fileDiffersFromHead(filePath) {
|
|
88
|
+
const absolutePath = path.join(cwd, filePath)
|
|
89
|
+
if (!fs.existsSync(absolutePath)) return false
|
|
90
|
+
|
|
91
|
+
const tracked = runGit(['ls-files', '--error-unmatch', '--', filePath], { capture: true })
|
|
92
|
+
if (tracked.status !== 0) {
|
|
93
|
+
return true
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const diff = runGit(['diff', '--quiet', 'HEAD', '--', filePath], { capture: true })
|
|
97
|
+
return diff.status !== 0
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function stageExistingFiles(files) {
|
|
101
|
+
const existingFiles = files.filter((filePath) => fs.existsSync(path.join(cwd, filePath)))
|
|
102
|
+
if (existingFiles.length === 0) return 0
|
|
103
|
+
return runGit(['add', '--', ...existingFiles]).status
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function main() {
|
|
107
|
+
const syncResult = runSync(process.argv.slice(2))
|
|
108
|
+
if (syncResult.status !== 0) {
|
|
109
|
+
process.exit(syncResult.status)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (syncResult.stdout.includes('already match dependency policy')) {
|
|
113
|
+
console.log('[sync-deps-commit] Nothing to install or commit.')
|
|
114
|
+
process.exit(0)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const installExitCode = runPnpm(['install'])
|
|
118
|
+
if (installExitCode !== 0) {
|
|
119
|
+
process.exit(installExitCode)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const candidateFiles = new Set([
|
|
123
|
+
'package.json',
|
|
124
|
+
'pnpm-lock.yaml',
|
|
125
|
+
'pnpm-workspace.yaml',
|
|
126
|
+
'.nvmrc',
|
|
127
|
+
'.node-version',
|
|
128
|
+
'Dockerfile',
|
|
129
|
+
'Dockerfile.local',
|
|
130
|
+
'Jenkinsfile',
|
|
131
|
+
])
|
|
132
|
+
for (const filePath of listTrackedFiles()) {
|
|
133
|
+
if (isSyncRelatedPath(filePath)) {
|
|
134
|
+
candidateFiles.add(filePath)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const filesToStage = [...candidateFiles].filter((filePath) => fileDiffersFromHead(filePath))
|
|
139
|
+
if (filesToStage.length === 0) {
|
|
140
|
+
console.log('[sync-deps-commit] No sync-related changes to commit.')
|
|
141
|
+
process.exit(0)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const stageExitCode = stageExistingFiles(filesToStage)
|
|
145
|
+
if (stageExitCode !== 0) {
|
|
146
|
+
process.exit(stageExitCode)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
console.log(`[sync-deps-commit] Staged ${filesToStage.length} file(s)`)
|
|
150
|
+
console.log(`[sync-deps-commit] Auto-committing: ${commitMessage}`)
|
|
151
|
+
process.exit(runGit(['commit', '-m', commitMessage]).status)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
main()
|