fg-devkit 1.22.0 → 1.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +16 -7
  2. package/configs/dependency-policy.vue-workspace.json +27 -27
  3. package/package.json +10 -81
  4. package/scaffold/vue/package.json +12 -12
  5. package/scripts/audit-override-commit.mjs +167 -24
  6. package/scripts/bump-node-toolchain.mjs +8 -31
  7. package/scripts/bump-pnpm-toolchain.mjs +8 -29
  8. package/scripts/check-dependency-policy.mjs +10 -35
  9. package/scripts/fg-devkit.mjs +274 -331
  10. package/scripts/fleet-bump-fg-devkit.mjs +4 -5
  11. package/scripts/fleet-git-commit-push-scoped.mjs +6 -26
  12. package/scripts/fleet-git-discard-scoped.mjs +5 -25
  13. package/scripts/fleet-git-pull-scoped.mjs +5 -25
  14. package/scripts/fleet-vulns.mjs +4 -9
  15. package/scripts/generate-release-notes.mjs +1 -1
  16. package/scripts/{audit-fix-plan.mjs → lib/audit-fix-plan.mjs} +77 -4
  17. package/scripts/{audit-fix-plan.test.mjs → lib/audit-fix-plan.test.mjs} +50 -2
  18. package/scripts/lib/common.mjs +95 -0
  19. package/scripts/{dependency-policy-toolchain.mjs → lib/dependency-policy-toolchain.mjs} +3 -35
  20. package/scripts/{git-commit-push-fleet-common.mjs → lib/git-commit-push-fleet-common.mjs} +1 -1
  21. package/scripts/{git-discard-fleet-common.mjs → lib/git-discard-fleet-common.mjs} +1 -1
  22. package/scripts/{git-pull-fleet-common.mjs → lib/git-pull-fleet-common.mjs} +1 -1
  23. package/scripts/{override-changes.mjs → lib/override-changes.mjs} +20 -0
  24. package/scripts/{piwik-dimensions.test.mjs → lib/piwik-dimensions.test.mjs} +0 -5
  25. package/scripts/{release-notes-common.mjs → lib/release-notes-common.mjs} +5 -7
  26. package/scripts/{resolve-dependency-policy-path.mjs → lib/resolve-dependency-policy-path.mjs} +4 -3
  27. package/scripts/piwik.mjs +6 -6
  28. package/scripts/poeditor-download.mjs +1 -1
  29. package/scripts/poeditor-upload.mjs +1 -1
  30. package/scripts/policy-outdated.mjs +3 -8
  31. package/scripts/policy-upgrade-commit.mjs +5 -26
  32. package/scripts/policy-upgrade.mjs +6 -30
  33. package/scripts/policy-vulns.mjs +3 -8
  34. package/scripts/prune-overrides.mjs +5 -16
  35. package/scripts/prune-release-age-exclude.mjs +1 -1
  36. package/scripts/refresh-dependency-policy-from-repos.mjs +5 -7
  37. package/scripts/release.sh +2 -1
  38. package/scripts/scaffold-vue.mjs +1 -3
  39. package/scripts/sync-consumer-lefthook.mjs +7 -24
  40. package/scripts/sync-core-coding-standards.mjs +2 -17
  41. package/scripts/sync-dependency-check-suppressions-commit.mjs +7 -46
  42. package/scripts/sync-dependency-policy-commit.mjs +6 -38
  43. package/scripts/sync-dependency-policy.mjs +9 -35
  44. package/scripts/sync-node-toolchain.mjs +5 -7
  45. package/scripts/sync-pnpm-toolchain.mjs +5 -7
  46. package/scripts/sync-scaffold-vue-deps.mjs +6 -7
  47. package/scripts/sync-tooling-configs.mjs +8 -23
  48. package/scripts/sync-vite-plugin-vue-inspector.mjs +7 -39
  49. package/scripts/verify-release-notes.mjs +1 -1
  50. package/scaffold/vue/.gitignore +0 -13
  51. package/scripts/cz/.cz-config.cjs +0 -29
  52. package/scripts/fleet-git-commit-push.mjs +0 -75
  53. package/scripts/fleet-git-discard.mjs +0 -66
  54. package/scripts/fleet-git-pull.mjs +0 -65
  55. package/scripts/sync-peers-from-dev.mjs +0 -31
  56. package/scripts/vuln-commit.mjs +0 -142
  57. /package/configs/{fallowrc.sync-stub.json → fallowrc.json} +0 -0
  58. /package/scripts/{dependency-policy-pins.mjs → lib/dependency-policy-pins.mjs} +0 -0
  59. /package/scripts/{fleet-project-repos.mjs → lib/fleet-project-repos.mjs} +0 -0
  60. /package/scripts/{fleet-repo-picker.mjs → lib/fleet-repo-picker.mjs} +0 -0
  61. /package/scripts/{fleet-vue-repos.mjs → lib/fleet-vue-repos.mjs} +0 -0
  62. /package/scripts/{git-fleet-common.mjs → lib/git-fleet-common.mjs} +0 -0
  63. /package/scripts/{node-toolchain-sync.mjs → lib/node-toolchain-sync.mjs} +0 -0
  64. /package/scripts/{piwik-common.mjs → lib/piwik-common.mjs} +0 -0
  65. /package/scripts/{piwik-dimensions.mjs → lib/piwik-dimensions.mjs} +0 -0
  66. /package/scripts/{pnpm-toolchain-sync.mjs → lib/pnpm-toolchain-sync.mjs} +0 -0
  67. /package/scripts/{poeditor-common.mjs → lib/poeditor-common.mjs} +0 -0
@@ -7,6 +7,7 @@
7
7
 
8
8
  import fs from 'node:fs'
9
9
  import path from 'node:path'
10
+ import { fgDevkitRoot } from './common.mjs'
10
11
 
11
12
  const DEFAULT_POLICY = 'dependency-policy.vue-workspace.json'
12
13
 
@@ -16,12 +17,12 @@ const DEFAULT_POLICY = 'dependency-policy.vue-workspace.json'
16
17
  * - Absolute path: used as-is
17
18
  * - Relative path: if it exists under cwd, use it; else fg-devkit/configs/<arg>
18
19
  */
19
- export function resolveDependencyPolicyPath(scriptDir, cwd, argv) {
20
+ export function resolveDependencyPolicyPath(cwd, argv) {
20
21
  // Optional policy path is argv[2] only when it is not an option flag
21
22
  // (e.g. `policy-upgrade --interactive` must use the default policy file).
22
23
  const arg = argv[2]
23
24
  if (!arg || arg.startsWith('-')) {
24
- return path.resolve(scriptDir, '../configs', DEFAULT_POLICY)
25
+ return path.join(fgDevkitRoot, 'configs', DEFAULT_POLICY)
25
26
  }
26
27
  if (path.isAbsolute(arg)) {
27
28
  return arg
@@ -30,5 +31,5 @@ export function resolveDependencyPolicyPath(scriptDir, cwd, argv) {
30
31
  if (fs.existsSync(fromCwd)) {
31
32
  return fromCwd
32
33
  }
33
- return path.resolve(scriptDir, '../configs', arg)
34
+ return path.join(fgDevkitRoot, 'configs', arg)
34
35
  }
package/scripts/piwik.mjs CHANGED
@@ -37,14 +37,14 @@ import {
37
37
  planLocalPull,
38
38
  renderTable,
39
39
  rewriteDimensionNumbers,
40
- } from './piwik-dimensions.mjs'
40
+ } from './lib/piwik-dimensions.mjs'
41
41
  import {
42
42
  assertApiConfig,
43
43
  createPiwikClient,
44
44
  loadLocalDimensions,
45
45
  resolveEnvironmentPair,
46
46
  resolvePiwikConfig,
47
- } from './piwik-common.mjs'
47
+ } from './lib/piwik-common.mjs'
48
48
 
49
49
  const COMMANDS = new Set(['list', 'diff', 'add', 'update', 'sync', 'pull', 'compare', 'migrate'])
50
50
 
@@ -83,7 +83,7 @@ slot is not the local slot.`)
83
83
  }
84
84
 
85
85
  /**
86
- * @param {import('./piwik-dimensions.mjs').LocalDimension[]} locals
86
+ * @param {import('./lib/piwik-dimensions.mjs').LocalDimension[]} locals
87
87
  */
88
88
  function printLocal(locals) {
89
89
  for (const scope of SCOPES) {
@@ -100,7 +100,7 @@ function printLocal(locals) {
100
100
  }
101
101
 
102
102
  /**
103
- * @param {import('./piwik-dimensions.mjs').RemoteDimension[]} dimensions
103
+ * @param {import('./lib/piwik-dimensions.mjs').RemoteDimension[]} dimensions
104
104
  * @param {Record<string, { used?: number, available?: number, left?: number }>} slots
105
105
  */
106
106
  function printRemote(dimensions, slots) {
@@ -149,7 +149,7 @@ async function confirmApply(message, config) {
149
149
  /**
150
150
  * @param {ReturnType<typeof createPiwikClient>} client
151
151
  * @param {ReturnType<typeof resolvePiwikConfig>} config
152
- * @param {import('./piwik-dimensions.mjs').LocalDimension[]} creates
152
+ * @param {import('./lib/piwik-dimensions.mjs').LocalDimension[]} creates
153
153
  */
154
154
  async function applyCreates(client, config, creates) {
155
155
  for (const local of creates) {
@@ -179,7 +179,7 @@ async function applyCreates(client, config, creates) {
179
179
  /**
180
180
  * @param {ReturnType<typeof createPiwikClient>} client
181
181
  * @param {string} websiteId
182
- * @param {{ local: import('./piwik-dimensions.mjs').LocalDimension, remote: import('./piwik-dimensions.mjs').RemoteDimension }[]} updates
182
+ * @param {{ local: import('./lib/piwik-dimensions.mjs').LocalDimension, remote: import('./lib/piwik-dimensions.mjs').RemoteDimension }[]} updates
183
183
  */
184
184
  async function applyUpdates(client, websiteId, updates) {
185
185
  for (const { local, remote } of updates) {
@@ -18,7 +18,7 @@ import {
18
18
  loadPoeditorConfig,
19
19
  parseFlags,
20
20
  resolvePathFromCwd,
21
- } from './poeditor-common.mjs'
21
+ } from './lib/poeditor-common.mjs'
22
22
 
23
23
  async function exportLanguage({ token, projectId, language, format }) {
24
24
  const params = new URLSearchParams({
@@ -13,7 +13,7 @@
13
13
  import fs from 'node:fs'
14
14
  import path from 'node:path'
15
15
 
16
- import { getFlagValue, getPoeditorToken, loadPoeditorConfig, parseFlags, resolvePathFromCwd } from './poeditor-common.mjs'
16
+ import { getFlagValue, getPoeditorToken, loadPoeditorConfig, parseFlags, resolvePathFromCwd } from './lib/poeditor-common.mjs'
17
17
 
18
18
  const MIN_UPLOAD_INTERVAL_MS = 20_000
19
19
  const MAX_UPLOAD_RETRIES = 3
@@ -11,15 +11,10 @@ import fs from 'node:fs'
11
11
  import os from 'node:os'
12
12
  import path from 'node:path'
13
13
  import { spawnSync } from 'node:child_process'
14
- import { fileURLToPath } from 'node:url'
15
- import { resolveDependencyPolicyPath } from './resolve-dependency-policy-path.mjs'
14
+ import { resolveDependencyPolicyPath } from './lib/resolve-dependency-policy-path.mjs'
15
+ import { readJson } from './lib/common.mjs'
16
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
- }
17
+ const policyPath = resolveDependencyPolicyPath(process.cwd(), process.argv)
23
18
 
24
19
  const policy = readJson(policyPath)
25
20
  const deps = {
@@ -17,10 +17,12 @@ import {
17
17
  collectOverrideChanges,
18
18
  collectOverrides,
19
19
  formatOverrideValue,
20
- } from './override-changes.mjs'
20
+ } from './lib/override-changes.mjs'
21
+ import { readJson, runGit, stageExistingFiles } from './lib/common.mjs'
21
22
 
22
23
  const require = createRequire(import.meta.url)
23
24
  const cwd = process.cwd()
25
+ const GIT = { cwd, tag: '[policy-upgrade-commit]' }
24
26
  const scriptDir = path.dirname(fileURLToPath(import.meta.url))
25
27
  const packageJsonPath = path.join(cwd, 'package.json')
26
28
  const PRUNE_FLAG = '--prune-overrides'
@@ -59,19 +61,6 @@ function runNcu(args = []) {
59
61
  return result.status ?? 1
60
62
  }
61
63
 
62
- function runGit(args) {
63
- const result = spawnSync('git', args, {
64
- stdio: 'inherit',
65
- cwd,
66
- env: process.env,
67
- })
68
- if (result.error) {
69
- console.error('[policy-upgrade-commit]', result.error.message)
70
- return 1
71
- }
72
- return result.status ?? 1
73
- }
74
-
75
64
  function runPruneOverridesFix() {
76
65
  console.log('[policy-upgrade-commit] Pruning overrides that no longer affect pnpm audit…')
77
66
  const result = spawnSync(process.execPath, [path.join(scriptDir, 'prune-overrides.mjs'), '--fix'], {
@@ -86,16 +75,6 @@ function runPruneOverridesFix() {
86
75
  return result.status ?? 1
87
76
  }
88
77
 
89
- function stageExistingFiles(files) {
90
- const existingFiles = files.filter((filePath) => fs.existsSync(path.join(cwd, filePath)))
91
- if (existingFiles.length === 0) return 0
92
- return runGit(['add', '--', ...existingFiles])
93
- }
94
-
95
- function readJson(jsonPath) {
96
- return JSON.parse(fs.readFileSync(jsonPath, 'utf8'))
97
- }
98
-
99
78
  function collectPackageVersionChanges(beforePackage, afterPackage) {
100
79
  const before = {
101
80
  ...(beforePackage.dependencies ?? {}),
@@ -144,7 +123,7 @@ function buildCommitMessage(changed) {
144
123
  }
145
124
 
146
125
  function commitChanges(prefix, subject, body) {
147
- const stageExitCode = stageExistingFiles(['package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml'])
126
+ const stageExitCode = stageExistingFiles(['package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml'], GIT)
148
127
  if (stageExitCode !== 0) {
149
128
  return stageExitCode
150
129
  }
@@ -153,7 +132,7 @@ function commitChanges(prefix, subject, body) {
153
132
  console.log(body)
154
133
  }
155
134
  const commitArgs = body ? ['commit', '-m', subject, '-m', body] : ['commit', '-m', subject]
156
- return runGit(commitArgs)
135
+ return runGit(commitArgs, GIT).status
157
136
  }
158
137
 
159
138
  function pruneAndCommitOverrides() {
@@ -15,14 +15,13 @@ import fs from 'node:fs'
15
15
  import os from 'node:os'
16
16
  import path from 'node:path'
17
17
  import { spawnSync } from 'node:child_process'
18
- import { fileURLToPath } from 'node:url'
19
18
  import { createRequire } from 'node:module'
20
- import { resolveDependencyPolicyPath } from './resolve-dependency-policy-path.mjs'
19
+ import { resolveDependencyPolicyPath } from './lib/resolve-dependency-policy-path.mjs'
21
20
  import { syncScaffoldVueDepsFromPolicy } from './sync-scaffold-vue-deps.mjs'
21
+ import { fgDevkitRoot, readJson, runGit, stageExistingFiles } from './lib/common.mjs'
22
22
 
23
23
  const require = createRequire(import.meta.url)
24
- const scriptDir = path.dirname(fileURLToPath(import.meta.url))
25
- const fgDevkitRoot = path.resolve(scriptDir, '..')
24
+ const GIT = { cwd: fgDevkitRoot, tag: '[policy-upgrade]' }
26
25
 
27
26
  if (process.argv.includes('--help') || process.argv.includes('-h')) {
28
27
  console.log(`Usage:
@@ -36,13 +35,9 @@ Examples:
36
35
 
37
36
  const argPolicy = process.argv[2]
38
37
  const hasPolicyArg = Boolean(argPolicy) && !argPolicy.startsWith('-')
39
- const policyPath = resolveDependencyPolicyPath(scriptDir, process.cwd(), process.argv)
38
+ const policyPath = resolveDependencyPolicyPath(process.cwd(), process.argv)
40
39
  const ncuArgs = hasPolicyArg ? process.argv.slice(3) : process.argv.slice(2)
41
40
 
42
- function readJson(p) {
43
- return JSON.parse(fs.readFileSync(p, 'utf8'))
44
- }
45
-
46
41
  function collectPolicyVersions(policy) {
47
42
  return {
48
43
  ...(policy.managedDependencies?.dependencies ?? {}),
@@ -72,25 +67,6 @@ function buildCommitMessage(changed) {
72
67
  return { subject: `dep(): bump ${changed.length} packages`, body }
73
68
  }
74
69
 
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
70
  function toRepoRelative(absolutePath) {
95
71
  return path.relative(fgDevkitRoot, absolutePath)
96
72
  }
@@ -188,7 +164,7 @@ const stageExitCode = stageExistingFiles([
188
164
  toRepoRelative(policyPath),
189
165
  'scaffold/vue/package.json',
190
166
  'scaffold/vue/Dockerfile.local',
191
- ])
167
+ ], GIT)
192
168
  if (stageExitCode !== 0) {
193
169
  process.exit(stageExitCode)
194
170
  }
@@ -199,4 +175,4 @@ if (body) {
199
175
  console.log(body)
200
176
  }
201
177
  const commitArgs = body ? ['commit', '-m', subject, '-m', body] : ['commit', '-m', subject]
202
- process.exit(runGit(commitArgs))
178
+ process.exit(runGit(commitArgs, GIT).status)
@@ -11,15 +11,10 @@ import fs from 'node:fs'
11
11
  import os from 'node:os'
12
12
  import path from 'node:path'
13
13
  import { spawnSync } from 'node:child_process'
14
- import { fileURLToPath } from 'node:url'
15
- import { resolveDependencyPolicyPath } from './resolve-dependency-policy-path.mjs'
14
+ import { resolveDependencyPolicyPath } from './lib/resolve-dependency-policy-path.mjs'
15
+ import { readJson } from './lib/common.mjs'
16
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
- }
17
+ const policyPath = resolveDependencyPolicyPath(process.cwd(), process.argv)
23
18
 
24
19
  const policy = readJson(policyPath)
25
20
  console.log(`[policy-vulns] policy=${policyPath}`)
@@ -23,9 +23,11 @@ import {
23
23
  collectOverrideChanges,
24
24
  collectOverrides,
25
25
  formatOverrideValue,
26
- } from './override-changes.mjs'
26
+ } from './lib/override-changes.mjs'
27
+ import { runGit } from './lib/common.mjs'
27
28
 
28
29
  const ROOT = process.cwd()
30
+ const GIT = { cwd: ROOT, tag: '[prune-overrides]' }
29
31
  const WORKSPACE_FILE = 'pnpm-workspace.yaml'
30
32
  const COPIED_FILES = ['package.json', 'pnpm-lock.yaml', WORKSPACE_FILE, '.npmrc']
31
33
 
@@ -49,19 +51,6 @@ Pass --commit to apply the deletions and auto-commit.`)
49
51
 
50
52
  const shouldFix = args.fix || args.commit
51
53
 
52
- function runGit(gitArgs) {
53
- const result = spawnSync('git', gitArgs, {
54
- stdio: 'inherit',
55
- cwd: ROOT,
56
- env: process.env,
57
- })
58
- if (result.error) {
59
- console.error('[prune-overrides]', result.error.message)
60
- return 1
61
- }
62
- return result.status ?? 1
63
- }
64
-
65
54
  function commitOverrideChanges(beforeOverrides, afterOverrides) {
66
55
  const changed = collectOverrideChanges(beforeOverrides, afterOverrides)
67
56
  if (changed.length === 0) {
@@ -83,7 +72,7 @@ function commitOverrideChanges(beforeOverrides, afterOverrides) {
83
72
  return 1
84
73
  }
85
74
 
86
- const stageExitCode = runGit(['add', '--', ...files])
75
+ const stageExitCode = runGit(['add', '--', ...files], GIT).status
87
76
  if (stageExitCode !== 0) {
88
77
  return stageExitCode
89
78
  }
@@ -94,7 +83,7 @@ function commitOverrideChanges(beforeOverrides, afterOverrides) {
94
83
  console.log(body)
95
84
  }
96
85
  const commitArgs = body ? ['commit', '-m', subject, '-m', body] : ['commit', '-m', subject]
97
- return runGit(commitArgs)
86
+ return runGit(commitArgs, GIT).status
98
87
  }
99
88
 
100
89
  function runPnpm(cwd, pnpmArgs, { allowFailure = false } = {}) {
@@ -24,7 +24,7 @@ import {
24
24
  planReleaseAgeExcludePrune,
25
25
  readWorkspaceList,
26
26
  rewriteWorkspaceList,
27
- } from './audit-fix-plan.mjs'
27
+ } from './lib/audit-fix-plan.mjs'
28
28
 
29
29
  const TAG = '[prune-release-age-exclude]'
30
30
  const KEY = 'minimumReleaseAgeExclude'
@@ -26,19 +26,17 @@
26
26
 
27
27
  import fs from 'node:fs'
28
28
  import path from 'node:path'
29
- import { fileURLToPath } from 'node:url'
30
29
 
31
- import { collectPinViolations } from './dependency-policy-pins.mjs'
32
- import { collectToolchainPolicyViolations } from './dependency-policy-toolchain.mjs'
30
+ import { collectPinViolations } from './lib/dependency-policy-pins.mjs'
31
+ import { collectToolchainPolicyViolations } from './lib/dependency-policy-toolchain.mjs'
33
32
  import { syncScaffoldVueDepsFromPolicy } from './sync-scaffold-vue-deps.mjs'
33
+ import { fgDevkitRoot } from './lib/common.mjs'
34
34
 
35
- const scriptDir = path.dirname(fileURLToPath(import.meta.url))
36
- const fgDevkitRoot = path.resolve(scriptDir, '..')
37
35
  const fgDevkitPackageJsonPath = path.join(fgDevkitRoot, 'package.json')
38
36
 
39
37
  const projectsRoot = process.argv[2]
40
38
  ? path.resolve(process.cwd(), process.argv[2])
41
- : path.resolve(scriptDir, '../..')
39
+ : path.resolve(fgDevkitRoot, '..')
42
40
 
43
41
  const policyPath = process.argv[3]
44
42
  ? path.resolve(process.cwd(), process.argv[3])
@@ -56,7 +54,7 @@ try {
56
54
  /** Relative paths under projectsRoot whose package.json files are ignored (maintainer choice). */
57
55
  /** Relative path prefixes under projectsRoot to skip when scanning (add repo names as needed). */
58
56
  const SKIP_DIR_PREFIXES = []
59
- const EXTRA_TOOLING_EXCLUDES = new Set(['husky', 'lint-staged', '@rushstack/eslint-patch', 'jsonc-eslint-parser', 'yaml-eslint-parser'])
57
+ const EXTRA_TOOLING_EXCLUDES = new Set(['@rushstack/eslint-patch', 'jsonc-eslint-parser', 'yaml-eslint-parser'])
60
58
  const EXCLUDED_POLICY_PACKAGES = (() => {
61
59
  try {
62
60
  const pkg = JSON.parse(fs.readFileSync(fgDevkitPackageJsonPath, 'utf8'))
@@ -79,7 +79,8 @@ is_fg_devkit_repo="$(
79
79
  sync_fg_devkit_package_files() {
80
80
  if [[ "$is_fg_devkit_repo" == "yes" && -f "./scripts/sync-scaffold-vue-deps.mjs" && -f "./scaffold/vue/package.json" ]]; then
81
81
  node ./scripts/sync-scaffold-vue-deps.mjs
82
- git add package.json scaffold/vue/package.json
82
+ # Stage everything sync-scaffold-vue-deps can write, or the release leaves it uncommitted.
83
+ git add package.json scaffold/vue/package.json configs/dependency-policy.vue-workspace.json
83
84
  else
84
85
  git add package.json
85
86
  fi
@@ -26,10 +26,8 @@
26
26
 
27
27
  import fs from 'node:fs'
28
28
  import path from 'node:path'
29
- import { fileURLToPath } from 'node:url'
29
+ import { fgDevkitRoot } from './lib/common.mjs'
30
30
 
31
- const scriptDir = path.dirname(fileURLToPath(import.meta.url))
32
- const fgDevkitRoot = path.resolve(scriptDir, '..')
33
31
  const scaffoldRoot = path.join(fgDevkitRoot, 'scaffold/vue')
34
32
 
35
33
  /** True if the directory does not exist, is empty, or only contains a fresh clone (.git). */
@@ -2,9 +2,7 @@
2
2
  /**
3
3
  * Syncs Lefthook setup into a consuming repo:
4
4
  * - writes lefthook.yml from fg-devkit template
5
- * - removes legacy .husky directory (if present)
6
- * - removes legacy lint-staged config block from package.json
7
- * - removes legacy prepare hook scripts for husky/lefthook bootstrap
5
+ * - removes a legacy `prepare` script that bootstrapped lefthook (hooks are installed by setup-lefthook)
8
6
  *
9
7
  * Usage:
10
8
  * node node_modules/fg-devkit/scripts/sync-consumer-lefthook.mjs
@@ -13,15 +11,12 @@
13
11
 
14
12
  import fs from 'node:fs'
15
13
  import path from 'node:path'
16
- import { fileURLToPath } from 'node:url'
14
+ import { fgDevkitRoot } from './lib/common.mjs'
17
15
 
18
16
  const projectRoot = process.cwd()
19
- const scriptDir = path.dirname(fileURLToPath(import.meta.url))
20
- const fgRoot = path.resolve(scriptDir, '..')
21
17
 
22
- const lefthookTemplate = path.join(fgRoot, 'configs', 'lefthook.yml')
18
+ const lefthookTemplate = path.join(fgDevkitRoot, 'configs', 'lefthook.yml')
23
19
  const lefthookTarget = path.join(projectRoot, 'lefthook.yml')
24
- const huskyDir = path.join(projectRoot, '.husky')
25
20
  const packageJsonPath = path.join(projectRoot, 'package.json')
26
21
 
27
22
  if (!fs.existsSync(lefthookTemplate)) {
@@ -42,25 +37,13 @@ try {
42
37
  process.exit(1)
43
38
  }
44
39
 
45
- pkg.scripts = pkg.scripts && typeof pkg.scripts === 'object' ? pkg.scripts : {}
46
- if (
47
- pkg.scripts.prepare &&
48
- (pkg.scripts.prepare.includes('husky') || pkg.scripts.prepare.includes('setup-lefthook'))
49
- ) {
50
- delete pkg.scripts.prepare
51
- }
52
-
53
- if (pkg['lint-staged'] !== undefined) {
54
- delete pkg['lint-staged']
55
- }
40
+ const removePrepare = pkg.scripts?.prepare?.includes('setup-lefthook')
41
+ if (removePrepare) delete pkg.scripts.prepare
56
42
 
57
43
  try {
58
44
  fs.copyFileSync(lefthookTemplate, lefthookTarget)
59
- fs.writeFileSync(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`, 'utf8')
60
- if (fs.existsSync(huskyDir)) {
61
- fs.rmSync(huskyDir, { recursive: true, force: true })
62
- }
63
- console.log('[sync-consumer-lefthook] Synced lefthook.yml and removed .husky/lint-staged legacy setup.')
45
+ if (removePrepare) fs.writeFileSync(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`, 'utf8')
46
+ console.log('[sync-consumer-lefthook] Synced lefthook.yml.')
64
47
  } catch (err) {
65
48
  console.error(`[sync-consumer-lefthook] ${err.message}`)
66
49
  process.exit(1)
@@ -10,24 +10,9 @@
10
10
 
11
11
  import fs from 'node:fs'
12
12
  import path from 'node:path'
13
- import { fileURLToPath } from 'node:url'
13
+ import { findFgDevkitPackageRoot } from './lib/common.mjs'
14
14
 
15
15
  const projectRoot = process.cwd()
16
- const scriptDir = path.dirname(fileURLToPath(import.meta.url))
17
-
18
- function findFgDevkitPackageRoot() {
19
- const candidates = [
20
- path.resolve(scriptDir, '..'),
21
- path.join(projectRoot, 'node_modules', 'fg-devkit'),
22
- path.join(projectRoot, 'node_modules', 'fds-vue-core', 'node_modules', 'fg-devkit'),
23
- ]
24
- for (const p of candidates) {
25
- if (fs.existsSync(path.join(p, 'package.json'))) {
26
- return p
27
- }
28
- }
29
- return null
30
- }
31
16
 
32
17
  function getConsumerPackageName() {
33
18
  const pkgPath = path.join(projectRoot, 'package.json')
@@ -45,7 +30,7 @@ function getConsumerPackageName() {
45
30
  return 'consumer-project'
46
31
  }
47
32
 
48
- const fgRoot = findFgDevkitPackageRoot()
33
+ const fgRoot = findFgDevkitPackageRoot(projectRoot)
49
34
  if (!fgRoot) {
50
35
  console.error(
51
36
  '[sync-core-coding-standards] Could not find fg-devkit (install fg-devkit or a package that bundles it, e.g. fds-vue-core).',
@@ -13,16 +13,16 @@
13
13
 
14
14
  import fs from 'node:fs'
15
15
  import path from 'node:path'
16
- import { fileURLToPath } from 'node:url'
17
16
  import { spawnSync } from 'node:child_process'
18
17
  import { parseArgs } from 'node:util'
19
- import { filterSuppressions, normalizeAdvisories, parseAuditJson, parseSuppressions } from './audit-fix-plan.mjs'
18
+ import { filterSuppressions, normalizeAdvisories, parseAuditJson, parseSuppressions } from './lib/audit-fix-plan.mjs'
19
+ import { fileDiffersFromHead, findFgDevkitPackageRoot, runGit } from './lib/common.mjs'
20
20
 
21
21
  const TAG = '[sync-dependency-check-suppressions]'
22
22
  const FILE_NAME = 'dependency-check-suppressions.xml'
23
23
  const COMMIT_MESSAGE = 'chore(repo): sync dependency-check suppressions'
24
24
  const projectRoot = process.cwd()
25
- const scriptDir = path.dirname(fileURLToPath(import.meta.url))
25
+ const GIT = { cwd: projectRoot, tag: TAG }
26
26
 
27
27
  const { values: args } = parseArgs({
28
28
  options: {
@@ -42,45 +42,6 @@ pnpm audit reports in this repo, and auto-commits it.
42
42
  process.exit(0)
43
43
  }
44
44
 
45
- function findFgDevkitPackageRoot() {
46
- const candidates = [
47
- path.resolve(scriptDir, '..'),
48
- path.join(projectRoot, 'node_modules', 'fg-devkit'),
49
- path.join(projectRoot, 'node_modules', 'fds-vue-core', 'node_modules', 'fg-devkit'),
50
- ]
51
- for (const candidate of candidates) {
52
- if (fs.existsSync(path.join(candidate, 'package.json'))) {
53
- return candidate
54
- }
55
- }
56
- return null
57
- }
58
-
59
- function runGit(gitArgs, options = {}) {
60
- const result = spawnSync('git', gitArgs, {
61
- stdio: options.capture ? 'pipe' : 'inherit',
62
- encoding: options.capture ? 'utf8' : undefined,
63
- cwd: projectRoot,
64
- env: process.env,
65
- })
66
- if (result.error) {
67
- console.error(TAG, result.error.message)
68
- return { status: 1, stdout: '' }
69
- }
70
- return { status: result.status ?? 1, stdout: result.stdout ?? '' }
71
- }
72
-
73
- function fileDiffersFromHead(filePath) {
74
- const absolutePath = path.join(projectRoot, filePath)
75
- if (!fs.existsSync(absolutePath)) return false
76
-
77
- const tracked = runGit(['ls-files', '--error-unmatch', '--', filePath], { capture: true })
78
- if (tracked.status !== 0) return true
79
-
80
- const diff = runGit(['diff', '--quiet', 'HEAD', '--', filePath], { capture: true })
81
- return diff.status !== 0
82
- }
83
-
84
45
  /** GHSA ids `pnpm audit` reports in this repo. Exits on audit failure so nothing is written blindly. */
85
46
  function reportedGhsas() {
86
47
  const result = spawnSync('pnpm', ['audit', '--json'], {
@@ -97,7 +58,7 @@ function reportedGhsas() {
97
58
  return new Set(normalizeAdvisories(parseAuditJson(result.stdout)).map((advisory) => advisory.ghsa))
98
59
  }
99
60
 
100
- const fgRoot = findFgDevkitPackageRoot()
61
+ const fgRoot = findFgDevkitPackageRoot(projectRoot)
101
62
  if (!fgRoot) {
102
63
  console.error(`${TAG} Could not find fg-devkit (install fg-devkit or a package that bundles it, e.g. fds-vue-core).`)
103
64
  process.exit(1)
@@ -137,13 +98,13 @@ if (!args.all) {
137
98
  fs.writeFileSync(targetPath, content)
138
99
  console.log(`${TAG} Updated ${FILE_NAME}.`)
139
100
 
140
- if (!fileDiffersFromHead(FILE_NAME)) {
101
+ if (!fileDiffersFromHead(FILE_NAME, GIT)) {
141
102
  console.log(`${TAG} No changes to commit.`)
142
103
  process.exit(0)
143
104
  }
144
105
 
145
- const stage = runGit(['add', '--', FILE_NAME])
106
+ const stage = runGit(['add', '--', FILE_NAME], GIT)
146
107
  if (stage.status !== 0) process.exit(stage.status)
147
108
 
148
109
  console.log(`${TAG} Auto-committing: ${COMMIT_MESSAGE}`)
149
- process.exit(runGit(['commit', '-m', COMMIT_MESSAGE]).status)
110
+ process.exit(runGit(['commit', '-m', COMMIT_MESSAGE], GIT).status)