fg-devkit 1.12.14 → 1.14.3
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 +7 -4
- package/configs/cliff.toml +1 -1
- package/configs/cliff.user.toml +1 -1
- package/configs/dependency-policy.vue-workspace.json +15 -15
- package/package.json +14 -8
- package/release-notes/format.ts +9 -13
- package/release-notes/serializeUserChangelog.ts +5 -2
- package/release-notes/sync-user-changelog.ts +8 -56
- package/scaffold/vue/package.json +3 -4
- package/scripts/audit-override-commit.mjs +25 -14
- package/scripts/fg-devkit.mjs +7 -7
- package/scripts/fleet-bump-fg-devkit.mjs +59 -20
- package/scripts/fleet-vulns.mjs +24 -2
- package/scripts/policy-upgrade-commit.mjs +22 -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/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,7 +126,8 @@ 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
|
|
@@ -138,13 +139,15 @@ Sync dependency policy, run pnpm install, and auto-commit (`chore(repo): sync de
|
|
|
138
139
|
pnpm exec fgd sync-deps-commit
|
|
139
140
|
```
|
|
140
141
|
|
|
141
|
-
Upgrade one package.json
|
|
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):
|
|
142
144
|
|
|
143
145
|
```bash
|
|
144
146
|
pnpm exec fgd policy-upgrade-commit
|
|
145
147
|
```
|
|
146
148
|
|
|
147
|
-
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):
|
|
148
151
|
|
|
149
152
|
```bash
|
|
150
153
|
pnpm exec fgd audit-override-commit
|
package/configs/cliff.toml
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[changelog]
|
|
6
6
|
body = """
|
|
7
7
|
{% if version %}\
|
|
8
|
-
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d
|
|
8
|
+
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
|
|
9
9
|
{% else %}\
|
|
10
10
|
## [unreleased]
|
|
11
11
|
{% endif %}\
|
package/configs/cliff.user.toml
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[changelog]
|
|
6
6
|
body = """
|
|
7
7
|
{% if version %}\
|
|
8
|
-
## Version {{ version | trim_start_matches(pat="v") }} - {{ timestamp | date(format="%Y-%m-%d
|
|
8
|
+
## Version {{ version | trim_start_matches(pat="v") }} - {{ timestamp | date(format="%Y-%m-%d") }}
|
|
9
9
|
{% else %}\
|
|
10
10
|
## [unreleased]
|
|
11
11
|
{% endif %}\
|
|
@@ -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.3",
|
|
4
4
|
"description": "Shared configs, scripts, and DX tooling for Vue / TypeScript frontend repos",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -107,13 +107,13 @@
|
|
|
107
107
|
"@inquirer/input": "5.1.2",
|
|
108
108
|
"@inquirer/select": "5.2.1",
|
|
109
109
|
"@intlify/eslint-plugin-vue-i18n": "4.5.1",
|
|
110
|
-
"@typescript-eslint/eslint-plugin": "8.
|
|
111
|
-
"@typescript-eslint/parser": "8.
|
|
112
|
-
"@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",
|
|
113
113
|
"@vue/eslint-config-prettier": "10.2.0",
|
|
114
114
|
"@vue/eslint-config-typescript": "14.9.0",
|
|
115
115
|
"@vue/tsconfig": "0.9.1",
|
|
116
|
-
"eslint": "10.8.
|
|
116
|
+
"eslint": "10.8.1",
|
|
117
117
|
"eslint-plugin-prettier": "5.5.6",
|
|
118
118
|
"eslint-plugin-vue": "10.10.0",
|
|
119
119
|
"fallow": "2.101.0",
|
|
@@ -121,13 +121,19 @@
|
|
|
121
121
|
"lefthook": "2.1.10",
|
|
122
122
|
"npm-check-updates": "22.2.7",
|
|
123
123
|
"prettier": "3.9.6",
|
|
124
|
-
"tsx": "4.23.
|
|
124
|
+
"tsx": "4.23.12",
|
|
125
125
|
"typescript": "5.9.3",
|
|
126
126
|
"vue-eslint-parser": "10.4.1",
|
|
127
127
|
"vue-tsc": "3.3.9"
|
|
128
128
|
},
|
|
129
129
|
"devDependencies": {
|
|
130
|
-
"cz-git": "1.13.
|
|
131
|
-
"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"
|
|
132
138
|
}
|
|
133
139
|
}
|
package/release-notes/format.ts
CHANGED
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
import type { ChangelogRelease } from './types'
|
|
2
2
|
|
|
3
|
+
export const toChangelogDateOnly = (date: string): string => {
|
|
4
|
+
const dateMatch = date.match(/^(\d{4}-\d{2}-\d{2})(?: \d{2}:\d{2})?$/)
|
|
5
|
+
return dateMatch?.[1] ?? date
|
|
6
|
+
}
|
|
7
|
+
|
|
3
8
|
export const formatChangelogDate = (date: string): string => {
|
|
4
|
-
const
|
|
5
|
-
if (
|
|
9
|
+
const datePart = toChangelogDateOnly(date)
|
|
10
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(datePart)) {
|
|
6
11
|
return date
|
|
7
12
|
}
|
|
8
13
|
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
const parsed = timePart ? new Date(`${datePart}T${timePart}:00`) : new Date(`${datePart}T12:00:00`)
|
|
12
|
-
const formattedDate = parsed.toLocaleDateString('sv-SE', { dateStyle: 'long' })
|
|
13
|
-
|
|
14
|
-
if (!timePart) {
|
|
15
|
-
return formattedDate
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const formattedTime = parsed.toLocaleTimeString('sv-SE', { hour: '2-digit', minute: '2-digit' })
|
|
19
|
-
return `${formattedDate} ${formattedTime}`
|
|
14
|
+
const parsed = new Date(`${datePart}T12:00:00`)
|
|
15
|
+
return parsed.toLocaleDateString('sv-SE', { dateStyle: 'long' })
|
|
20
16
|
}
|
|
21
17
|
|
|
22
18
|
const CONVENTIONAL_COMMIT_RE = /^(feat|fix|perf|refactor|chore|dep|vuln)(\([^)]+\))?:\s/
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { sortUserReleaseSections } from './format'
|
|
1
|
+
import { sortUserReleaseSections, toChangelogDateOnly } from './format'
|
|
2
2
|
import type { ChangelogRelease } from './types'
|
|
3
3
|
|
|
4
4
|
export const serializeUserChangelogRelease = (release: ChangelogRelease): string => {
|
|
5
|
-
const lines: string[] = [
|
|
5
|
+
const lines: string[] = [
|
|
6
|
+
`## Version ${release.version} - ${toChangelogDateOnly(release.date)}`,
|
|
7
|
+
'',
|
|
8
|
+
]
|
|
6
9
|
|
|
7
10
|
for (const section of sortUserReleaseSections(release.sections)) {
|
|
8
11
|
if (section.items.length === 0) {
|
|
@@ -3,7 +3,6 @@ import path from 'node:path'
|
|
|
3
3
|
import { fileURLToPath } from 'node:url'
|
|
4
4
|
import { parseUserChangelog } from './parseChangelog.ts'
|
|
5
5
|
import { serializeUserChangelogRelease } from './serializeUserChangelog.ts'
|
|
6
|
-
import type { ChangelogRelease } from './types.ts'
|
|
7
6
|
|
|
8
7
|
const rootDir = process.env.FG_DEVKIT_CWD
|
|
9
8
|
? path.resolve(process.env.FG_DEVKIT_CWD)
|
|
@@ -14,36 +13,6 @@ const contentPath = path.join(rootDir, 'CHANGELOG.user.md')
|
|
|
14
13
|
const readMarkdown = (filePath: string): string =>
|
|
15
14
|
existsSync(filePath) ? readFileSync(filePath, 'utf-8') : ''
|
|
16
15
|
|
|
17
|
-
const updateVersionTimestamps = (
|
|
18
|
-
content: string,
|
|
19
|
-
draftReleases: ChangelogRelease[],
|
|
20
|
-
): { content: string; versions: string[] } => {
|
|
21
|
-
const versions: string[] = []
|
|
22
|
-
let result = content
|
|
23
|
-
|
|
24
|
-
for (const release of draftReleases) {
|
|
25
|
-
const dateTimeMatch = release.date.match(/^(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2})$/)
|
|
26
|
-
if (!dateTimeMatch) {
|
|
27
|
-
continue
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const [, datePart, timePart] = dateTimeMatch
|
|
31
|
-
const headingWithoutTime = `## Version ${release.version} - ${datePart}`
|
|
32
|
-
const headingWithTime = `## Version ${release.version} - ${datePart} ${timePart}`
|
|
33
|
-
|
|
34
|
-
if (result.includes(headingWithTime)) {
|
|
35
|
-
continue
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (result.includes(headingWithoutTime)) {
|
|
39
|
-
result = result.replaceAll(headingWithoutTime, headingWithTime)
|
|
40
|
-
versions.push(release.version)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return { content: result, versions }
|
|
45
|
-
}
|
|
46
|
-
|
|
47
16
|
const draft = parseUserChangelog(readMarkdown(draftPath))
|
|
48
17
|
const existingContent = readMarkdown(contentPath).trimEnd()
|
|
49
18
|
const existing = existingContent.length > 0 ? parseUserChangelog(existingContent) : []
|
|
@@ -51,34 +20,17 @@ const existing = existingContent.length > 0 ? parseUserChangelog(existingContent
|
|
|
51
20
|
const existingVersions = new Set(existing.map((release) => release.version))
|
|
52
21
|
const newReleases = draft.filter((release) => !existingVersions.has(release.version))
|
|
53
22
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (newReleases.length > 0) {
|
|
57
|
-
const newBlocks = newReleases.map((release) => serializeUserChangelogRelease(release)).join('\n\n')
|
|
58
|
-
mergedContent =
|
|
59
|
-
existingContent.length > 0 ? `${newBlocks}\n\n${existingContent}` : newBlocks
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const { content: contentWithTimestamps, versions: updatedTimestamps } = updateVersionTimestamps(
|
|
63
|
-
mergedContent,
|
|
64
|
-
draft,
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
if (newReleases.length === 0 && updatedTimestamps.length === 0) {
|
|
23
|
+
if (newReleases.length === 0) {
|
|
68
24
|
process.stdout.write('No user changelog changes to sync.\n')
|
|
69
25
|
process.exit(0)
|
|
70
26
|
}
|
|
71
27
|
|
|
72
|
-
|
|
28
|
+
const newBlocks = newReleases.map((release) => serializeUserChangelogRelease(release)).join('\n\n')
|
|
29
|
+
const mergedContent =
|
|
30
|
+
existingContent.length > 0 ? `${newBlocks}\n\n${existingContent}` : newBlocks
|
|
73
31
|
|
|
74
|
-
|
|
75
|
-
process.stdout.write(
|
|
76
|
-
`Added user changelog version(s): ${newReleases.map((release) => release.version).join(', ')}\n`,
|
|
77
|
-
)
|
|
78
|
-
}
|
|
32
|
+
writeFileSync(contentPath, `${mergedContent.trimEnd()}\n`)
|
|
79
33
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
)
|
|
84
|
-
}
|
|
34
|
+
process.stdout.write(
|
|
35
|
+
`Added user changelog version(s): ${newReleases.map((release) => release.version).join(', ')}\n`,
|
|
36
|
+
)
|
|
@@ -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.3",
|
|
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
|
@@ -503,7 +503,7 @@ Commands:
|
|
|
503
503
|
sync-deps-commit [policy-file] Sync dependency policy, pnpm install, then auto-commit
|
|
504
504
|
policy-outdated [policy-file] Show outdated policy packages via pnpm outdated
|
|
505
505
|
policy-vulns [policy-file] Check all policy packages together (including transitives) via pnpm audit
|
|
506
|
-
repo-vulns Check
|
|
506
|
+
repo-vulns Check repo + nested lockfile packages via pnpm audit
|
|
507
507
|
fleet-vulns [projects-root] [--summary-only] [--delay-ms=<ms>]
|
|
508
508
|
Run pnpm audit across Vue repos (full output + combined summary)
|
|
509
509
|
fleet-bump-fg-devkit [projects-root] [--dry-run]
|
|
@@ -535,11 +535,11 @@ Commands:
|
|
|
535
535
|
Maintainer: discard tracked git changes in chosen repositories
|
|
536
536
|
Options: --dry-run, --fg-devkit-only, --pick, --all, --only=a,b
|
|
537
537
|
policy-upgrade [policy-file] [ncu-args...]
|
|
538
|
-
Upgrade policy packages via
|
|
538
|
+
Upgrade policy packages via ncu (interactive) and auto-commit
|
|
539
539
|
policy-upgrade-commit [ncu-args...]
|
|
540
|
-
Upgrade one consumer package.json
|
|
540
|
+
Upgrade one or more consumer package.json packages and auto-commit
|
|
541
541
|
audit-override-commit [pnpm-audit-args...]
|
|
542
|
-
Fix one vulnerability
|
|
542
|
+
Fix one or more vulnerability overrides via pnpm audit and auto-commit
|
|
543
543
|
sync-project-configs VS Code + tooling sync (overwrites config files)
|
|
544
544
|
sync-tooling-configs Tooling sync only (overwrites config files)
|
|
545
545
|
sync-vscode-settings Copy shared VS Code settings into .vscode/settings.json
|
|
@@ -785,8 +785,8 @@ async function runInteractiveMenu() {
|
|
|
785
785
|
choices: [
|
|
786
786
|
{ name: 'Check', value: 'check' },
|
|
787
787
|
{ name: 'Sync and auto-commit', value: 'sync-commit' },
|
|
788
|
-
{ name: 'Upgrade
|
|
789
|
-
{ name: 'Fix
|
|
788
|
+
{ name: 'Upgrade package.json packages and auto-commit', value: 'upgrade-commit' },
|
|
789
|
+
{ name: 'Fix vulnerability overrides and auto-commit', value: 'audit-override-commit' },
|
|
790
790
|
{ name: 'Cancel', value: 'cancel' },
|
|
791
791
|
],
|
|
792
792
|
default: 'check',
|
|
@@ -857,7 +857,7 @@ async function runInteractiveMenu() {
|
|
|
857
857
|
message: 'Maintainer',
|
|
858
858
|
choices: [
|
|
859
859
|
{ name: 'Show outdated dependency policy packages', value: 'm1' },
|
|
860
|
-
{ name: 'Upgrade dependency policy (interactive)', value: 'm2' },
|
|
860
|
+
{ name: 'Upgrade dependency policy (interactive) and auto-commit', value: 'm2' },
|
|
861
861
|
{ name: 'Refresh dependency policy from repos (and scaffold/vue package.json)', value: 'm3' },
|
|
862
862
|
{ name: 'Check policy vulnerabilities (audit)', value: 'm4' },
|
|
863
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...]
|
|
@@ -139,25 +139,34 @@ function main() {
|
|
|
139
139
|
console.log('[policy-upgrade-commit] No package version changes detected in package.json.')
|
|
140
140
|
process.exit(0)
|
|
141
141
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
console.log('[policy-upgrade-commit] Auto-commit supports exactly one changed package. Commit manually.')
|
|
148
|
-
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}`)
|
|
149
146
|
}
|
|
150
147
|
|
|
151
|
-
const [only] = changed
|
|
152
148
|
const stageExitCode = stageExistingFiles(['package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml'])
|
|
153
149
|
if (stageExitCode !== 0) {
|
|
154
150
|
process.exit(stageExitCode)
|
|
155
151
|
}
|
|
156
152
|
|
|
157
|
-
const
|
|
158
|
-
console.log(`[policy-upgrade-commit]
|
|
159
|
-
|
|
160
|
-
|
|
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 }
|
|
161
170
|
}
|
|
162
171
|
|
|
163
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)) {
|