fg-devkit 1.3.3 → 1.4.0
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 +14 -0
- package/configs/dependency-policy.vue-workspace.json +13 -13
- package/configs/lefthook.yml +3 -8
- package/package.json +4 -1
- package/scripts/cz/cz-adapter.cjs +9 -0
- package/scripts/fg-devkit.mjs +200 -2
- package/scripts/policy-outdated.mjs +78 -0
- package/scripts/policy-upgrade.mjs +117 -0
- package/scripts/policy-vulns.mjs +78 -0
- package/scripts/sync-consumer-lefthook.mjs +1 -3
package/README.md
CHANGED
|
@@ -70,6 +70,20 @@ Run full consumer setup in one command:
|
|
|
70
70
|
pnpm exec fgd full-consumer-setup
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
## Dependency policy update workflow
|
|
74
|
+
|
|
75
|
+
Check outdated policy versions:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
pnpm exec fgd policy-outdated
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Upgrade policy versions interactively:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
pnpm exec fgd policy-upgrade
|
|
85
|
+
```
|
|
86
|
+
|
|
73
87
|
## tsconfig in consuming repos
|
|
74
88
|
|
|
75
89
|
Use `fgd sync-project-configs` (or `fgd sync-tooling-configs`) to write the local `tsconfig.json` template from `fg-devkit`.
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"@sentry/tracing": "7.37.2",
|
|
11
11
|
"@sentry/vue": "7.37.2",
|
|
12
12
|
"@sentry/wasm": "7.67.0",
|
|
13
|
-
"@tailwindcss/postcss": "4.2.
|
|
14
|
-
"@tanstack/vue-query": "5.
|
|
13
|
+
"@tailwindcss/postcss": "4.2.3",
|
|
14
|
+
"@tanstack/vue-query": "5.99.2",
|
|
15
15
|
"@types/leaflet": "1.5.7",
|
|
16
16
|
"@unhead/vue": "2.0.5",
|
|
17
17
|
"@vue-leaflet/vue-leaflet": "0.10.1",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"imask": "7.6.1",
|
|
28
28
|
"leaflet": "1.8.0",
|
|
29
29
|
"lexical": "0.30.0",
|
|
30
|
-
"lodash": "4.
|
|
30
|
+
"lodash": "4.18.1",
|
|
31
31
|
"lodash-es": "4.18.1",
|
|
32
32
|
"markdown-it": "14.1.1",
|
|
33
33
|
"pinia": "3.0.4",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"randexp": "0.5.3",
|
|
37
37
|
"register-service-worker": "1.7.2",
|
|
38
38
|
"vega-embed": "7.1.0",
|
|
39
|
-
"vega-lite": "6.4.
|
|
39
|
+
"vega-lite": "6.4.2",
|
|
40
40
|
"vue-chartjs": "5.3.3",
|
|
41
41
|
"vue-i18n": "11.3.2",
|
|
42
42
|
"vue-quilly": "1.0.5",
|
|
@@ -56,14 +56,14 @@
|
|
|
56
56
|
"@storybook/addon-vitest": "10.2.12",
|
|
57
57
|
"@storybook/vue3": "10.2.12",
|
|
58
58
|
"@storybook/vue3-vite": "10.2.12",
|
|
59
|
-
"@tanstack/vue-query-devtools": "6.1.
|
|
59
|
+
"@tanstack/vue-query-devtools": "6.1.18",
|
|
60
60
|
"@tsconfig/node22": "22.0.5",
|
|
61
61
|
"@types/lodash-es": "4.17.12",
|
|
62
62
|
"@types/node": "22.16.5",
|
|
63
63
|
"@vitest/browser": "3.2.4",
|
|
64
|
-
"@vue/compiler-dom": "3.5.
|
|
64
|
+
"@vue/compiler-dom": "3.5.32",
|
|
65
65
|
"@vue/eslint-config-standard": "8.0.1",
|
|
66
|
-
"@vue/server-renderer": "3.5.
|
|
66
|
+
"@vue/server-renderer": "3.5.32",
|
|
67
67
|
"@vue/test-utils": "2.4.6",
|
|
68
68
|
"@vuepic/vue-datepicker": "6.0.3",
|
|
69
69
|
"arg": "5.0.2",
|
|
@@ -71,25 +71,25 @@
|
|
|
71
71
|
"eslint-plugin-storybook": "10.1.10",
|
|
72
72
|
"globals": "15.11.0",
|
|
73
73
|
"jsdom": "26.1.0",
|
|
74
|
-
"postcss": "8.5.
|
|
74
|
+
"postcss": "8.5.10",
|
|
75
75
|
"sass": "1.97.3",
|
|
76
76
|
"start-server-and-test": "2.1.3",
|
|
77
77
|
"storybook": "10.2.12",
|
|
78
78
|
"tsx": "4.21.0",
|
|
79
79
|
"vega": "6.2.0",
|
|
80
80
|
"vite-plugin-dts": "4.5.4",
|
|
81
|
-
"vite-plugin-vue-devtools": "8.
|
|
81
|
+
"vite-plugin-vue-devtools": "8.1.1",
|
|
82
82
|
"vitest": "3.2.4",
|
|
83
83
|
"yaml": "2.8.3"
|
|
84
84
|
}
|
|
85
85
|
},
|
|
86
86
|
"managedAnywhere": {
|
|
87
|
-
"@tailwindcss/vite": "4.2.
|
|
88
|
-
"@vitejs/plugin-vue": "6.0.
|
|
89
|
-
"axios": "1.15.
|
|
87
|
+
"@tailwindcss/vite": "4.2.3",
|
|
88
|
+
"@vitejs/plugin-vue": "6.0.6",
|
|
89
|
+
"axios": "1.15.1",
|
|
90
90
|
"dotenv": "16.4.5",
|
|
91
91
|
"qrcode.vue": "3.8.1",
|
|
92
|
-
"tailwindcss": "4.2.
|
|
92
|
+
"tailwindcss": "4.2.3",
|
|
93
93
|
"vite": "7.3.2",
|
|
94
94
|
"vue": "3.5.32"
|
|
95
95
|
}
|
package/configs/lefthook.yml
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
pre-commit:
|
|
2
2
|
commands:
|
|
3
3
|
lint-check:
|
|
4
|
-
run:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
elif command -v node >/dev/null 2>&1; then
|
|
8
|
-
node ./node_modules/fg-devkit/scripts/fg-devkit.mjs lint .;
|
|
9
|
-
else
|
|
10
|
-
/usr/bin/env node ./node_modules/fg-devkit/scripts/fg-devkit.mjs lint .;
|
|
11
|
-
fi
|
|
4
|
+
run: zsh -lc "node ./node_modules/fg-devkit/scripts/fg-devkit.mjs lint ."
|
|
5
|
+
typecheck:
|
|
6
|
+
run: zsh -lc "node ./node_modules/fg-devkit/scripts/fg-devkit.mjs typecheck"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fg-devkit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Shared configs, scripts, and DX tooling for Vue / TypeScript frontend repos",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -28,6 +28,8 @@
|
|
|
28
28
|
"./scripts/sync-consumer-scripts.mjs": "./scripts/sync-consumer-scripts.mjs",
|
|
29
29
|
"./scripts/sync-consumer-lefthook.mjs": "./scripts/sync-consumer-lefthook.mjs",
|
|
30
30
|
"./scripts/prune-consumer-deps.mjs": "./scripts/prune-consumer-deps.mjs",
|
|
31
|
+
"./scripts/policy-outdated.mjs": "./scripts/policy-outdated.mjs",
|
|
32
|
+
"./scripts/policy-upgrade.mjs": "./scripts/policy-upgrade.mjs",
|
|
31
33
|
"./scripts/check-dependency-policy.mjs": "./scripts/check-dependency-policy.mjs",
|
|
32
34
|
"./scripts/sync-dependency-policy.mjs": "./scripts/sync-dependency-policy.mjs",
|
|
33
35
|
"./scripts/resolve-dependency-policy-path.mjs": "./scripts/resolve-dependency-policy-path.mjs",
|
|
@@ -70,6 +72,7 @@
|
|
|
70
72
|
"eslint-plugin-prettier": "5.5.5",
|
|
71
73
|
"eslint-plugin-vue": "10.8.0",
|
|
72
74
|
"lefthook": "2.1.6",
|
|
75
|
+
"npm-check-updates": "21.0.3",
|
|
73
76
|
"prettier": "3.8.3",
|
|
74
77
|
"typescript": "5.9.3",
|
|
75
78
|
"vue-eslint-parser": "10.4.0",
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
module.exports = {
|
|
6
6
|
prompter(cz, commit) {
|
|
7
7
|
const defaultType = process.env.FG_DEVKIT_CZ_DEFAULT_TYPE;
|
|
8
|
+
const defaultPackages = process.env.FG_DEVKIT_CZ_DEFAULT_PACKAGES;
|
|
9
|
+
const defaultDepVersion = process.env.FG_DEVKIT_CZ_DEFAULT_DEP_VERSION;
|
|
10
|
+
const defaultDepChangeKind = process.env.FG_DEVKIT_CZ_DEFAULT_DEP_CHANGE_KIND;
|
|
8
11
|
const types = [
|
|
9
12
|
{ value: "feat", name: "feat(scope): Added" },
|
|
10
13
|
{ value: "fix", name: "fix(scope): Fixed" },
|
|
@@ -36,6 +39,7 @@ module.exports = {
|
|
|
36
39
|
name: "packages",
|
|
37
40
|
when: (answers) => ["dep", "vuln"].includes(answers.change_type),
|
|
38
41
|
message: "Packages:",
|
|
42
|
+
default: defaultType === "dep" && defaultPackages ? defaultPackages : undefined,
|
|
39
43
|
},
|
|
40
44
|
{
|
|
41
45
|
type: "list",
|
|
@@ -64,12 +68,17 @@ module.exports = {
|
|
|
64
68
|
{ value: "update", name: "updated package" },
|
|
65
69
|
{ value: "remove", name: "removed package" },
|
|
66
70
|
],
|
|
71
|
+
default:
|
|
72
|
+
defaultType === "dep" && ["new", "update", "remove"].includes(defaultDepChangeKind)
|
|
73
|
+
? defaultDepChangeKind
|
|
74
|
+
: "update",
|
|
67
75
|
},
|
|
68
76
|
{
|
|
69
77
|
type: "input",
|
|
70
78
|
name: "dep_version",
|
|
71
79
|
when: (answers) => answers.change_type === "dep",
|
|
72
80
|
message: "Version (x.y.z):",
|
|
81
|
+
default: defaultType === "dep" && defaultDepVersion ? defaultDepVersion : undefined,
|
|
73
82
|
validate: (value) => (/^\d+\.\d+\.\d+$/.test(value) ? true : "Use format x.y.z"),
|
|
74
83
|
},
|
|
75
84
|
{
|
package/scripts/fg-devkit.mjs
CHANGED
|
@@ -5,6 +5,9 @@
|
|
|
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 policy-outdated [policy-file]
|
|
9
|
+
* pnpm exec fg-devkit policy-vulns [policy-file]
|
|
10
|
+
* pnpm exec fg-devkit policy-upgrade [policy-file] [ncu-args...]
|
|
8
11
|
* pnpm exec fg-devkit sync-project-configs (VS Code + tooling sync; overwrites config files)
|
|
9
12
|
* pnpm exec fg-devkit sync-tooling-configs (tooling sync only; overwrites config files)
|
|
10
13
|
* pnpm exec fg-devkit sync-vscode-settings
|
|
@@ -38,6 +41,7 @@ import { createRequire } from 'node:module'
|
|
|
38
41
|
|
|
39
42
|
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
|
|
40
43
|
const require = createRequire(import.meta.url)
|
|
44
|
+
const fgRoot = path.resolve(scriptDir, '..')
|
|
41
45
|
|
|
42
46
|
/** Run another script in this package via Node; inherits stdio and returns the child exit code. */
|
|
43
47
|
function runNode(scriptRelative, args = [], options = {}) {
|
|
@@ -94,6 +98,24 @@ function runPnpmInstall() {
|
|
|
94
98
|
return r.status ?? 1
|
|
95
99
|
}
|
|
96
100
|
|
|
101
|
+
/** Run pnpm audit in current repo and return normalized status info. */
|
|
102
|
+
function runPnpmAuditCurrentRepo() {
|
|
103
|
+
const r = spawnSync('pnpm', ['audit'], {
|
|
104
|
+
stdio: 'inherit',
|
|
105
|
+
cwd: process.cwd(),
|
|
106
|
+
env: process.env,
|
|
107
|
+
})
|
|
108
|
+
if (r.error) {
|
|
109
|
+
console.error('[fg-devkit]', r.error.message)
|
|
110
|
+
return { ok: false, hasVulns: false, exitCode: 1 }
|
|
111
|
+
}
|
|
112
|
+
const code = r.status ?? 1
|
|
113
|
+
if (code === 1) {
|
|
114
|
+
return { ok: true, hasVulns: true, exitCode: 0 }
|
|
115
|
+
}
|
|
116
|
+
return { ok: code === 0, hasVulns: false, exitCode: code }
|
|
117
|
+
}
|
|
118
|
+
|
|
97
119
|
/** Run Lefthook from fg-devkit bundled dependency set. */
|
|
98
120
|
function runBundledLefthook(args = []) {
|
|
99
121
|
let lefthookBin
|
|
@@ -153,6 +175,124 @@ function runFullConsumerSetup() {
|
|
|
153
175
|
return runPnpmInstall()
|
|
154
176
|
}
|
|
155
177
|
|
|
178
|
+
function stageFiles(paths = []) {
|
|
179
|
+
const existing = paths.filter((p) => fs.existsSync(path.join(process.cwd(), p)))
|
|
180
|
+
if (existing.length === 0) return 0
|
|
181
|
+
const r = spawnSync('git', ['add', '--', ...existing], {
|
|
182
|
+
stdio: 'inherit',
|
|
183
|
+
cwd: process.cwd(),
|
|
184
|
+
env: process.env,
|
|
185
|
+
})
|
|
186
|
+
if (r.error) {
|
|
187
|
+
console.error('[fg-devkit]', r.error.message)
|
|
188
|
+
return 1
|
|
189
|
+
}
|
|
190
|
+
return r.status ?? 1
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function commitStaged(message) {
|
|
194
|
+
const r = spawnSync('git', ['commit', '-m', message], {
|
|
195
|
+
stdio: 'inherit',
|
|
196
|
+
cwd: process.cwd(),
|
|
197
|
+
env: process.env,
|
|
198
|
+
})
|
|
199
|
+
if (r.error) {
|
|
200
|
+
console.error('[fg-devkit]', r.error.message)
|
|
201
|
+
return 1
|
|
202
|
+
}
|
|
203
|
+
return r.status ?? 1
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function collectPolicyVersionChanges(beforePolicy, afterPolicy) {
|
|
207
|
+
const before = {
|
|
208
|
+
...(beforePolicy.managedDependencies?.dependencies ?? {}),
|
|
209
|
+
...(beforePolicy.managedDependencies?.devDependencies ?? {}),
|
|
210
|
+
...(beforePolicy.managedAnywhere ?? {}),
|
|
211
|
+
}
|
|
212
|
+
const after = {
|
|
213
|
+
...(afterPolicy.managedDependencies?.dependencies ?? {}),
|
|
214
|
+
...(afterPolicy.managedDependencies?.devDependencies ?? {}),
|
|
215
|
+
...(afterPolicy.managedAnywhere ?? {}),
|
|
216
|
+
}
|
|
217
|
+
const changed = []
|
|
218
|
+
for (const [name, newVersion] of Object.entries(after)) {
|
|
219
|
+
const prev = before[name]
|
|
220
|
+
if (prev !== undefined && prev !== newVersion) {
|
|
221
|
+
changed.push({ name, from: prev, to: newVersion })
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return changed
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** Maintainer flow: run policy-upgrade, stage policy file, then auto-commit dep(package): bump to version. */
|
|
228
|
+
function runMaintainerPolicyUpgradeAndCommit() {
|
|
229
|
+
const policyPath = path.join(process.cwd(), 'configs', 'dependency-policy.vue-workspace.json')
|
|
230
|
+
if (!fs.existsSync(policyPath)) {
|
|
231
|
+
console.error('[fg-devkit] Expected policy at configs/dependency-policy.vue-workspace.json')
|
|
232
|
+
return 1
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
let beforePolicy
|
|
236
|
+
try {
|
|
237
|
+
beforePolicy = JSON.parse(fs.readFileSync(policyPath, 'utf8'))
|
|
238
|
+
} catch (err) {
|
|
239
|
+
console.error(`[fg-devkit] Failed to read policy before upgrade: ${err.message}`)
|
|
240
|
+
return 1
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const upgradeCode = runNode('policy-upgrade.mjs')
|
|
244
|
+
if (upgradeCode !== 0) return upgradeCode
|
|
245
|
+
|
|
246
|
+
let afterPolicy
|
|
247
|
+
try {
|
|
248
|
+
afterPolicy = JSON.parse(fs.readFileSync(policyPath, 'utf8'))
|
|
249
|
+
} catch (err) {
|
|
250
|
+
console.error(`[fg-devkit] Failed to read policy after upgrade: ${err.message}`)
|
|
251
|
+
return 1
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const changed = collectPolicyVersionChanges(beforePolicy, afterPolicy)
|
|
255
|
+
if (changed.length === 0) {
|
|
256
|
+
console.log('[fg-devkit] No policy package version changes detected; skipping stage and commit flow.')
|
|
257
|
+
return 0
|
|
258
|
+
}
|
|
259
|
+
if (changed.length > 1) {
|
|
260
|
+
console.log('[fg-devkit] Multiple package changes detected in policy-upgrade:')
|
|
261
|
+
for (const item of changed) {
|
|
262
|
+
console.log(` - ${item.name}: ${item.from} -> ${item.to}`)
|
|
263
|
+
}
|
|
264
|
+
console.log('[fg-devkit] Please commit manually (or rerun and select a single package).')
|
|
265
|
+
return 1
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const [only] = changed
|
|
269
|
+
const stageCode = stageFiles(['configs/dependency-policy.vue-workspace.json'])
|
|
270
|
+
if (stageCode !== 0) return stageCode
|
|
271
|
+
|
|
272
|
+
const commitMessage = `dep(${only.name}): bump to ${only.to}`
|
|
273
|
+
console.log(`[fg-devkit] Staged policy change for ${only.name} -> ${only.to}`)
|
|
274
|
+
console.log(`[fg-devkit] Auto-committing: ${commitMessage}`)
|
|
275
|
+
return commitStaged(commitMessage)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** Maintainer flow: run both policy vuln check and fg-devkit root audit. */
|
|
279
|
+
function runMaintainerAuditAll() {
|
|
280
|
+
console.log('[fg-devkit] Running policy vulnerability scan...')
|
|
281
|
+
const policyCode = runNode('policy-vulns.mjs')
|
|
282
|
+
if (policyCode !== 0) return policyCode
|
|
283
|
+
|
|
284
|
+
console.log('[fg-devkit] Running fg-devkit repository audit...')
|
|
285
|
+
const repoAudit = runPnpmAuditCurrentRepo()
|
|
286
|
+
if (!repoAudit.ok) return repoAudit.exitCode
|
|
287
|
+
|
|
288
|
+
if (repoAudit.hasVulns) {
|
|
289
|
+
console.log('[fg-devkit] Completed: vulnerabilities were reported in fg-devkit repository audit.')
|
|
290
|
+
} else {
|
|
291
|
+
console.log('[fg-devkit] Completed: no vulnerabilities reported in fg-devkit repository audit.')
|
|
292
|
+
}
|
|
293
|
+
return 0
|
|
294
|
+
}
|
|
295
|
+
|
|
156
296
|
/** Prompt release type in CLI before invoking release.sh to avoid a "stuck" terminal feeling. */
|
|
157
297
|
async function promptReleaseType(rl) {
|
|
158
298
|
console.log('\nSelect release type:')
|
|
@@ -293,6 +433,9 @@ function runBundledTypeScript(args = []) {
|
|
|
293
433
|
const DIRECT_COMMANDS = {
|
|
294
434
|
'check-deps': 'check-dependency-policy.mjs',
|
|
295
435
|
'sync-deps': 'sync-dependency-policy.mjs',
|
|
436
|
+
'policy-outdated': 'policy-outdated.mjs',
|
|
437
|
+
'policy-vulns': 'policy-vulns.mjs',
|
|
438
|
+
'policy-upgrade': 'policy-upgrade.mjs',
|
|
296
439
|
'sync-project-configs': 'sync-project-configs.mjs',
|
|
297
440
|
'sync-tooling-configs': 'sync-tooling-configs.mjs',
|
|
298
441
|
'sync-vscode-settings': 'sync-vscode-settings.mjs',
|
|
@@ -308,6 +451,10 @@ function printHelp() {
|
|
|
308
451
|
Commands:
|
|
309
452
|
check-deps [policy-file] Validate package.json + pins against policy
|
|
310
453
|
sync-deps [policy-file] Align declared versions to policy (existing keys only)
|
|
454
|
+
policy-outdated [policy-file] Show outdated policy packages via pnpm outdated
|
|
455
|
+
policy-vulns [policy-file] Check policy packages for vulnerabilities via pnpm audit
|
|
456
|
+
policy-upgrade [policy-file] [ncu-args...]
|
|
457
|
+
Upgrade policy packages via npm-check-updates (default interactive)
|
|
311
458
|
sync-project-configs VS Code + tooling sync (overwrites config files)
|
|
312
459
|
sync-tooling-configs Tooling sync only (overwrites config files)
|
|
313
460
|
sync-vscode-settings Copy shared VS Code settings into .vscode/settings.json
|
|
@@ -381,12 +528,63 @@ const MENU = [
|
|
|
381
528
|
},
|
|
382
529
|
]
|
|
383
530
|
|
|
531
|
+
const MAINTAINER_MENU = [
|
|
532
|
+
{
|
|
533
|
+
key: 'm1',
|
|
534
|
+
label: 'Maintainer: Show outdated dependency policy packages',
|
|
535
|
+
run: () => runNode('policy-outdated.mjs'),
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
key: 'm2',
|
|
539
|
+
label: 'Maintainer: Upgrade dependency policy (interactive)',
|
|
540
|
+
run: () => runNode('policy-upgrade.mjs'),
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
key: 'm3',
|
|
544
|
+
label: 'Maintainer: Refresh dependency policy from repos',
|
|
545
|
+
run: () => runNode('refresh-dependency-policy-from-repos.mjs'),
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
key: 'm4',
|
|
549
|
+
label: 'Maintainer: Upgrade one policy package, stage, and auto-commit',
|
|
550
|
+
run: () => runMaintainerPolicyUpgradeAndCommit(),
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
key: 'm5',
|
|
554
|
+
label: 'Maintainer: Check policy vulnerabilities (audit)',
|
|
555
|
+
run: () => runNode('policy-vulns.mjs'),
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
key: 'm6',
|
|
559
|
+
label: 'Maintainer: Check vulnerabilities (policy + fg-devkit repo)',
|
|
560
|
+
run: () => runMaintainerAuditAll(),
|
|
561
|
+
},
|
|
562
|
+
]
|
|
563
|
+
|
|
564
|
+
function isFgDevkitMaintainerContext() {
|
|
565
|
+
if (path.resolve(process.cwd()) !== fgRoot) {
|
|
566
|
+
return false
|
|
567
|
+
}
|
|
568
|
+
const pkgPath = path.join(process.cwd(), 'package.json')
|
|
569
|
+
if (!fs.existsSync(pkgPath)) {
|
|
570
|
+
return false
|
|
571
|
+
}
|
|
572
|
+
try {
|
|
573
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'))
|
|
574
|
+
return pkg?.name === 'fg-devkit'
|
|
575
|
+
} catch {
|
|
576
|
+
return false
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
384
580
|
async function runInteractiveMenu() {
|
|
385
581
|
const rl = readline.createInterface({ input, output })
|
|
582
|
+
const isMaintainer = isFgDevkitMaintainerContext()
|
|
583
|
+
const menu = isMaintainer ? [...MENU, ...MAINTAINER_MENU] : MENU
|
|
386
584
|
|
|
387
585
|
console.log(`\nfg-devkit — choose a task (cwd: ${process.cwd()})\n`)
|
|
388
586
|
|
|
389
|
-
for (const item of
|
|
587
|
+
for (const item of menu) {
|
|
390
588
|
console.log(` ${item.key}) ${item.label}`)
|
|
391
589
|
}
|
|
392
590
|
console.log(' 0) Exit\n')
|
|
@@ -398,7 +596,7 @@ async function runInteractiveMenu() {
|
|
|
398
596
|
return 0
|
|
399
597
|
}
|
|
400
598
|
|
|
401
|
-
const item =
|
|
599
|
+
const item = menu.find((m) => m.key === choice)
|
|
402
600
|
if (!item) {
|
|
403
601
|
console.error('[fg-devkit] Unknown option. Run again and choose a number from the list.')
|
|
404
602
|
rl.close()
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Shows outdated packages for dependency policy entries by projecting policy data
|
|
4
|
+
* into a temporary package.json and running `pnpm outdated` there.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* pnpm exec fg-devkit policy-outdated [policy-file]
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import fs from 'node:fs'
|
|
11
|
+
import os from 'node:os'
|
|
12
|
+
import path from 'node:path'
|
|
13
|
+
import { spawnSync } from 'node:child_process'
|
|
14
|
+
import { fileURLToPath } from 'node:url'
|
|
15
|
+
import { resolveDependencyPolicyPath } from './resolve-dependency-policy-path.mjs'
|
|
16
|
+
|
|
17
|
+
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
|
|
18
|
+
const policyPath = resolveDependencyPolicyPath(scriptDir, process.cwd(), process.argv)
|
|
19
|
+
|
|
20
|
+
function readJson(p) {
|
|
21
|
+
return JSON.parse(fs.readFileSync(p, 'utf8'))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const policy = readJson(policyPath)
|
|
25
|
+
const deps = {
|
|
26
|
+
...(policy.managedDependencies?.dependencies ?? {}),
|
|
27
|
+
...(policy.managedAnywhere ?? {}),
|
|
28
|
+
}
|
|
29
|
+
const devDeps = {
|
|
30
|
+
...(policy.managedDependencies?.devDependencies ?? {}),
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'fgd-policy-outdated-'))
|
|
34
|
+
const pkgPath = path.join(tmpDir, 'package.json')
|
|
35
|
+
fs.writeFileSync(
|
|
36
|
+
pkgPath,
|
|
37
|
+
`${JSON.stringify(
|
|
38
|
+
{
|
|
39
|
+
name: 'fgd-policy-outdated-temp',
|
|
40
|
+
private: true,
|
|
41
|
+
version: '0.0.0',
|
|
42
|
+
dependencies: deps,
|
|
43
|
+
devDependencies: devDeps,
|
|
44
|
+
},
|
|
45
|
+
null,
|
|
46
|
+
2,
|
|
47
|
+
)}\n`,
|
|
48
|
+
'utf8',
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
console.log(`[policy-outdated] policy=${policyPath}`)
|
|
52
|
+
const install = spawnSync('pnpm', ['install', '--lockfile-only', '--ignore-scripts'], {
|
|
53
|
+
cwd: tmpDir,
|
|
54
|
+
stdio: 'inherit',
|
|
55
|
+
env: process.env,
|
|
56
|
+
})
|
|
57
|
+
if (install.error) {
|
|
58
|
+
console.error('[policy-outdated]', install.error.message)
|
|
59
|
+
process.exit(1)
|
|
60
|
+
}
|
|
61
|
+
if ((install.status ?? 1) !== 0) {
|
|
62
|
+
process.exit(install.status ?? 1)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const result = spawnSync('pnpm', ['outdated'], {
|
|
66
|
+
cwd: tmpDir,
|
|
67
|
+
stdio: 'inherit',
|
|
68
|
+
env: process.env,
|
|
69
|
+
})
|
|
70
|
+
if (result.error) {
|
|
71
|
+
console.error('[policy-outdated]', result.error.message)
|
|
72
|
+
process.exit(1)
|
|
73
|
+
}
|
|
74
|
+
// pnpm outdated returns exit code 1 when outdated packages are found.
|
|
75
|
+
if ((result.status ?? 1) === 1) {
|
|
76
|
+
process.exit(0)
|
|
77
|
+
}
|
|
78
|
+
process.exit(result.status ?? 1)
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Upgrades dependency policy package versions through npm-check-updates.
|
|
4
|
+
* It projects the policy into a temporary package.json, runs ncu, then writes
|
|
5
|
+
* selected versions back to the policy file.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* pnpm exec fg-devkit policy-upgrade [policy-file] [ncu-args...]
|
|
9
|
+
*
|
|
10
|
+
* Defaults when no ncu args are given:
|
|
11
|
+
* --interactive --format group --upgrade --packageManager pnpm --install never
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import fs from 'node:fs'
|
|
15
|
+
import os from 'node:os'
|
|
16
|
+
import path from 'node:path'
|
|
17
|
+
import { spawnSync } from 'node:child_process'
|
|
18
|
+
import { fileURLToPath } from 'node:url'
|
|
19
|
+
import { createRequire } from 'node:module'
|
|
20
|
+
import { resolveDependencyPolicyPath } from './resolve-dependency-policy-path.mjs'
|
|
21
|
+
|
|
22
|
+
const require = createRequire(import.meta.url)
|
|
23
|
+
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
|
|
24
|
+
|
|
25
|
+
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
26
|
+
console.log(`Usage:
|
|
27
|
+
pnpm exec fg-devkit policy-upgrade [policy-file] [ncu-args...]
|
|
28
|
+
|
|
29
|
+
Examples:
|
|
30
|
+
pnpm exec fg-devkit policy-upgrade
|
|
31
|
+
pnpm exec fg-devkit policy-upgrade configs/dependency-policy.vue-workspace.json --interactive --format group --upgrade`)
|
|
32
|
+
process.exit(0)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const argPolicy = process.argv[2]
|
|
36
|
+
const hasPolicyArg = Boolean(argPolicy) && !argPolicy.startsWith('-')
|
|
37
|
+
const policyPath = resolveDependencyPolicyPath(scriptDir, process.cwd(), process.argv)
|
|
38
|
+
const ncuArgs = hasPolicyArg ? process.argv.slice(3) : process.argv.slice(2)
|
|
39
|
+
|
|
40
|
+
function readJson(p) {
|
|
41
|
+
return JSON.parse(fs.readFileSync(p, 'utf8'))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const policy = readJson(policyPath)
|
|
45
|
+
|
|
46
|
+
const depNames = new Set(Object.keys(policy.managedDependencies?.dependencies ?? {}))
|
|
47
|
+
const devNames = new Set(Object.keys(policy.managedDependencies?.devDependencies ?? {}))
|
|
48
|
+
const anyNames = new Set(Object.keys(policy.managedAnywhere ?? {}))
|
|
49
|
+
|
|
50
|
+
const deps = {
|
|
51
|
+
...(policy.managedDependencies?.dependencies ?? {}),
|
|
52
|
+
...(policy.managedAnywhere ?? {}),
|
|
53
|
+
}
|
|
54
|
+
const devDeps = {
|
|
55
|
+
...(policy.managedDependencies?.devDependencies ?? {}),
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'fgd-policy-upgrade-'))
|
|
59
|
+
const pkgPath = path.join(tmpDir, 'package.json')
|
|
60
|
+
fs.writeFileSync(
|
|
61
|
+
pkgPath,
|
|
62
|
+
`${JSON.stringify(
|
|
63
|
+
{
|
|
64
|
+
name: 'fgd-policy-upgrade-temp',
|
|
65
|
+
private: true,
|
|
66
|
+
version: '0.0.0',
|
|
67
|
+
dependencies: deps,
|
|
68
|
+
devDependencies: devDeps,
|
|
69
|
+
},
|
|
70
|
+
null,
|
|
71
|
+
2,
|
|
72
|
+
)}\n`,
|
|
73
|
+
'utf8',
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
let ncuBin
|
|
77
|
+
try {
|
|
78
|
+
const ncuPkgPath = require.resolve('npm-check-updates/package.json')
|
|
79
|
+
ncuBin = path.join(path.dirname(ncuPkgPath), 'build', 'cli.js')
|
|
80
|
+
} catch {
|
|
81
|
+
console.error('[policy-upgrade] Could not resolve npm-check-updates binary.')
|
|
82
|
+
process.exit(1)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const effectiveNcuArgs =
|
|
86
|
+
ncuArgs.length > 0
|
|
87
|
+
? ncuArgs
|
|
88
|
+
: ['--interactive', '--format', 'group', '--upgrade', '--packageManager', 'pnpm', '--install', 'never']
|
|
89
|
+
|
|
90
|
+
console.log(`[policy-upgrade] policy=${policyPath}`)
|
|
91
|
+
const run = spawnSync(process.execPath, [ncuBin, ...effectiveNcuArgs], {
|
|
92
|
+
cwd: tmpDir,
|
|
93
|
+
stdio: 'inherit',
|
|
94
|
+
env: process.env,
|
|
95
|
+
})
|
|
96
|
+
if (run.error) {
|
|
97
|
+
console.error('[policy-upgrade]', run.error.message)
|
|
98
|
+
process.exit(1)
|
|
99
|
+
}
|
|
100
|
+
if ((run.status ?? 1) !== 0) {
|
|
101
|
+
process.exit(run.status ?? 1)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const updatedPkg = readJson(pkgPath)
|
|
105
|
+
const updatedDeps = updatedPkg.dependencies ?? {}
|
|
106
|
+
const updatedDevDeps = updatedPkg.devDependencies ?? {}
|
|
107
|
+
|
|
108
|
+
for (const [name, version] of Object.entries(updatedDeps)) {
|
|
109
|
+
if (anyNames.has(name)) policy.managedAnywhere[name] = version
|
|
110
|
+
else if (depNames.has(name)) policy.managedDependencies.dependencies[name] = version
|
|
111
|
+
}
|
|
112
|
+
for (const [name, version] of Object.entries(updatedDevDeps)) {
|
|
113
|
+
if (devNames.has(name)) policy.managedDependencies.devDependencies[name] = version
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
fs.writeFileSync(policyPath, `${JSON.stringify(policy, null, 2)}\n`, 'utf8')
|
|
117
|
+
console.log('[policy-upgrade] Updated dependency policy from selected ncu changes.')
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Checks vulnerabilities for dependency policy entries by projecting policy data
|
|
4
|
+
* into a temporary package.json and running `pnpm audit` there.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* pnpm exec fg-devkit policy-vulns [policy-file]
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import fs from 'node:fs'
|
|
11
|
+
import os from 'node:os'
|
|
12
|
+
import path from 'node:path'
|
|
13
|
+
import { spawnSync } from 'node:child_process'
|
|
14
|
+
import { fileURLToPath } from 'node:url'
|
|
15
|
+
import { resolveDependencyPolicyPath } from './resolve-dependency-policy-path.mjs'
|
|
16
|
+
|
|
17
|
+
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
|
|
18
|
+
const policyPath = resolveDependencyPolicyPath(scriptDir, process.cwd(), process.argv)
|
|
19
|
+
|
|
20
|
+
function readJson(p) {
|
|
21
|
+
return JSON.parse(fs.readFileSync(p, 'utf8'))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const policy = readJson(policyPath)
|
|
25
|
+
const deps = {
|
|
26
|
+
...(policy.managedDependencies?.dependencies ?? {}),
|
|
27
|
+
...(policy.managedAnywhere ?? {}),
|
|
28
|
+
}
|
|
29
|
+
const devDeps = {
|
|
30
|
+
...(policy.managedDependencies?.devDependencies ?? {}),
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'fgd-policy-vulns-'))
|
|
34
|
+
const pkgPath = path.join(tmpDir, 'package.json')
|
|
35
|
+
fs.writeFileSync(
|
|
36
|
+
pkgPath,
|
|
37
|
+
`${JSON.stringify(
|
|
38
|
+
{
|
|
39
|
+
name: 'fgd-policy-vulns-temp',
|
|
40
|
+
private: true,
|
|
41
|
+
version: '0.0.0',
|
|
42
|
+
dependencies: deps,
|
|
43
|
+
devDependencies: devDeps,
|
|
44
|
+
},
|
|
45
|
+
null,
|
|
46
|
+
2,
|
|
47
|
+
)}\n`,
|
|
48
|
+
'utf8',
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
console.log(`[policy-vulns] policy=${policyPath}`)
|
|
52
|
+
const install = spawnSync('pnpm', ['install', '--ignore-scripts'], {
|
|
53
|
+
cwd: tmpDir,
|
|
54
|
+
stdio: 'inherit',
|
|
55
|
+
env: process.env,
|
|
56
|
+
})
|
|
57
|
+
if (install.error) {
|
|
58
|
+
console.error('[policy-vulns]', install.error.message)
|
|
59
|
+
process.exit(1)
|
|
60
|
+
}
|
|
61
|
+
if ((install.status ?? 1) !== 0) {
|
|
62
|
+
process.exit(install.status ?? 1)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const audit = spawnSync('pnpm', ['audit'], {
|
|
66
|
+
cwd: tmpDir,
|
|
67
|
+
stdio: 'inherit',
|
|
68
|
+
env: process.env,
|
|
69
|
+
})
|
|
70
|
+
if (audit.error) {
|
|
71
|
+
console.error('[policy-vulns]', audit.error.message)
|
|
72
|
+
process.exit(1)
|
|
73
|
+
}
|
|
74
|
+
// pnpm audit returns exit code 1 when vulnerabilities are found.
|
|
75
|
+
if ((audit.status ?? 1) === 1) {
|
|
76
|
+
process.exit(0)
|
|
77
|
+
}
|
|
78
|
+
process.exit(audit.status ?? 1)
|
|
@@ -55,9 +55,7 @@ if (pkg['lint-staged'] !== undefined) {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
try {
|
|
58
|
-
|
|
59
|
-
const rendered = template.replaceAll('__FG_NODE_BIN__', process.execPath)
|
|
60
|
-
fs.writeFileSync(lefthookTarget, rendered, 'utf8')
|
|
58
|
+
fs.copyFileSync(lefthookTemplate, lefthookTarget)
|
|
61
59
|
fs.writeFileSync(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`, 'utf8')
|
|
62
60
|
if (fs.existsSync(huskyDir)) {
|
|
63
61
|
fs.rmSync(huskyDir, { recursive: true, force: true })
|