commit-pack 1.1.4 → 1.1.7

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/bin/index.mjs CHANGED
@@ -10,10 +10,40 @@ import { fileURLToPath } from 'url'
10
10
  import { log } from './chalkColor.js'
11
11
  import { installWithProgress } from './installWithProgress.js'
12
12
 
13
+ const printBanner = () => {
14
+ const top = '╭' + '─'.repeat(40) + '╮'
15
+ const bottom = '╰' + '─'.repeat(40) + '╯'
16
+ const middle = `│ ${chalk.bold.cyan('🚀 Commit Pack 初始化中...')} │`
17
+
18
+ console.log('\n' + top)
19
+ console.log(middle)
20
+ console.log(bottom + '\n')
21
+ }
22
+
13
23
  // 模拟 CommonJS 的 __dirname
14
24
  const __filename = fileURLToPath(import.meta.url)
15
25
  const __dirname = path.dirname(__filename)
16
26
 
27
+ // 解析命令行参数
28
+ const args = process.argv.slice(2)
29
+ const workspaceArgIndex = args.findIndex(
30
+ (arg) => arg.startsWith('--workspace=') || arg.startsWith('-w=')
31
+ )
32
+ let workspaceName = ''
33
+ if (workspaceArgIndex !== -1) {
34
+ const arg = args[workspaceArgIndex]
35
+ workspaceName = arg.split('=')[1]
36
+ } else {
37
+ // 查找是否有单独的 -w 或 --workspace 参数
38
+ const wIndex = args.findIndex((arg) => arg === '-w')
39
+ const workspaceIndex = args.findIndex((arg) => arg === '--workspace')
40
+ if (wIndex !== -1 && wIndex + 1 < args.length) {
41
+ workspaceName = args[wIndex + 1]
42
+ } else if (workspaceIndex !== -1 && workspaceIndex + 1 < args.length) {
43
+ workspaceName = args[workspaceIndex + 1]
44
+ }
45
+ }
46
+
17
47
  // 向上查找带锁文件的根目录
18
48
  function findProjectRootWithLockFile() {
19
49
  let dir = __dirname
@@ -46,19 +76,99 @@ function detectPackageManager() {
46
76
  }
47
77
 
48
78
  const packageManager = detectPackageManager()
79
+
80
+ // 计算实际的工作目录
81
+ let actualProjectRoot = projectRoot
82
+ if (workspaceName) {
83
+ const packageJsonContent = JSON.parse(
84
+ fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf8')
85
+ )
86
+
87
+ // 根据包管理器确定工作spaces路径
88
+ let workspaces = []
89
+ if (packageJsonContent.workspaces) {
90
+ if (Array.isArray(packageJsonContent.workspaces)) {
91
+ workspaces = packageJsonContent.workspaces
92
+ } else if (packageJsonContent.workspaces.packages) {
93
+ workspaces = packageJsonContent.workspaces.packages
94
+ }
95
+ }
96
+
97
+ // 查找workspace包的路径
98
+ if (workspaces.length > 0) {
99
+ for (const workspacePattern of workspaces) {
100
+ // 处理通配符模式,例如 'packages/*'
101
+ if (workspacePattern.includes('*')) {
102
+ const basePath = workspacePattern.replace('/*', '')
103
+ const packagesDir = path.join(projectRoot, basePath)
104
+ if (fs.existsSync(packagesDir)) {
105
+ const packageDirs = fs.readdirSync(packagesDir)
106
+ for (const dir of packageDirs) {
107
+ const dirPath = path.join(packagesDir, dir)
108
+ if (fs.statSync(dirPath).isDirectory()) {
109
+ try {
110
+ const pkgPath = path.join(dirPath, 'package.json')
111
+ if (fs.existsSync(pkgPath)) {
112
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'))
113
+ if (pkg.name === workspaceName || dir === workspaceName) {
114
+ actualProjectRoot = dirPath
115
+ break
116
+ }
117
+ }
118
+ } catch (e) {
119
+ console.log(e)
120
+ }
121
+ }
122
+ }
123
+ }
124
+ } else {
125
+ // 直接路径匹配
126
+ const dirPath = path.join(projectRoot, workspacePattern)
127
+ if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
128
+ try {
129
+ const pkgPath = path.join(dirPath, 'package.json')
130
+ if (fs.existsSync(pkgPath)) {
131
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'))
132
+ if (
133
+ pkg.name === workspaceName ||
134
+ path.basename(dirPath) === workspaceName
135
+ ) {
136
+ actualProjectRoot = dirPath
137
+ break
138
+ }
139
+ }
140
+ } catch (e) {
141
+ console.log(e)
142
+ }
143
+ }
144
+ }
145
+ }
146
+ }
147
+ }
148
+
149
+ console.log('')
150
+ printBanner()
151
+ console.log('')
49
152
  console.log('')
50
153
  console.log(`🍀 包管理器:${packageManager}`)
51
- console.log(`📁 根目录:${projectRoot}`)
154
+ console.log(`📁 根目录:${actualProjectRoot}`)
155
+ if (workspaceName) {
156
+ console.log(`📦 工作空间: ${workspaceName}`)
157
+ }
52
158
 
53
- const packageJsonPath = path.join(projectRoot, 'package.json')
159
+ const packageJsonPath = path.join(actualProjectRoot, 'package.json')
54
160
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
55
161
 
56
162
  // 检查是否已经初始化过
57
- const initFlagPath = path.join(projectRoot, '.commit-pack-init')
163
+ const initFlagPath = path.join(actualProjectRoot, '.commit-pack-init')
58
164
  if (fs.existsSync(initFlagPath)) {
165
+ console.log(log.warn('⚠️ 该工作空间/项目已被初始化,跳过初始化'))
59
166
  process.exit(0)
60
167
  }
61
168
 
169
+ // 回滚机制:记录初始状态
170
+ const initialPackageJson = JSON.stringify(packageJson, null, 2)
171
+
62
172
  // 确保 devDependencies 存在
63
173
  if (!packageJson.devDependencies) {
64
174
  packageJson.devDependencies = {}
@@ -100,55 +210,57 @@ for (const [dep, version] of Object.entries(devDependenciesWithVersion)) {
100
210
  }
101
211
  }
102
212
 
103
- installWithProgress(dependenciesToInstall, packageManager, projectRoot)
104
-
105
- let isGitRepo = false
106
-
107
213
  try {
108
- // 获取 Git 仓库的顶级目录
109
- const gitTopLevel = execSync('git rev-parse --show-toplevel', { cwd: projectRoot })
110
- .toString()
111
- .trim()
112
- // 比较顶级目录与当前项目目录
113
- if (path.resolve(gitTopLevel) === path.resolve(projectRoot)) {
114
- isGitRepo = true
115
- } else {
214
+ installWithProgress(dependenciesToInstall, packageManager, actualProjectRoot)
215
+
216
+ let isGitRepo = false
217
+
218
+ try {
219
+ // 获取 Git 仓库的顶级目录
220
+ const gitTopLevel = execSync('git rev-parse --show-toplevel', {
221
+ cwd: actualProjectRoot
222
+ })
223
+ .toString()
224
+ .trim()
225
+ // 比较顶级目录与当前项目目录
226
+ if (path.resolve(gitTopLevel) === path.resolve(actualProjectRoot)) {
227
+ isGitRepo = true
228
+ } else {
229
+ isGitRepo = false
230
+ }
231
+ } catch {
116
232
  isGitRepo = false
117
233
  }
118
- } catch {
119
- isGitRepo = false
120
- }
121
234
 
122
- if (isGitRepo) {
123
- console.log(log.success('👍 Git仓库已存在'))
124
- } else {
125
- console.log(log.warn('👌 Git仓库初始化...'))
126
- execSync('git init', { stdio: 'inherit', cwd: projectRoot })
127
- }
235
+ if (isGitRepo) {
236
+ console.log(log.success('👍 Git仓库已存在'))
237
+ } else {
238
+ console.log(log.warn('👌 Git仓库初始化...'))
239
+ execSync('git init', { stdio: 'inherit', cwd: actualProjectRoot })
240
+ }
128
241
 
129
- // 根据包管理器,执行对应的 Husky 初始化命令
130
- let huskyInitCommand = ''
131
- switch (packageManager) {
132
- case 'pnpm':
133
- huskyInitCommand = 'pnpm exec husky init'
134
- break
135
- case 'yarn':
136
- huskyInitCommand = 'yarn dlx husky init'
137
- break
138
- case 'bun':
139
- huskyInitCommand = 'bunx husky init'
140
- break
141
- default:
142
- huskyInitCommand = 'npx husky init'
143
- break
144
- }
242
+ // 根据包管理器,执行对应的 Husky 初始化命令
243
+ let huskyInitCommand = ''
244
+ switch (packageManager) {
245
+ case 'pnpm':
246
+ huskyInitCommand = 'pnpm exec husky init'
247
+ break
248
+ case 'yarn':
249
+ huskyInitCommand = 'yarn dlx husky init'
250
+ break
251
+ case 'bun':
252
+ huskyInitCommand = 'bunx husky init'
253
+ break
254
+ default:
255
+ huskyInitCommand = 'npx husky init'
256
+ break
257
+ }
145
258
 
146
- console.log(chalk.green(`🐶 Husky初始化...`))
147
- execSync(huskyInitCommand, { stdio: 'inherit', cwd: projectRoot })
259
+ console.log(chalk.green(`🐶 Husky初始化...`))
260
+ execSync(huskyInitCommand, { stdio: 'inherit', cwd: actualProjectRoot })
148
261
 
149
- // 执行 setup-script 中的所有文件
150
- console.log('🚀 创建配置文件...')
151
- try {
262
+ // 执行 setup-script 中的所有文件
263
+ console.log('🚀 创建配置文件...')
152
264
  const setupScripts = [
153
265
  'prettier.sh',
154
266
  'lintstagedrc.sh',
@@ -161,61 +273,153 @@ try {
161
273
 
162
274
  for (const script of setupScripts) {
163
275
  const scriptPath = path.join(__dirname, '..', 'setup-script', script)
164
- execSync(`sh ${scriptPath}`, { stdio: 'inherit', cwd: projectRoot })
276
+ execSync(`sh ${scriptPath}`, { stdio: 'inherit', cwd: actualProjectRoot })
165
277
  }
166
- } catch (error) {
167
- console.error(log.warn('❌ 文件创建出错'), error)
168
- }
169
278
 
170
- // 创建或更新脚本
171
- if (!packageJson.scripts) {
172
- packageJson.scripts = {}
173
- console.log('🔥 创建或更新脚本...')
174
- }
279
+ // 创建或更新脚本
280
+ if (!packageJson.scripts) {
281
+ packageJson.scripts = {}
282
+ console.log('🔥 创建或更新脚本...')
283
+ }
284
+
285
+ let modified = false
286
+
287
+ if (!packageJson.scripts.lint) {
288
+ if (workspaceName) {
289
+ // 为workspace项目使用工作空间命令
290
+ if (packageManager === 'pnpm') {
291
+ packageJson.scripts.lint = `pnpm -F ${workspaceName} exec eslint ./ --ext .ts,.tsx,.json --max-warnings=0`
292
+ } else if (packageManager === 'yarn') {
293
+ packageJson.scripts.lint = `yarn workspace ${workspaceName} exec eslint ./ --ext .ts,.tsx,.json --max-warnings=0`
294
+ } else {
295
+ packageJson.scripts.lint = 'eslint ./ --ext .ts,.tsx,.json --max-warnings=0'
296
+ }
297
+ } else {
298
+ packageJson.scripts.lint = 'eslint ./ --ext .ts,.tsx,.json --max-warnings=0'
299
+ }
300
+ console.log(log.success('✅ 已添加 "lint" 至 package.json'))
301
+ modified = true
302
+ } else {
303
+ console.log(log.warn('⚠️ package.json 中已存在 "lint" 未作修改'))
304
+ }
175
305
 
176
- let modified = false
306
+ if (!packageJson.scripts.format) {
307
+ if (workspaceName) {
308
+ // 为workspace项目使用工作空间命令
309
+ if (packageManager === 'pnpm') {
310
+ packageJson.scripts.format = `pnpm -F ${workspaceName} exec prettier --config .prettierrc '.' --write`
311
+ } else if (packageManager === 'yarn') {
312
+ packageJson.scripts.format = `yarn workspace ${workspaceName} exec prettier --config .prettierrc '.' --write`
313
+ } else {
314
+ packageJson.scripts.format = "prettier --config .prettierrc '.' --write"
315
+ }
316
+ } else {
317
+ packageJson.scripts.format = "prettier --config .prettierrc '.' --write"
318
+ }
319
+ console.log(log.success('✅ 已添加 "format" 至 package.json'))
320
+ modified = true
321
+ } else {
322
+ console.log(log.warn('⚠️ package.json 中已存在 "format" 未作修改'))
323
+ }
177
324
 
178
- if (!packageJson.scripts.lint) {
179
- packageJson.scripts.lint = 'eslint ./ --ext .ts,.tsx,.json --max-warnings=0'
180
- console.log(log.success('已添加 "lint" 至 package.json'))
325
+ // 添加或更新 "commit" 脚本
326
+ if (workspaceName) {
327
+ // 为workspace项目使用工作空间命令
328
+ if (packageManager === 'pnpm') {
329
+ packageJson.scripts.commit = `pnpm -F ${workspaceName} exec cz`
330
+ } else if (packageManager === 'yarn') {
331
+ packageJson.scripts.commit = `yarn workspace ${workspaceName} exec cz`
332
+ } else {
333
+ packageJson.scripts.commit = 'cz'
334
+ }
335
+ } else {
336
+ packageJson.scripts.commit = 'cz'
337
+ }
338
+ console.log(log.success('✅ 已添加 "commit" 至 package.json'))
181
339
  modified = true
182
- } else {
183
- console.log(log.warn('package.json 中已存在 "lint" 未作修改'))
184
- }
185
340
 
186
- if (!packageJson.scripts.format) {
187
- packageJson.scripts.format = "prettier --config .prettierrc '.' --write"
188
- console.log(log.success('已添加 "format" 至 package.json'))
341
+ // 添加或更新 "config.commitizen" 配置
342
+ if (!packageJson.config) {
343
+ packageJson.config = {}
344
+ }
345
+
346
+ packageJson.config.commitizen = {
347
+ path: 'node_modules/cz-customizable'
348
+ }
189
349
  modified = true
190
- } else {
191
- console.log(log.warn('package.json 中已存在 "format" 未作修改'))
192
- }
193
350
 
194
- // 添加或更新 "commit" 脚本
195
- packageJson.scripts.commit = 'cz'
196
- console.log(log.success('已添加或更新 "commit" 脚本到 package.json'))
197
- modified = true
351
+ // 写入修改后的 package.json
352
+ if (modified) {
353
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf8')
354
+ console.log(chalk.green('✅ 已更新 package.json'))
355
+ console.log('')
356
+ console.log('')
357
+ }
198
358
 
199
- // 添加或更新 "config.commitizen" 配置
200
- if (!packageJson.config) {
201
- packageJson.config = {}
202
- }
359
+ // 创建初始化标志文件
360
+ fs.writeFileSync(initFlagPath, 'initialized', 'utf8')
361
+ console.log(log.success(' 🎉🎉🎉 完成啦!'))
362
+ console.log('')
363
+ if (workspaceName) {
364
+ console.log(
365
+ ` 在 ${workspaceName} 工作空间中,运行: git add . && ${packageManager} run commit`
366
+ )
367
+ } else {
368
+ console.log(` 运行 git add 后 | 运行 ${packageManager} run commit 即可`)
369
+ }
370
+ } catch (error) {
371
+ console.error(log.error('❌ 初始化过程中发生错误,正在执行回滚...'))
372
+ console.error('错误详情:', error.message)
373
+ console.error('错误堆栈:', error.stack)
374
+ if (error.stdout) console.error('标准输出:', error.stdout.toString())
375
+ if (error.stderr) console.error('错误输出:', error.stderr.toString())
376
+
377
+ try {
378
+ // 回滚:恢复原始的package.json
379
+ fs.writeFileSync(packageJsonPath, initialPackageJson, 'utf8')
380
+ console.log(log.warn('✅ 已恢复原始 package.json'))
381
+
382
+ // 删除可能创建的配置文件
383
+ const configFiles = [
384
+ '.prettierrc',
385
+ '.eslintrc',
386
+ '.commitlintrc.json',
387
+ '.cz-config.js',
388
+ '.czrc',
389
+ '.lintstagedrc',
390
+ '.prettierignore',
391
+ '.eslintignore'
392
+ ]
393
+ for (const configFile of configFiles) {
394
+ const configPath = path.join(actualProjectRoot, configFile)
395
+ if (fs.existsSync(configPath)) {
396
+ fs.unlinkSync(configPath)
397
+ console.log(log.warn(`✅ 已删除临时配置文件: ${configFile}`))
398
+ }
399
+ }
203
400
 
204
- packageJson.config.commitizen = {
205
- path: 'node_modules/cz-customizable'
206
- }
207
- modified = true
401
+ // 删除可能创建的.husky目录
402
+ const huskyDir = path.join(actualProjectRoot, '.husky')
403
+ if (fs.existsSync(huskyDir)) {
404
+ fs.rmSync(huskyDir, { recursive: true, force: true })
405
+ console.log(log.warn('✅ 已删除临时 .husky 目录'))
406
+ }
208
407
 
209
- // 写入修改后的 package.json
210
- if (modified) {
211
- fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf8')
212
- console.log(chalk.green('已更新 package.json'))
213
- console.log('')
214
- console.log('')
215
- }
408
+ // 删除初始化标志文件
409
+ if (fs.existsSync(initFlagPath)) {
410
+ fs.unlinkSync(initFlagPath)
411
+ }
216
412
 
217
- // 创建初始化标志文件
218
- // fs.writeFileSync(initFlagPath, 'initialized', 'utf8')
219
- console.log(log.success(' 🎉🎉🎉 完成啦!'))
220
- console.log('')
221
- console.log(` 运行 git add 后 | 运行 ${packageManager} run commit 即可`)
413
+ console.log(log.success(' 🔄 回滚完成'))
414
+ } catch (rollbackError) {
415
+ console.error(log.error(' 回滚过程中也发生了错误,请手动检查项目状态'))
416
+ console.error('回滚错误详情:', rollbackError.message)
417
+ console.error('回滚错误堆栈:', rollbackError.stack)
418
+ if (rollbackError.stdout)
419
+ console.error('回滚标准输出:', rollbackError.stdout.toString())
420
+ if (rollbackError.stderr)
421
+ console.error('回滚错误输出:', rollbackError.stderr.toString())
422
+ }
423
+
424
+ process.exit(1) // 确保进程以错误码退出
425
+ }
@@ -1,6 +1,8 @@
1
1
  /* eslint-env node */
2
2
  import chalk from 'chalk'
3
3
  import { execSync } from 'child_process'
4
+ import fs from 'fs'
5
+ import path from 'path'
4
6
  import cliProgress from 'cli-progress'
5
7
 
6
8
  export function installWithProgress(dependencies, packageManager, projectRoot) {
@@ -10,10 +12,17 @@ export function installWithProgress(dependencies, packageManager, projectRoot) {
10
12
  }
11
13
 
12
14
  console.log('')
13
- console.log(chalk.cyan(`⬇️ 开始安装依赖...`))
15
+ console.log(`⬇️ 开始安装依赖...`)
16
+
17
+ // 检查是否为 monorepo(检查是否有 pnpm-workspace.yaml 或 package.json 中的 workspaces 字段)
18
+ const isMonorepo =
19
+ fs.existsSync(path.join(projectRoot, 'pnpm-workspace.yaml')) ||
20
+ (fs.existsSync(path.join(projectRoot, 'package.json')) &&
21
+ JSON.parse(fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf8'))
22
+ .workspaces)
14
23
 
15
24
  const bar = new cliProgress.SingleBar({
16
- format: `${chalk.green('📦 安装中')} [{bar}] {percentage}% | {value}/{total} | 正在安装: {dep}`,
25
+ format: ` [${chalk.cyan('{bar}')}]{percentage}% | 正在安装: {dep}`,
17
26
  barCompleteChar: '▰',
18
27
  barIncompleteChar: '▱',
19
28
  hideCursor: true
@@ -25,26 +34,35 @@ export function installWithProgress(dependencies, packageManager, projectRoot) {
25
34
  for (let i = 0; i < dependencies.length; i++) {
26
35
  const dep = dependencies[i]
27
36
 
28
- const installCommand = {
29
- pnpm: `pnpm add -D ${dep}`,
30
- yarn: `yarn add ${dep} --dev`,
31
- bun: `bun add -d ${dep}`,
32
- npm: `npm install ${dep} --save-dev`
33
- }[packageManager]
37
+ let installCommand
38
+ if (packageManager === 'pnpm' && isMonorepo) {
39
+ installCommand = `pnpm add -w -D ${dep}`
40
+ } else {
41
+ installCommand = {
42
+ pnpm: `pnpm add -D ${dep}`,
43
+ yarn: `yarn add ${dep} --dev`,
44
+ bun: `bun add -d ${dep}`,
45
+ npm: `npm install ${dep} --save-dev`
46
+ }[packageManager]
47
+ }
34
48
 
35
49
  bar.update(i, { dep })
36
50
 
37
- execSync(installCommand, { cwd: projectRoot, stdio: 'ignore' })
51
+ execSync(installCommand, { cwd: projectRoot, stdio: ['pipe', 'pipe', 'pipe'] })
38
52
 
39
53
  bar.update(i + 1, { dep })
40
54
  }
41
- bar.update(dependencies.length, { dep: chalk.green('✔️ 完成') })
55
+ bar.update(dependencies.length, { dep: chalk.green(' ') })
42
56
  bar.stop()
43
57
  console.log('')
44
58
  console.log('')
45
59
  } catch (err) {
46
60
  bar.stop()
47
- console.log(chalk.red('❌ 安装过程中出错'), err)
61
+ console.log(chalk.red('❌ 安装过程中出错'))
62
+ console.error('错误详情:', err.message)
63
+ console.error('错误堆栈:', err.stack)
64
+ if (err.stdout) console.error('标准输出:', err.stdout.toString())
65
+ if (err.stderr) console.error('错误输出:', err.stderr.toString())
48
66
  throw err
49
67
  }
50
68
  }