fe-build-cli 1.2.4 → 1.5.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 +248 -11
- package/package.json +1 -1
- package/src/cli.js +197 -26
- package/src/config-template.js +14 -1
- package/src/deploy-core.js +310 -64
- package/src/dingtalk.js +31 -17
- package/src/git-branch.js +191 -34
- package/src/index.js +13 -1
- package/src/logger.js +381 -0
- package/src/ssh-client.js +69 -0
package/src/cli.js
CHANGED
|
@@ -5,10 +5,12 @@ import { execSync } from 'node:child_process';
|
|
|
5
5
|
import fs from 'node:fs';
|
|
6
6
|
import path from 'node:path';
|
|
7
7
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
8
|
-
import { deployToServer, rollbackDeployment } from './deploy-core.js';
|
|
8
|
+
import { deployToServer, rollbackDeployment, getServerBackupList, getLocalBackupList, rollbackFromLocal } from './deploy-core.js';
|
|
9
|
+
import SSHClient from './ssh-client.js';
|
|
9
10
|
import {
|
|
10
11
|
getCurrentBranch,
|
|
11
12
|
getGitSha,
|
|
13
|
+
getGitCommitMessage,
|
|
12
14
|
executeMainBranchFlow,
|
|
13
15
|
executeCurrentBranchFlow,
|
|
14
16
|
executeTestBranchFlow,
|
|
@@ -20,6 +22,7 @@ import {
|
|
|
20
22
|
sendDeployFailureNotification,
|
|
21
23
|
sendRollbackNotification
|
|
22
24
|
} from './dingtalk.js';
|
|
25
|
+
import { DeployLogger } from './logger.js';
|
|
23
26
|
|
|
24
27
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
25
28
|
|
|
@@ -164,7 +167,7 @@ fe-build-cli - 前端项目打包部署工具
|
|
|
164
167
|
|
|
165
168
|
命令:
|
|
166
169
|
deploy [环境] 部署到指定环境(默认命令)
|
|
167
|
-
rollback [环境]
|
|
170
|
+
rollback [环境] 回滚到指定版本(交互选择备份来源)
|
|
168
171
|
help 显示帮助信息
|
|
169
172
|
|
|
170
173
|
选项:
|
|
@@ -176,6 +179,9 @@ fe-build-cli - 前端项目打包部署工具
|
|
|
176
179
|
--no-merge test 发布时不合并,使用 stash 储藏本地改动
|
|
177
180
|
--skip-build 跳过构建步骤
|
|
178
181
|
--no-push 发布时不推送到远程
|
|
182
|
+
--server 回滚时使用服务器备份(默认)
|
|
183
|
+
--local 回滚时使用本地备份
|
|
184
|
+
--version <版本号> 回滚到指定版本
|
|
179
185
|
|
|
180
186
|
示例:
|
|
181
187
|
fe-build # 交互式选择环境部署
|
|
@@ -186,7 +192,9 @@ fe-build-cli - 前端项目打包部署工具
|
|
|
186
192
|
fe-build --test-branch --no-merge # test 发布,stash 储藏改动
|
|
187
193
|
fe-build --current-branch # 当前分支发布
|
|
188
194
|
fe-build --main-branch # 主分支发布流程
|
|
189
|
-
fe-build rollback production
|
|
195
|
+
fe-build rollback production # 回滚生产环境(交互选择)
|
|
196
|
+
fe-build rollback production --server # 回滚生产环境(服务器备份)
|
|
197
|
+
fe-build rollback production --local # 回滚生产环境(本地备份)
|
|
190
198
|
|
|
191
199
|
配置文件 (fe-build.config.js):
|
|
192
200
|
export default {
|
|
@@ -268,20 +276,23 @@ async function deployCommand(config) {
|
|
|
268
276
|
}
|
|
269
277
|
}
|
|
270
278
|
|
|
271
|
-
//
|
|
272
|
-
|
|
279
|
+
// 确定发布模式
|
|
280
|
+
// 优先级:命令行参数 > 配置文件 deployMode > 自动识别
|
|
281
|
+
let deployMode = 'main'; // 默认值
|
|
273
282
|
|
|
274
|
-
// 命令行参数优先
|
|
283
|
+
// 1. 命令行参数优先
|
|
275
284
|
if (useTestBranch) {
|
|
276
285
|
deployMode = 'test';
|
|
277
286
|
} else if (useCurrentBranch) {
|
|
278
287
|
deployMode = 'current';
|
|
279
288
|
} else if (useMainBranch) {
|
|
280
289
|
deployMode = 'main';
|
|
290
|
+
} else if (config.deployMode) {
|
|
291
|
+
// 2. 使用配置文件的 deployMode
|
|
292
|
+
deployMode = config.deployMode;
|
|
293
|
+
console.log(`\n📌 使用配置文件发布模式: ${deployMode}`);
|
|
281
294
|
} else {
|
|
282
|
-
//
|
|
283
|
-
// test 环境 → test 发布模式
|
|
284
|
-
// production 环境 → main 发布模式
|
|
295
|
+
// 3. 自动根据部署环境选择发布模式(仅当配置文件未设置时)
|
|
285
296
|
const targetEnv = selectedServers[0];
|
|
286
297
|
if (targetEnv === 'test') {
|
|
287
298
|
deployMode = 'test';
|
|
@@ -292,6 +303,12 @@ async function deployCommand(config) {
|
|
|
292
303
|
}
|
|
293
304
|
}
|
|
294
305
|
|
|
306
|
+
// 创建日志记录器(在分支操作之前)
|
|
307
|
+
const logDir = config.logDir || 'logs';
|
|
308
|
+
const localBackupDir = config.localBackupDir || 'D:\\备份';
|
|
309
|
+
const logger = new DeployLogger({ logDir, localBackupDir });
|
|
310
|
+
logger.start();
|
|
311
|
+
|
|
295
312
|
// 执行分支发布流程
|
|
296
313
|
let branchResult = null;
|
|
297
314
|
let originalBranch = getCurrentBranch(); // 记录原始分支
|
|
@@ -317,7 +334,8 @@ async function deployCommand(config) {
|
|
|
317
334
|
testBranch: branches.test,
|
|
318
335
|
mergeChanges,
|
|
319
336
|
pushToRemote: !noPush,
|
|
320
|
-
prompt
|
|
337
|
+
prompt,
|
|
338
|
+
logger // 传递 logger
|
|
321
339
|
});
|
|
322
340
|
originalBranch = branchResult.originalBranch;
|
|
323
341
|
needRestore = branchResult.needRestore;
|
|
@@ -336,19 +354,21 @@ async function deployCommand(config) {
|
|
|
336
354
|
const confirmAnswer = await prompt('确认执行主分支发布流程? (y/n): ');
|
|
337
355
|
if (confirmAnswer.toLowerCase() !== 'y') {
|
|
338
356
|
console.log('已取消发布');
|
|
357
|
+
logger.end('cancelled');
|
|
339
358
|
process.exit(0);
|
|
340
359
|
}
|
|
341
360
|
|
|
342
361
|
branchResult = executeMainBranchFlow({
|
|
343
362
|
testBranch: branches.test,
|
|
344
363
|
mainBranch: branches.main,
|
|
345
|
-
pushToRemote: !noPush
|
|
364
|
+
pushToRemote: !noPush,
|
|
365
|
+
logger // 传递 logger
|
|
346
366
|
});
|
|
347
367
|
originalBranch = branchResult.originalBranch;
|
|
348
368
|
needRestore = true;
|
|
349
369
|
} else if (deployMode === 'current') {
|
|
350
370
|
// 当前分支发布模式
|
|
351
|
-
branchResult = executeCurrentBranchFlow();
|
|
371
|
+
branchResult = executeCurrentBranchFlow(logger);
|
|
352
372
|
originalBranch = branchResult.currentBranch;
|
|
353
373
|
needRestore = false;
|
|
354
374
|
console.log('📌 当前分支发布模式:不切换分支');
|
|
@@ -356,7 +376,10 @@ async function deployCommand(config) {
|
|
|
356
376
|
} catch (branchError) {
|
|
357
377
|
// 分支流程失败,发送钉钉通知
|
|
358
378
|
console.error(`❌ 分支流程失败:`, branchError.message);
|
|
379
|
+
logger.log('ERROR', '分支流程失败', branchError.message);
|
|
380
|
+
logger.end('failed');
|
|
359
381
|
|
|
382
|
+
const commitMessage = getGitCommitMessage();
|
|
360
383
|
if (config.dingtalk && config.dingtalk.enabled && config.dingtalk.webhook) {
|
|
361
384
|
console.log('\n发送钉钉失败通知...');
|
|
362
385
|
const envConfig = getServerConfig(config, selectedServers[0] || serverNames[0]);
|
|
@@ -365,13 +388,14 @@ async function deployCommand(config) {
|
|
|
365
388
|
buildVersion: '未完成',
|
|
366
389
|
serverHost: envConfig?.sshHost || '未知',
|
|
367
390
|
branch: originalBranch,
|
|
391
|
+
commitMessage,
|
|
368
392
|
error: `分支流程失败: ${branchError.message}`,
|
|
369
393
|
keyword: config.dingtalk.keyword || '部署'
|
|
370
394
|
});
|
|
371
395
|
}
|
|
372
396
|
|
|
373
397
|
// 切回原分支
|
|
374
|
-
restoreBranch(originalBranch, hasStash);
|
|
398
|
+
restoreBranch(originalBranch, hasStash, logger);
|
|
375
399
|
process.exit(1);
|
|
376
400
|
}
|
|
377
401
|
|
|
@@ -401,18 +425,25 @@ async function deployCommand(config) {
|
|
|
401
425
|
}
|
|
402
426
|
console.log('========================================');
|
|
403
427
|
|
|
428
|
+
// 部署到服务器(使用前面创建的 logger)
|
|
404
429
|
try {
|
|
405
430
|
await deployToServer({
|
|
406
431
|
environment: serverName,
|
|
407
432
|
envConfig,
|
|
408
433
|
buildVersion,
|
|
409
434
|
skipBuild: skipBuild || !isFirst,
|
|
410
|
-
skipLocalCleanup: i < selectedServers.length - 1
|
|
435
|
+
skipLocalCleanup: i < selectedServers.length - 1,
|
|
436
|
+
logger,
|
|
437
|
+
localBackupDir
|
|
411
438
|
});
|
|
412
439
|
|
|
440
|
+
// 部署成功,结束日志记录
|
|
441
|
+
logger.end('success');
|
|
442
|
+
|
|
413
443
|
// 部署成功,发送钉钉通知
|
|
414
444
|
const duration = Math.round((Date.now() - startTime) / 1000);
|
|
415
445
|
const currentBranch = getCurrentBranch();
|
|
446
|
+
const commitMessage = getGitCommitMessage();
|
|
416
447
|
|
|
417
448
|
if (config.dingtalk && config.dingtalk.enabled && config.dingtalk.webhook) {
|
|
418
449
|
console.log('\n发送钉钉通知...');
|
|
@@ -423,15 +454,21 @@ async function deployCommand(config) {
|
|
|
423
454
|
deployUrl: envConfig.deployUrl,
|
|
424
455
|
branch: currentBranch,
|
|
425
456
|
deployMode,
|
|
457
|
+
commitMessage,
|
|
426
458
|
duration: `${duration}秒`,
|
|
427
459
|
keyword: config.dingtalk.keyword || '部署'
|
|
428
460
|
});
|
|
461
|
+
logger.logDingTalk(true);
|
|
429
462
|
}
|
|
430
463
|
} catch (error) {
|
|
431
464
|
console.error(`❌ 部署到 ${serverName} 失败:`, error.message);
|
|
432
465
|
|
|
466
|
+
// 部署失败,结束日志记录
|
|
467
|
+
logger.end('failed');
|
|
468
|
+
|
|
433
469
|
// 部署失败,发送钉钉通知
|
|
434
470
|
const currentBranch = getCurrentBranch();
|
|
471
|
+
const commitMessage = getGitCommitMessage();
|
|
435
472
|
if (config.dingtalk && config.dingtalk.enabled && config.dingtalk.webhook) {
|
|
436
473
|
console.log('\n发送钉钉失败通知...');
|
|
437
474
|
await sendDeployFailureNotification(config.dingtalk.webhook, {
|
|
@@ -439,14 +476,16 @@ async function deployCommand(config) {
|
|
|
439
476
|
buildVersion,
|
|
440
477
|
serverHost: envConfig.sshHost,
|
|
441
478
|
branch: currentBranch,
|
|
479
|
+
commitMessage,
|
|
442
480
|
error: error.message,
|
|
443
481
|
keyword: config.dingtalk.keyword || '部署'
|
|
444
482
|
});
|
|
483
|
+
logger.logDingTalk(false, error.message);
|
|
445
484
|
}
|
|
446
485
|
|
|
447
486
|
// 出错时切回原分支
|
|
448
487
|
if (needRestore && originalBranch) {
|
|
449
|
-
restoreBranch(originalBranch, hasStash);
|
|
488
|
+
restoreBranch(originalBranch, hasStash, logger);
|
|
450
489
|
}
|
|
451
490
|
process.exit(1);
|
|
452
491
|
}
|
|
@@ -457,13 +496,13 @@ async function deployCommand(config) {
|
|
|
457
496
|
// 合并模式:自动切回原分支
|
|
458
497
|
if (autoRestore) {
|
|
459
498
|
console.log('\n📌 自动切回原分支...');
|
|
460
|
-
restoreBranch(originalBranch, false);
|
|
499
|
+
restoreBranch(originalBranch, false, logger);
|
|
461
500
|
console.log(`✅ 已切回 ${originalBranch},可继续开发`);
|
|
462
501
|
} else {
|
|
463
502
|
// stash 模式:询问是否切回
|
|
464
503
|
const returnAnswer = await prompt('\n是否切回原分支? (y/n): ');
|
|
465
504
|
if (returnAnswer.toLowerCase() === 'y') {
|
|
466
|
-
restoreBranch(originalBranch, hasStash);
|
|
505
|
+
restoreBranch(originalBranch, hasStash, logger);
|
|
467
506
|
} else if (hasStash) {
|
|
468
507
|
console.log('\n💡 提示: 本地改动已储藏,执行以下命令恢复:');
|
|
469
508
|
console.log(' git stash pop');
|
|
@@ -488,10 +527,12 @@ async function rollbackCommand(config) {
|
|
|
488
527
|
const environment = args.find(arg => arg !== 'rollback' && !arg.startsWith('--'));
|
|
489
528
|
const versionIndex = args.indexOf('--version');
|
|
490
529
|
const specifiedVersion = versionIndex !== -1 ? args[versionIndex + 1] : undefined;
|
|
530
|
+
const useLocalBackup = args.includes('--local'); // 是否使用本地备份
|
|
531
|
+
const useServerBackup = args.includes('--server'); // 是否使用服务器备份
|
|
491
532
|
|
|
492
533
|
if (!environment || !serverNames.includes(environment)) {
|
|
493
534
|
console.error(`❌ 请指定服务器: ${serverNames.join(' 或 ')}`);
|
|
494
|
-
console.error(`用法: fe-build rollback [${serverNames.join('|')}] [--version <版本号>]`);
|
|
535
|
+
console.error(`用法: fe-build rollback [${serverNames.join('|')}] [--server|--local] [--version <版本号>]`);
|
|
495
536
|
process.exit(1);
|
|
496
537
|
}
|
|
497
538
|
|
|
@@ -502,22 +543,134 @@ async function rollbackCommand(config) {
|
|
|
502
543
|
process.exit(1);
|
|
503
544
|
}
|
|
504
545
|
|
|
546
|
+
// 创建日志记录器
|
|
547
|
+
const logDir = config.logDir || 'logs';
|
|
548
|
+
const localBackupDir = config.localBackupDir || 'D:\\备份';
|
|
549
|
+
const logger = new DeployLogger({ logDir, localBackupDir });
|
|
550
|
+
logger.start();
|
|
551
|
+
|
|
552
|
+
console.log('========================================');
|
|
553
|
+
console.log(`开始回滚 ${environment} 环境`);
|
|
554
|
+
console.log(`服务器: ${envConfig.sshHost}`);
|
|
555
|
+
console.log('========================================');
|
|
556
|
+
|
|
557
|
+
// 连接服务器
|
|
558
|
+
const ssh = new SSHClient(envConfig);
|
|
559
|
+
await ssh.connect();
|
|
560
|
+
logger.logSSHConnect(envConfig.sshHost, true);
|
|
561
|
+
|
|
505
562
|
let backupFile = '';
|
|
506
|
-
let
|
|
563
|
+
let selectedBackup = null;
|
|
564
|
+
let backupSource = 'server'; // 默认服务器备份
|
|
507
565
|
|
|
508
566
|
try {
|
|
509
|
-
//
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
567
|
+
// 如果指定了版本号,直接使用
|
|
568
|
+
if (specifiedVersion) {
|
|
569
|
+
backupFile = `${envConfig.backupDir}/${envConfig.backupPrefix}-${specifiedVersion}.tar.gz`;
|
|
570
|
+
console.log(`\n使用指定版本: ${specifiedVersion}`);
|
|
571
|
+
logger.log('INFO', '回滚版本', `指定版本: ${specifiedVersion}`);
|
|
572
|
+
} else {
|
|
573
|
+
// 获取备份列表
|
|
574
|
+
let serverBackups = [];
|
|
575
|
+
let localBackups = [];
|
|
576
|
+
|
|
577
|
+
// 获取服务器备份列表
|
|
578
|
+
console.log('\n[步骤 1] 获取服务器备份列表...');
|
|
579
|
+
serverBackups = await getServerBackupList(ssh, envConfig);
|
|
580
|
+
console.log(`找到 ${serverBackups.length} 个服务器备份`);
|
|
581
|
+
|
|
582
|
+
// 获取本地备份列表
|
|
583
|
+
console.log('\n[步骤 2] 获取本地备份列表...');
|
|
584
|
+
localBackups = getLocalBackupList(localBackupDir, envConfig.backupPrefix);
|
|
585
|
+
console.log(`找到 ${localBackups.length} 个本地备份`);
|
|
586
|
+
|
|
587
|
+
// 如果没有备份
|
|
588
|
+
if (serverBackups.length === 0 && localBackups.length === 0) {
|
|
589
|
+
logger.log('ERROR', '获取备份', '未找到任何备份文件');
|
|
590
|
+
console.error('❌ 未找到任何备份文件!');
|
|
591
|
+
await ssh.disconnect();
|
|
592
|
+
logger.end('failed');
|
|
593
|
+
process.exit(1);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// 确定备份来源
|
|
597
|
+
if (useLocalBackup && localBackups.length > 0) {
|
|
598
|
+
backupSource = 'local';
|
|
599
|
+
} else if (useServerBackup && serverBackups.length > 0) {
|
|
600
|
+
backupSource = 'server';
|
|
601
|
+
} else if (!useLocalBackup && !useServerBackup) {
|
|
602
|
+
// 交互选择备份来源(默认服务器)
|
|
603
|
+
console.log('\n========================================');
|
|
604
|
+
console.log(' 📦 选择备份来源');
|
|
605
|
+
console.log('========================================');
|
|
606
|
+
console.log(` 1. 服务器备份 (${serverBackups.length} 个) - 默认`);
|
|
607
|
+
if (localBackups.length > 0) {
|
|
608
|
+
console.log(` 2. 本地备份 (${localBackups.length} 个)`);
|
|
609
|
+
}
|
|
610
|
+
console.log('========================================');
|
|
611
|
+
|
|
612
|
+
const sourceAnswer = await prompt(`请选择备份来源 (1${localBackups.length > 0 ? '/2' : ''}): `);
|
|
613
|
+
if (sourceAnswer === '2' && localBackups.length > 0) {
|
|
614
|
+
backupSource = 'local';
|
|
615
|
+
} else {
|
|
616
|
+
backupSource = 'server';
|
|
617
|
+
}
|
|
618
|
+
}
|
|
513
619
|
|
|
620
|
+
// 显示备份列表供选择
|
|
621
|
+
const backups = backupSource === 'server' ? serverBackups : localBackups;
|
|
622
|
+
|
|
623
|
+
console.log(`\n========================================`);
|
|
624
|
+
console.log(` 📦 ${backupSource === 'server' ? '服务器' : '本地'}备份列表`);
|
|
625
|
+
console.log(`========================================`);
|
|
626
|
+
|
|
627
|
+
backups.forEach((backup, index) => {
|
|
628
|
+
const sizeStr = backup.size ? ` (${formatFileSize(backup.size)})` : '';
|
|
629
|
+
const timeStr = backup.mtime ? ` - ${backup.mtime.toLocaleDateString('zh-CN')}` : '';
|
|
630
|
+
console.log(` ${index + 1}. ${backup.version}${sizeStr}${timeStr}`);
|
|
631
|
+
});
|
|
632
|
+
console.log(`========================================`);
|
|
633
|
+
|
|
634
|
+
const backupAnswer = await prompt(`请选择要回滚的备份 (1-${backups.length}): `);
|
|
635
|
+
const selectedIndex = parseInt(backupAnswer, 10) - 1;
|
|
636
|
+
|
|
637
|
+
if (selectedIndex < 0 || selectedIndex >= backups.length) {
|
|
638
|
+
console.error('❌ 无效选择');
|
|
639
|
+
await ssh.disconnect();
|
|
640
|
+
logger.end('failed');
|
|
641
|
+
process.exit(1);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
selectedBackup = backups[selectedIndex];
|
|
645
|
+
backupFile = selectedBackup.file;
|
|
646
|
+
|
|
647
|
+
console.log(`\n已选择: ${selectedBackup.version}`);
|
|
648
|
+
logger.log('INFO', '选择备份', `来源: ${backupSource}, 版本: ${selectedBackup.version}`);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// 如果是本地备份,需要先上传到服务器
|
|
652
|
+
if (backupSource === 'local' && selectedBackup) {
|
|
653
|
+
const remoteFile = await rollbackFromLocal({
|
|
654
|
+
ssh,
|
|
655
|
+
envConfig,
|
|
656
|
+
localBackupFile: backupFile,
|
|
657
|
+
logger
|
|
658
|
+
});
|
|
659
|
+
backupFile = remoteFile;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// 执行回滚
|
|
514
663
|
await rollbackDeployment({
|
|
515
664
|
environment,
|
|
516
665
|
envConfig,
|
|
517
|
-
specifiedVersion
|
|
666
|
+
specifiedVersion: specifiedVersion || (selectedBackup ? selectedBackup.version : undefined),
|
|
667
|
+
backupFile,
|
|
668
|
+
logger,
|
|
669
|
+
ssh // 传递已连接的 ssh
|
|
518
670
|
});
|
|
519
671
|
|
|
520
|
-
|
|
672
|
+
await ssh.disconnect();
|
|
673
|
+
logger.end('success');
|
|
521
674
|
|
|
522
675
|
// 回滚成功,发送钉钉通知
|
|
523
676
|
if (config.dingtalk && config.dingtalk.enabled && config.dingtalk.webhook) {
|
|
@@ -530,10 +683,18 @@ async function rollbackCommand(config) {
|
|
|
530
683
|
success: true,
|
|
531
684
|
keyword: config.dingtalk.keyword || '部署'
|
|
532
685
|
});
|
|
686
|
+
logger.logDingTalk(true);
|
|
533
687
|
}
|
|
534
688
|
} catch (error) {
|
|
535
689
|
console.error('❌ 回滚失败:', error.message);
|
|
536
|
-
|
|
690
|
+
logger.log('ERROR', '回滚失败', error.message);
|
|
691
|
+
logger.end('failed');
|
|
692
|
+
|
|
693
|
+
try {
|
|
694
|
+
await ssh.disconnect();
|
|
695
|
+
} catch (e) {
|
|
696
|
+
// 忽略
|
|
697
|
+
}
|
|
537
698
|
|
|
538
699
|
// 回滚失败,发送钉钉通知
|
|
539
700
|
if (config.dingtalk && config.dingtalk.enabled && config.dingtalk.webhook) {
|
|
@@ -546,12 +707,22 @@ async function rollbackCommand(config) {
|
|
|
546
707
|
success: false,
|
|
547
708
|
keyword: config.dingtalk.keyword || '部署'
|
|
548
709
|
});
|
|
710
|
+
logger.logDingTalk(false, error.message);
|
|
549
711
|
}
|
|
550
712
|
|
|
551
713
|
process.exit(1);
|
|
552
714
|
}
|
|
553
715
|
}
|
|
554
716
|
|
|
717
|
+
/**
|
|
718
|
+
* 格式化文件大小
|
|
719
|
+
*/
|
|
720
|
+
function formatFileSize(bytes) {
|
|
721
|
+
if (bytes < 1024) return bytes + ' B';
|
|
722
|
+
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
|
|
723
|
+
return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
|
|
724
|
+
}
|
|
725
|
+
|
|
555
726
|
/**
|
|
556
727
|
* 主入口
|
|
557
728
|
*/
|
package/src/config-template.js
CHANGED
|
@@ -80,5 +80,18 @@ export default {
|
|
|
80
80
|
webhook: 'https://oapi.dingtalk.com/robot/send?access_token=your-token', // 钉钉机器人 webhook URL
|
|
81
81
|
enabled: true, // 是否启用钉钉通知,默认 true
|
|
82
82
|
keyword: '部署' // 安全设置关键词(如果机器人设置了关键词,必须配置此项)
|
|
83
|
-
}
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 日志配置(可选)
|
|
87
|
+
* 部署日志存储目录,默认项目根目录下的 logs 目录
|
|
88
|
+
*/
|
|
89
|
+
logDir: 'logs',
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 本地备份目录(可选)
|
|
93
|
+
* 线上备份下载到本地的存储目录,默认 D:\备份
|
|
94
|
+
* 保留 7 天内的备份,自动清理旧备份
|
|
95
|
+
*/
|
|
96
|
+
localBackupDir: 'D:\\备份'
|
|
84
97
|
};
|