fe-build-cli 1.1.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 +430 -0
- package/package.json +41 -0
- package/src/cli.js +492 -0
- package/src/config-template.js +83 -0
- package/src/deploy-core.js +326 -0
- package/src/dingtalk.js +238 -0
- package/src/git-branch.js +259 -0
- package/src/index.d.ts +330 -0
- package/src/index.js +47 -0
- package/src/ssh-client.js +153 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Git 分支管理模块
|
|
5
|
+
* 支持当前分支发布和主分支发布两种模式
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 获取当前 Git 分支名称
|
|
10
|
+
* @returns {string} 当前分支名
|
|
11
|
+
*/
|
|
12
|
+
export function getCurrentBranch() {
|
|
13
|
+
try {
|
|
14
|
+
return execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' }).trim();
|
|
15
|
+
} catch (error) {
|
|
16
|
+
console.error('❌ 获取当前分支失败:', error.message);
|
|
17
|
+
throw new Error('无法获取当前分支,请确保在 Git 仓库中执行');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 获取 Git 提交 SHA(短格式)
|
|
23
|
+
* @returns {string} 短 SHA
|
|
24
|
+
*/
|
|
25
|
+
export function getGitSha() {
|
|
26
|
+
try {
|
|
27
|
+
return execSync('git rev-parse --short HEAD', { encoding: 'utf-8' }).trim();
|
|
28
|
+
} catch (error) {
|
|
29
|
+
return 'local';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 检查工作区是否干净
|
|
35
|
+
* @returns {boolean} 是否干净
|
|
36
|
+
*/
|
|
37
|
+
export function isWorkingTreeClean() {
|
|
38
|
+
try {
|
|
39
|
+
const status = execSync('git status --porcelain', { encoding: 'utf-8' }).trim();
|
|
40
|
+
return status === '';
|
|
41
|
+
} catch (error) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 检查是否有未提交的更改
|
|
48
|
+
* @returns {{ clean: boolean, changes: string[] }} 状态信息
|
|
49
|
+
*/
|
|
50
|
+
export function checkUncommittedChanges() {
|
|
51
|
+
try {
|
|
52
|
+
const status = execSync('git status --porcelain', { encoding: 'utf-8' }).trim();
|
|
53
|
+
if (status === '') {
|
|
54
|
+
return { clean: true, changes: [] };
|
|
55
|
+
}
|
|
56
|
+
const changes = status.split('\n').filter(line => line.trim());
|
|
57
|
+
return { clean: false, changes };
|
|
58
|
+
} catch (error) {
|
|
59
|
+
return { clean: false, changes: [error.message] };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 切换到指定分支
|
|
65
|
+
* @param {string} branchName - 分支名
|
|
66
|
+
*/
|
|
67
|
+
export function checkoutBranch(branchName) {
|
|
68
|
+
try {
|
|
69
|
+
console.log(`\n📌 切换到分支: ${branchName}`);
|
|
70
|
+
execSync(`git checkout ${branchName}`, { stdio: 'inherit' });
|
|
71
|
+
console.log(`✅ 已切换到 ${branchName}`);
|
|
72
|
+
} catch (error) {
|
|
73
|
+
throw new Error(`切换到分支 ${branchName} 失败: ${error.message}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 拉取远程分支最新代码
|
|
79
|
+
* @param {string} branchName - 分支名
|
|
80
|
+
*/
|
|
81
|
+
export function pullBranch(branchName) {
|
|
82
|
+
try {
|
|
83
|
+
console.log(`\n📥 拉取 ${branchName} 最新代码...`);
|
|
84
|
+
execSync(`git pull origin ${branchName}`, { stdio: 'inherit' });
|
|
85
|
+
console.log(`✅ ${branchName} 已更新`);
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.warn(`⚠️ 拉取 ${branchName} 失败,继续执行...`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 合并分支
|
|
93
|
+
* @param {string} sourceBranch - 源分支
|
|
94
|
+
* @param {string} targetBranch - 目标分支(当前所在分支)
|
|
95
|
+
* @returns {boolean} 是否成功
|
|
96
|
+
*/
|
|
97
|
+
export function mergeBranch(sourceBranch, targetBranch) {
|
|
98
|
+
try {
|
|
99
|
+
console.log(`\n🔀 合并 ${sourceBranch} 到 ${targetBranch}...`);
|
|
100
|
+
execSync(`git merge ${sourceBranch} --no-edit`, { stdio: 'inherit' });
|
|
101
|
+
console.log(`✅ 合并成功`);
|
|
102
|
+
return true;
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error(`❌ 合并失败: ${error.message}`);
|
|
105
|
+
// 尝试中止合并
|
|
106
|
+
try {
|
|
107
|
+
execSync('git merge --abort', { stdio: 'inherit' });
|
|
108
|
+
console.log('已中止合并');
|
|
109
|
+
} catch (e) {
|
|
110
|
+
// 忽略
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* 推送分支到远程
|
|
118
|
+
* @param {string} branchName - 分支名
|
|
119
|
+
*/
|
|
120
|
+
export function pushBranch(branchName) {
|
|
121
|
+
try {
|
|
122
|
+
console.log(`\n📤 推送 ${branchName} 到远程...`);
|
|
123
|
+
execSync(`git push origin ${branchName}`, { stdio: 'inherit' });
|
|
124
|
+
console.log(`✅ 推送成功`);
|
|
125
|
+
} catch (error) {
|
|
126
|
+
throw new Error(`推送 ${branchName} 失败: ${error.message}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* 执行主分支发布流程
|
|
132
|
+
* 流程:当前分支 -> 测试分支 -> 主分支
|
|
133
|
+
* @param {object} config - 分支配置
|
|
134
|
+
* @param {string} config.testBranch - 测试分支名
|
|
135
|
+
* @param {string} config.mainBranch - 主分支名
|
|
136
|
+
* @param {boolean} config.pushToRemote - 是否推送到远程
|
|
137
|
+
* @returns {object} 执行结果
|
|
138
|
+
*/
|
|
139
|
+
export function executeMainBranchFlow(config) {
|
|
140
|
+
const { testBranch, mainBranch, pushToRemote = true } = config;
|
|
141
|
+
const originalBranch = getCurrentBranch();
|
|
142
|
+
|
|
143
|
+
console.log('\n========================================');
|
|
144
|
+
console.log(' 🌿 主分支发布流程');
|
|
145
|
+
console.log('========================================');
|
|
146
|
+
console.log(`当前分支: ${originalBranch}`);
|
|
147
|
+
console.log(`测试分支: ${testBranch}`);
|
|
148
|
+
console.log(`主分支: ${mainBranch}`);
|
|
149
|
+
console.log('========================================');
|
|
150
|
+
|
|
151
|
+
// 检查工作区状态
|
|
152
|
+
const { clean, changes } = checkUncommittedChanges();
|
|
153
|
+
if (!clean) {
|
|
154
|
+
console.error('❌ 工作区有未提交的更改:');
|
|
155
|
+
changes.forEach(change => console.log(` ${change}`));
|
|
156
|
+
throw new Error('请先提交或暂存更改后再执行发布');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
// 步骤1: 切换到测试分支并拉取最新代码
|
|
161
|
+
checkoutBranch(testBranch);
|
|
162
|
+
pullBranch(testBranch);
|
|
163
|
+
|
|
164
|
+
// 步骤2: 合并当前分支到测试分支
|
|
165
|
+
if (!mergeBranch(originalBranch, testBranch)) {
|
|
166
|
+
throw new Error(`合并 ${originalBranch} 到 ${testBranch} 失败`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// 步骤3: 推送测试分支(可选)
|
|
170
|
+
if (pushToRemote) {
|
|
171
|
+
pushBranch(testBranch);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// 步骤4: 切换到主分支并拉取最新代码
|
|
175
|
+
checkoutBranch(mainBranch);
|
|
176
|
+
pullBranch(mainBranch);
|
|
177
|
+
|
|
178
|
+
// 步骤5: 合并测试分支到主分支
|
|
179
|
+
if (!mergeBranch(testBranch, mainBranch)) {
|
|
180
|
+
throw new Error(`合并 ${testBranch} 到 ${mainBranch} 失败`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// 步骤6: 推送主分支(可选)
|
|
184
|
+
if (pushToRemote) {
|
|
185
|
+
pushBranch(mainBranch);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
console.log('\n========================================');
|
|
189
|
+
console.log('✅ 主分支发布流程完成');
|
|
190
|
+
console.log(`当前分支: ${mainBranch}`);
|
|
191
|
+
console.log('========================================');
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
success: true,
|
|
195
|
+
originalBranch,
|
|
196
|
+
currentBranch: mainBranch,
|
|
197
|
+
testBranch,
|
|
198
|
+
mainBranch
|
|
199
|
+
};
|
|
200
|
+
} catch (error) {
|
|
201
|
+
// 出错时尝试切回原分支
|
|
202
|
+
try {
|
|
203
|
+
checkoutBranch(originalBranch);
|
|
204
|
+
} catch (e) {
|
|
205
|
+
// 忽略
|
|
206
|
+
}
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* 执行当前分支发布流程
|
|
213
|
+
* 不切换分支,直接在当前分支发布
|
|
214
|
+
* @returns {object} 执行结果
|
|
215
|
+
*/
|
|
216
|
+
export function executeCurrentBranchFlow() {
|
|
217
|
+
const currentBranch = getCurrentBranch();
|
|
218
|
+
const gitSha = getGitSha();
|
|
219
|
+
|
|
220
|
+
console.log('\n========================================');
|
|
221
|
+
console.log(' 🌿 当前分支发布模式');
|
|
222
|
+
console.log('========================================');
|
|
223
|
+
console.log(`当前分支: ${currentBranch}`);
|
|
224
|
+
console.log(`提交 SHA: ${gitSha}`);
|
|
225
|
+
console.log('========================================');
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
success: true,
|
|
229
|
+
originalBranch: currentBranch,
|
|
230
|
+
currentBranch,
|
|
231
|
+
gitSha
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* 发布后切回原分支
|
|
237
|
+
* @param {string} originalBranch - 原分支名
|
|
238
|
+
*/
|
|
239
|
+
export function restoreBranch(originalBranch) {
|
|
240
|
+
const currentBranch = getCurrentBranch();
|
|
241
|
+
if (currentBranch !== originalBranch) {
|
|
242
|
+
console.log(`\n📌 切回原分支: ${originalBranch}`);
|
|
243
|
+
checkoutBranch(originalBranch);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export default {
|
|
248
|
+
getCurrentBranch,
|
|
249
|
+
getGitSha,
|
|
250
|
+
isWorkingTreeClean,
|
|
251
|
+
checkUncommittedChanges,
|
|
252
|
+
checkoutBranch,
|
|
253
|
+
pullBranch,
|
|
254
|
+
mergeBranch,
|
|
255
|
+
pushBranch,
|
|
256
|
+
executeMainBranchFlow,
|
|
257
|
+
executeCurrentBranchFlow,
|
|
258
|
+
restoreBranch
|
|
259
|
+
};
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fe-build-cli 类型定义
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 服务器配置
|
|
7
|
+
*/
|
|
8
|
+
export interface ServerConfig {
|
|
9
|
+
/** SSH 服务器地址 */
|
|
10
|
+
sshHost: string;
|
|
11
|
+
/** SSH 用户名 */
|
|
12
|
+
sshUser: string;
|
|
13
|
+
/** SSH 私钥路径 */
|
|
14
|
+
sshKeyPath: string;
|
|
15
|
+
/** SSH 端口(默认 22) */
|
|
16
|
+
sshPort?: number;
|
|
17
|
+
/** 部署后的访问地址 */
|
|
18
|
+
deployUrl: string;
|
|
19
|
+
/** 备份目录 */
|
|
20
|
+
backupDir: string;
|
|
21
|
+
/** 部署目录 */
|
|
22
|
+
deployDir: string;
|
|
23
|
+
/** 备份文件前缀 */
|
|
24
|
+
backupPrefix: string;
|
|
25
|
+
/** 构建模式:production 或 test */
|
|
26
|
+
buildMode?: 'production' | 'test';
|
|
27
|
+
/** 自定义构建命令 */
|
|
28
|
+
buildCommand?: string;
|
|
29
|
+
/** 需要保护的目录(部署时不会被删除) */
|
|
30
|
+
protectedDirs?: string[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 分支配置
|
|
35
|
+
*/
|
|
36
|
+
export interface BranchesConfig {
|
|
37
|
+
/** 测试分支名 */
|
|
38
|
+
test: string;
|
|
39
|
+
/** 主分支名 */
|
|
40
|
+
main: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 钉钉通知配置
|
|
45
|
+
*/
|
|
46
|
+
export interface DingtalkConfig {
|
|
47
|
+
/** 钉钉机器人 webhook URL */
|
|
48
|
+
webhook: string;
|
|
49
|
+
/** 是否启用钉钉通知,默认 true */
|
|
50
|
+
enabled?: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* fe-build-cli 配置
|
|
55
|
+
*/
|
|
56
|
+
export interface FeBuildConfig {
|
|
57
|
+
/** 分支配置 */
|
|
58
|
+
branches?: BranchesConfig;
|
|
59
|
+
/** 发布模式:main(主分支发布)或 current(当前分支发布) */
|
|
60
|
+
deployMode?: 'main' | 'current';
|
|
61
|
+
/** 钉钉通知配置 */
|
|
62
|
+
dingtalk?: DingtalkConfig;
|
|
63
|
+
/** 服务器配置 */
|
|
64
|
+
servers: Record<string, ServerConfig>;
|
|
65
|
+
/** 备份保留数量 */
|
|
66
|
+
backupRetentionCount?: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 部署选项
|
|
71
|
+
*/
|
|
72
|
+
export interface DeployOptions {
|
|
73
|
+
/** 环境名称 */
|
|
74
|
+
environment: string;
|
|
75
|
+
/** 环境配置 */
|
|
76
|
+
envConfig: ServerConfig;
|
|
77
|
+
/** 构建版本 */
|
|
78
|
+
buildVersion: string;
|
|
79
|
+
/** 是否跳过构建 */
|
|
80
|
+
skipBuild?: boolean;
|
|
81
|
+
/** 是否跳过本地清理 */
|
|
82
|
+
skipLocalCleanup?: boolean;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 回滚选项
|
|
87
|
+
*/
|
|
88
|
+
export interface RollbackOptions {
|
|
89
|
+
/** 环境名称 */
|
|
90
|
+
environment: string;
|
|
91
|
+
/** 环境配置 */
|
|
92
|
+
envConfig: ServerConfig;
|
|
93
|
+
/** 指定版本(可选) */
|
|
94
|
+
specifiedVersion?: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* 主分支发布流程选项
|
|
99
|
+
*/
|
|
100
|
+
export interface MainBranchFlowOptions {
|
|
101
|
+
/** 测试分支名 */
|
|
102
|
+
testBranch: string;
|
|
103
|
+
/** 主分支名 */
|
|
104
|
+
mainBranch: string;
|
|
105
|
+
/** 是否推送到远程 */
|
|
106
|
+
pushToRemote?: boolean;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 分支流程执行结果
|
|
111
|
+
*/
|
|
112
|
+
export interface BranchFlowResult {
|
|
113
|
+
/** 是否成功 */
|
|
114
|
+
success: boolean;
|
|
115
|
+
/** 原始分支 */
|
|
116
|
+
originalBranch: string;
|
|
117
|
+
/** 当前分支 */
|
|
118
|
+
currentBranch: string;
|
|
119
|
+
/** 测试分支(主分支模式) */
|
|
120
|
+
testBranch?: string;
|
|
121
|
+
/** 主分支(主分支模式) */
|
|
122
|
+
mainBranch?: string;
|
|
123
|
+
/** Git SHA(当前分支模式) */
|
|
124
|
+
gitSha?: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* SSH 客户端类
|
|
129
|
+
*/
|
|
130
|
+
export class SSHClient {
|
|
131
|
+
constructor(config: ServerConfig);
|
|
132
|
+
connect(): Promise<void>;
|
|
133
|
+
execCommand(command: string): Promise<string>;
|
|
134
|
+
uploadFile(localPath: string, remotePath: string): Promise<void>;
|
|
135
|
+
disconnect(): Promise<void>;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* 部署函数
|
|
140
|
+
*/
|
|
141
|
+
export function deployToServer(options: DeployOptions): Promise<void>;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* 回滚函数
|
|
145
|
+
*/
|
|
146
|
+
export function rollbackDeployment(options: RollbackOptions): Promise<void>;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* 构建项目
|
|
150
|
+
*/
|
|
151
|
+
export function buildProject(envConfig: ServerConfig, buildVersion: string): void;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* 验证构建输出
|
|
155
|
+
*/
|
|
156
|
+
export function verifyBuildOutput(skipBuild: boolean): void;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* 压缩构建产物
|
|
160
|
+
*/
|
|
161
|
+
export function compressBuild(localZipFile: string, skipBuild: boolean): void;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* 备份现有部署
|
|
165
|
+
*/
|
|
166
|
+
export function backupExistingDeployment(options: {
|
|
167
|
+
ssh: SSHClient;
|
|
168
|
+
envConfig: ServerConfig;
|
|
169
|
+
buildVersion: string;
|
|
170
|
+
skipBuild: boolean;
|
|
171
|
+
}): Promise<void>;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* 上传构建产物
|
|
175
|
+
*/
|
|
176
|
+
export function uploadBuild(
|
|
177
|
+
ssh: SSHClient,
|
|
178
|
+
localZipFile: string,
|
|
179
|
+
remoteZipFile: string,
|
|
180
|
+
skipBuild: boolean
|
|
181
|
+
): Promise<void>;
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* 清理部署目录并解压新版本
|
|
185
|
+
*/
|
|
186
|
+
export function deployAndExtract(options: {
|
|
187
|
+
ssh: SSHClient;
|
|
188
|
+
envConfig: ServerConfig;
|
|
189
|
+
remoteZipFile: string;
|
|
190
|
+
skipBuild: boolean;
|
|
191
|
+
}): Promise<void>;
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* 清理临时文件
|
|
195
|
+
*/
|
|
196
|
+
export function cleanupFiles(options: {
|
|
197
|
+
ssh: SSHClient;
|
|
198
|
+
remoteZipFile: string;
|
|
199
|
+
localZipFile: string;
|
|
200
|
+
skipLocalCleanup: boolean;
|
|
201
|
+
skipBuild: boolean;
|
|
202
|
+
}): Promise<void>;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* 获取当前 Git 分支名称
|
|
206
|
+
*/
|
|
207
|
+
export function getCurrentBranch(): string;
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* 获取 Git 提交 SHA(短格式)
|
|
211
|
+
*/
|
|
212
|
+
export function getGitSha(): string;
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* 检查工作区是否干净
|
|
216
|
+
*/
|
|
217
|
+
export function isWorkingTreeClean(): boolean;
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* 检查是否有未提交的更改
|
|
221
|
+
*/
|
|
222
|
+
export function checkUncommittedChanges(): { clean: boolean; changes: string[] };
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* 切换到指定分支
|
|
226
|
+
*/
|
|
227
|
+
export function checkoutBranch(branchName: string): void;
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* 拉取远程分支最新代码
|
|
231
|
+
*/
|
|
232
|
+
export function pullBranch(branchName: string): void;
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* 合并分支
|
|
236
|
+
*/
|
|
237
|
+
export function mergeBranch(sourceBranch: string, targetBranch: string): boolean;
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* 推送分支到远程
|
|
241
|
+
*/
|
|
242
|
+
export function pushBranch(branchName: string): void;
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* 执行主分支发布流程
|
|
246
|
+
*/
|
|
247
|
+
export function executeMainBranchFlow(config: MainBranchFlowOptions): BranchFlowResult;
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* 执行当前分支发布流程
|
|
251
|
+
*/
|
|
252
|
+
export function executeCurrentBranchFlow(): BranchFlowResult;
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* 发布后切回原分支
|
|
256
|
+
*/
|
|
257
|
+
export function restoreBranch(originalBranch: string): void;
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* 钉钉通知结果
|
|
261
|
+
*/
|
|
262
|
+
export interface DingtalkResult {
|
|
263
|
+
success: boolean;
|
|
264
|
+
data?: any;
|
|
265
|
+
error?: string;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* 部署成功通知选项
|
|
270
|
+
*/
|
|
271
|
+
export interface DeploySuccessNotificationOptions {
|
|
272
|
+
environment: string;
|
|
273
|
+
buildVersion: string;
|
|
274
|
+
serverHost: string;
|
|
275
|
+
deployUrl: string;
|
|
276
|
+
branch: string;
|
|
277
|
+
deployMode: string;
|
|
278
|
+
duration?: string;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* 部署失败通知选项
|
|
283
|
+
*/
|
|
284
|
+
export interface DeployFailureNotificationOptions {
|
|
285
|
+
environment: string;
|
|
286
|
+
buildVersion?: string;
|
|
287
|
+
serverHost: string;
|
|
288
|
+
branch: string;
|
|
289
|
+
error: string;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* 回滚通知选项
|
|
294
|
+
*/
|
|
295
|
+
export interface RollbackNotificationOptions {
|
|
296
|
+
environment: string;
|
|
297
|
+
backupFile: string;
|
|
298
|
+
serverHost: string;
|
|
299
|
+
deployUrl: string;
|
|
300
|
+
success: boolean;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* 发送钉钉消息
|
|
305
|
+
*/
|
|
306
|
+
export function sendDingTalkMessage(webhookUrl: string, message: any): Promise<DingtalkResult>;
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* 发送部署成功通知
|
|
310
|
+
*/
|
|
311
|
+
export function sendDeploySuccessNotification(
|
|
312
|
+
webhookUrl: string,
|
|
313
|
+
options: DeploySuccessNotificationOptions
|
|
314
|
+
): Promise<DingtalkResult>;
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* 发送部署失败通知
|
|
318
|
+
*/
|
|
319
|
+
export function sendDeployFailureNotification(
|
|
320
|
+
webhookUrl: string,
|
|
321
|
+
options: DeployFailureNotificationOptions
|
|
322
|
+
): Promise<DingtalkResult>;
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* 发送回滚通知
|
|
326
|
+
*/
|
|
327
|
+
export function sendRollbackNotification(
|
|
328
|
+
webhookUrl: string,
|
|
329
|
+
options: RollbackNotificationOptions
|
|
330
|
+
): Promise<DingtalkResult>;
|
package/src/index.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fe-build-cli - 前端项目打包部署工具
|
|
3
|
+
*
|
|
4
|
+
* 导出所有模块供外部使用
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// SSH 客户端
|
|
8
|
+
export { SSHClient } from './ssh-client.js';
|
|
9
|
+
|
|
10
|
+
// Git 分支管理
|
|
11
|
+
export {
|
|
12
|
+
getCurrentBranch,
|
|
13
|
+
getGitSha,
|
|
14
|
+
isWorkingTreeClean,
|
|
15
|
+
checkUncommittedChanges,
|
|
16
|
+
checkoutBranch,
|
|
17
|
+
pullBranch,
|
|
18
|
+
mergeBranch,
|
|
19
|
+
pushBranch,
|
|
20
|
+
executeMainBranchFlow,
|
|
21
|
+
executeCurrentBranchFlow,
|
|
22
|
+
restoreBranch
|
|
23
|
+
} from './git-branch.js';
|
|
24
|
+
|
|
25
|
+
// 部署核心逻辑
|
|
26
|
+
export {
|
|
27
|
+
buildProject,
|
|
28
|
+
verifyBuildOutput,
|
|
29
|
+
compressBuild,
|
|
30
|
+
backupExistingDeployment,
|
|
31
|
+
uploadBuild,
|
|
32
|
+
deployAndExtract,
|
|
33
|
+
cleanupFiles,
|
|
34
|
+
deployToServer,
|
|
35
|
+
rollbackDeployment
|
|
36
|
+
} from './deploy-core.js';
|
|
37
|
+
|
|
38
|
+
// 钉钉通知
|
|
39
|
+
export {
|
|
40
|
+
sendDingTalkMessage,
|
|
41
|
+
sendDeploySuccessNotification,
|
|
42
|
+
sendDeployFailureNotification,
|
|
43
|
+
sendRollbackNotification
|
|
44
|
+
} from './dingtalk.js';
|
|
45
|
+
|
|
46
|
+
// 配置模板
|
|
47
|
+
export { default as configTemplate } from './config-template.js';
|