@ruan-cat/vercel-deploy-tool 0.12.2 → 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 +375 -75
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +578 -0
- package/dist/index.d.ts +247 -0
- package/dist/index.js +566 -0
- package/package.json +14 -6
- package/src/cli.ts +61 -0
- package/src/commands/deploy.ts +50 -0
- package/src/commands/init.ts +92 -0
- package/src/config/define-config.ts +20 -0
- package/src/config/loader.ts +95 -0
- package/src/config/schema.ts +108 -0
- package/src/core/executor.ts +50 -0
- package/src/core/tasks/after-build.ts +46 -0
- package/src/core/tasks/alias.ts +37 -0
- package/src/core/tasks/build.ts +50 -0
- package/src/core/tasks/copy-dist.ts +59 -0
- package/src/core/tasks/deploy.ts +54 -0
- package/src/core/tasks/index.ts +144 -0
- package/src/core/tasks/link.ts +49 -0
- package/src/core/tasks/user-commands.ts +31 -0
- package/src/core/vercel.ts +55 -0
- package/src/index.ts +68 -550
- package/src/templates/vercel-deploy-tool.config.ts +129 -0
- package/src/types/index.ts +14 -0
- package/src/utils/type-guards.ts +33 -0
- package/src/utils/vercel-null-config.ts +46 -0
- package/tsconfig.json +3 -1
package/src/index.ts
CHANGED
|
@@ -1,589 +1,107 @@
|
|
|
1
|
-
// 学习一下如何使用 https://github.com/sindresorhus/execa/blob/main/readme.md
|
|
2
|
-
import { dirname, resolve } from "node:path";
|
|
3
|
-
import { spawnSync } from "node:child_process";
|
|
4
|
-
import fs, {
|
|
5
|
-
// 文件是否存在
|
|
6
|
-
existsSync,
|
|
7
|
-
// 复制文件
|
|
8
|
-
copyFileSync,
|
|
9
|
-
// 复制目录
|
|
10
|
-
cpSync,
|
|
11
|
-
// 删除目录
|
|
12
|
-
rmSync,
|
|
13
|
-
// 新建文件夹
|
|
14
|
-
mkdir,
|
|
15
|
-
} from "node:fs";
|
|
16
|
-
|
|
17
|
-
import { concat, isEmpty, isUndefined } from "lodash-es";
|
|
18
|
-
import { consola } from "consola";
|
|
19
|
-
import gradient from "gradient-string";
|
|
20
|
-
|
|
21
|
-
import {
|
|
22
|
-
isConditionsEvery,
|
|
23
|
-
isConditionsSome,
|
|
24
|
-
generateSimpleAsyncTask,
|
|
25
|
-
definePromiseTasks,
|
|
26
|
-
executePromiseTasks,
|
|
27
|
-
} from "@ruan-cat/utils";
|
|
28
|
-
import type { Task } from "@ruan-cat/utils";
|
|
29
|
-
import { generateSpawnSync as generateSpawnSyncUtils, type SpawnSyncSimpleParams } from "@ruan-cat/utils/node-cjs";
|
|
30
|
-
|
|
31
|
-
import { config, getConfig } from "./config";
|
|
32
|
-
import type { Config, Base, DeployTarget, WithUserCommands } from "./config";
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* vercel 的空配置
|
|
36
|
-
* @description
|
|
37
|
-
* 设计理由
|
|
38
|
-
*
|
|
39
|
-
* 用于驱动vercel构建简单的目录结构,不需要额外的配置
|
|
40
|
-
*
|
|
41
|
-
* 该配置会被写入到 `vercel.null.def.json` 文件中
|
|
42
|
-
*
|
|
43
|
-
* @see https://github.com/amondnet/vercel-action#method-1---via-vercel-interface
|
|
44
|
-
*/
|
|
45
|
-
export const vercelNullConfig = <const>{
|
|
46
|
-
framework: null,
|
|
47
|
-
buildCommand: null,
|
|
48
|
-
installCommand: null,
|
|
49
|
-
outputDirectory: null,
|
|
50
|
-
devCommand: null,
|
|
51
|
-
public: false,
|
|
52
|
-
/**
|
|
53
|
-
* 部署后提供干净的链接
|
|
54
|
-
* @see https://vercel.com/docs/projects/project-configuration#cleanurls
|
|
55
|
-
*
|
|
56
|
-
* @description
|
|
57
|
-
* 暂无效果
|
|
58
|
-
*
|
|
59
|
-
* 目前在 build-output-api 中,实现cleanUrls需要手动地写入配置文件
|
|
60
|
-
*
|
|
61
|
-
* 成本较大,目前不做投入。
|
|
62
|
-
*/
|
|
63
|
-
cleanUrls: true,
|
|
64
|
-
git: {
|
|
65
|
-
deploymentEnabled: {
|
|
66
|
-
main: false,
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* 空配置文件的路径
|
|
73
|
-
* @description
|
|
74
|
-
* 生成空配置文件。这样用户在其他项目内,就不需要自己提供vercel配置文件了。
|
|
75
|
-
*/
|
|
76
|
-
const vercelNullConfigPath = <const>"./vercel.null.def.json";
|
|
77
|
-
|
|
78
|
-
/** vercel文件api指定要求的文件目录 */
|
|
79
|
-
const vercelOutputStatic = <const>".vercel/output/static";
|
|
80
|
-
|
|
81
|
-
/** 初始化vercel的空配置文件 */
|
|
82
|
-
async function generateVercelNullConfig() {
|
|
83
|
-
fs.writeFileSync(vercelNullConfigPath, JSON.stringify(vercelNullConfig, null, 2));
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function isDeployTargetsBase(target: DeployTarget): target is Base {
|
|
87
|
-
return target.type === "static";
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function isDeployTargetsWithUserCommands(target: DeployTarget): target is WithUserCommands {
|
|
91
|
-
return target.type === "userCommands";
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/** 获得 isCopyDist 配置 */
|
|
95
|
-
function getIsCopyDist(target: WithUserCommands) {
|
|
96
|
-
return target?.isCopyDist ?? true;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/** isNeedVercelBuild 配置 */
|
|
100
|
-
function isNeedVercelBuild(target: Base) {
|
|
101
|
-
return target?.isNeedVercelBuild ?? true;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/** 是否需要移动文件? */
|
|
105
|
-
function isNeedCopyDist(target: DeployTarget) {
|
|
106
|
-
if (isDeployTargetsWithUserCommands(target)) {
|
|
107
|
-
const isCopyDist = getIsCopyDist(target);
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* 每个条件都满足时 就需要移动文件
|
|
111
|
-
* 默认总是认为要移动文件
|
|
112
|
-
*/
|
|
113
|
-
return isConditionsEvery([
|
|
114
|
-
// 如果被用户显性设置为false,不需要移动,那么就直接退出 不移动文件
|
|
115
|
-
() => isCopyDist,
|
|
116
|
-
|
|
117
|
-
// 只要用户提供了非空输出目录 就认为需要移动文件
|
|
118
|
-
// 输出目录是必填项 不做判断
|
|
119
|
-
// () => !isEmpty(target.outputDirectory),
|
|
120
|
-
|
|
121
|
-
// 只要用户提供了非空命令 就认为用户提供了有意义的build构建命令 就默认移动文件
|
|
122
|
-
// 用户不填写命令时 也可能需要移动文件 故这里不做判断
|
|
123
|
-
// () => !isEmpty(target.userCommands),
|
|
124
|
-
]);
|
|
125
|
-
} else {
|
|
126
|
-
// 不是带有用户命令的部署目标 那么就不需要移动文件
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function getYesCommandArgument() {
|
|
132
|
-
return <const>["--yes"];
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function getProdCommandArgument() {
|
|
136
|
-
return <const>["--prod"];
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function getPrebuiltCommandArgument() {
|
|
140
|
-
return <const>["--prebuilt"];
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/** 以命令参数数组的形式,获得项目名称 */
|
|
144
|
-
function getVercelProjetNameCommandArgument() {
|
|
145
|
-
return <const>[`--project=${config.vercelProjetName}`];
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* 以命令参数数组的形式,获得范围名称
|
|
150
|
-
* @see https://vercel.com/docs/cli/global-options#scope
|
|
151
|
-
*
|
|
152
|
-
* 为什么传递组织id?
|
|
153
|
-
* 此篇讨论内 使用了组织id
|
|
154
|
-
* @see https://vercel.community/t/deployment-via-gitlab-ci-to-dev-domain/523/3
|
|
155
|
-
*/
|
|
156
|
-
function getVercelScopeCommandArgument() {
|
|
157
|
-
return <const>[`--scope=${config.vercelOrgId}`];
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/** 以命令参数数组的形式,获得项目token */
|
|
161
|
-
function getVercelTokenCommandArgument() {
|
|
162
|
-
return <const>[`--token=${config.vercelToken}`];
|
|
163
|
-
}
|
|
164
|
-
|
|
165
1
|
/**
|
|
166
|
-
*
|
|
2
|
+
* @ruan-cat/vercel-deploy-tool
|
|
167
3
|
* @description
|
|
168
|
-
*
|
|
4
|
+
* Vercel 部署工具 - 支持 monorepo 的自动化部署
|
|
169
5
|
*
|
|
170
|
-
*
|
|
6
|
+
* @author ruan-cat
|
|
7
|
+
* @license MIT
|
|
171
8
|
*/
|
|
172
|
-
function getVercelLocalConfigCommandArgument() {
|
|
173
|
-
return <const>[`--local-config=${config?.vercelJsonPath ?? vercelNullConfigPath}`];
|
|
174
|
-
}
|
|
175
9
|
|
|
176
|
-
|
|
177
|
-
function getTargetCWDCommandArgument(deployTarget: DeployTarget) {
|
|
178
|
-
return <const>[`--cwd=${deployTarget.targetCWD}`];
|
|
179
|
-
}
|
|
10
|
+
// ==================== 配置系统 ====================
|
|
180
11
|
|
|
181
12
|
/**
|
|
182
|
-
*
|
|
13
|
+
* 定义配置的辅助函数
|
|
183
14
|
* @description
|
|
184
|
-
*
|
|
15
|
+
* 提供类型提示和智能补全
|
|
185
16
|
*
|
|
186
|
-
* @
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
return generateSpawnSyncUtils({
|
|
190
|
-
...spawnSyncSimpleParams,
|
|
191
|
-
printCurrentCommand(params) {
|
|
192
|
-
const { command, parameters } = params;
|
|
193
|
-
const coloredCommand = gradient(["rgb(0, 153, 247)", "rgb(241, 23, 18)"])(`${command} ${parameters.join(" ")}`);
|
|
194
|
-
consola.info(` 当前运行的命令为: ${coloredCommand} \n`);
|
|
195
|
-
},
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* 生成link任务
|
|
201
|
-
* @description
|
|
202
|
-
* 旨在于封装类似于这样的命令:
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { defineConfig } from "@ruan-cat/vercel-deploy-tool";
|
|
203
20
|
*
|
|
204
|
-
*
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
getYesCommandArgument(),
|
|
211
|
-
getTargetCWDCommandArgument(deployTarget),
|
|
212
|
-
getVercelProjetNameCommandArgument(),
|
|
213
|
-
getVercelTokenCommandArgument(),
|
|
214
|
-
),
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* 生成build任务
|
|
220
|
-
* @description
|
|
221
|
-
* 旨在于封装类似于这样的命令:
|
|
222
|
-
*
|
|
223
|
-
* vc build --yes --prod --cwd=${{env.p1}} -A ./vercel.null.json -t ${{env.vct}}
|
|
21
|
+
* export default defineConfig({
|
|
22
|
+
* vercelProjectName: "my-project",
|
|
23
|
+
* vercelToken: process.env.VERCEL_TOKEN || "",
|
|
24
|
+
* // ...
|
|
25
|
+
* });
|
|
26
|
+
* ```
|
|
224
27
|
*/
|
|
225
|
-
|
|
226
|
-
return generateSpawnSync({
|
|
227
|
-
command: "vc build",
|
|
228
|
-
parameters: concat(
|
|
229
|
-
getYesCommandArgument(),
|
|
230
|
-
getProdCommandArgument(),
|
|
231
|
-
getTargetCWDCommandArgument(deployTarget),
|
|
232
|
-
getVercelLocalConfigCommandArgument(),
|
|
233
|
-
getVercelTokenCommandArgument(),
|
|
234
|
-
),
|
|
235
|
-
});
|
|
236
|
-
}
|
|
28
|
+
export { defineConfig } from "./config/define-config";
|
|
237
29
|
|
|
238
30
|
/**
|
|
239
|
-
*
|
|
31
|
+
* 加载配置
|
|
240
32
|
* @description
|
|
241
|
-
*
|
|
33
|
+
* 异步加载用户配置文件
|
|
242
34
|
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { loadConfig } from "@ruan-cat/vercel-deploy-tool";
|
|
246
38
|
*
|
|
247
|
-
*
|
|
248
|
-
* mkdirp .vercel/output/static
|
|
249
|
-
*
|
|
250
|
-
* # 复制目录到目标
|
|
251
|
-
* cpx \"docs/.vitepress/dist/**\/*\" .vercel/output/static
|
|
252
|
-
*
|
|
253
|
-
* # 输出目录
|
|
254
|
-
* shx ls -R .vercel/output/static
|
|
39
|
+
* const config = await loadConfig();
|
|
255
40
|
* ```
|
|
256
|
-
*
|
|
257
|
-
* @version 1
|
|
258
|
-
* @deprecated
|
|
259
|
-
* 不再使用该方式
|
|
260
|
-
*
|
|
261
|
-
* 不打算在用户侧的项目内,使用 `pnpm dlx ???` 这样的命令来完成依赖安装。这样效率太低了。
|
|
262
41
|
*/
|
|
263
|
-
|
|
264
|
-
function delDirectoryCmd() {
|
|
265
|
-
return <const>`pnpm dlx rimraf ${vercelOutputStatic}`;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
function createDirectoryCmd() {
|
|
269
|
-
return <const>`pnpm dlx mkdirp ${vercelOutputStatic}`;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
function copyDirectoryFileCmd() {
|
|
273
|
-
return <const>`pnpm dlx cpx "${deployTarget.outputDirectory}" ${vercelOutputStatic}`;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
function printDirectoryFileCmd() {
|
|
277
|
-
return <const>`pnpm dlx shx ls -R ${vercelOutputStatic}`;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
function cmdPrefix() {
|
|
281
|
-
return <const>`pnpm -C=${deployTarget.targetCWD}`;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
function cmdTemple<T extends (...args: any) => string, R extends ReturnType<T>>(
|
|
285
|
-
cmdFunc: T,
|
|
286
|
-
): `${ReturnType<typeof cmdPrefix>} ${R}` {
|
|
287
|
-
return `${cmdPrefix()} ${<R>cmdFunc()}`;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
const delCmd = cmdTemple(delDirectoryCmd);
|
|
291
|
-
const createCmd = cmdTemple(createDirectoryCmd);
|
|
292
|
-
const copyFileCmd = cmdTemple(copyDirectoryFileCmd);
|
|
293
|
-
const printFileCmd = cmdTemple(printDirectoryFileCmd);
|
|
294
|
-
|
|
295
|
-
const copyDistTasks = (<const>[delCmd, createCmd, copyFileCmd, printFileCmd]).map((command) => {
|
|
296
|
-
return generateSimpleAsyncTask(async function () {
|
|
297
|
-
const commandFunction = generateSpawnSync({
|
|
298
|
-
command,
|
|
299
|
-
parameters: [],
|
|
300
|
-
});
|
|
301
|
-
const { stdout } = await commandFunction();
|
|
302
|
-
consola.info(` 执行了命令 🐓: `, command);
|
|
303
|
-
// consola.box(stdout);
|
|
304
|
-
});
|
|
305
|
-
});
|
|
42
|
+
export { loadConfig, getConfig } from "./config/loader";
|
|
306
43
|
|
|
307
|
-
|
|
308
|
-
}
|
|
44
|
+
// ==================== 类型定义 ====================
|
|
309
45
|
|
|
310
46
|
/**
|
|
311
|
-
*
|
|
312
|
-
* @description
|
|
313
|
-
* 生成以下任务
|
|
314
|
-
*
|
|
315
|
-
* - 删除目录
|
|
316
|
-
* - 新建目录
|
|
317
|
-
* - 复制粘贴
|
|
47
|
+
* 导出所有类型定义
|
|
318
48
|
*/
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
* 仅考虑为内部使用 不是通用工具
|
|
327
|
-
*
|
|
328
|
-
* 本函数仅仅拼接部分路径
|
|
329
|
-
*/
|
|
330
|
-
function joinPath<T extends string>(dir: T) {
|
|
331
|
-
const resPath = resolve(process.cwd(), targetCWD, dir);
|
|
332
|
-
// console.log(" in joinPath => ", resPath);
|
|
333
|
-
return <`${string}${typeof targetCWD}/${T}`>resPath;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
const pathVercelOutputStatic = joinPath(vercelOutputStatic);
|
|
337
|
-
const pathOutputDirectory = joinPath(outputDirectory);
|
|
338
|
-
|
|
339
|
-
async function delVercelOutputStatic() {
|
|
340
|
-
consola.start(` 开始删除文件任务 `);
|
|
341
|
-
rmSync(pathVercelOutputStatic, { recursive: true });
|
|
342
|
-
consola.success(` 删除该路径的文件: ${pathVercelOutputStatic} `);
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
async function createVercelOutputStatic() {
|
|
346
|
-
consola.start(` 开始创建文件夹任务 `);
|
|
347
|
-
mkdir(pathVercelOutputStatic, () => {});
|
|
348
|
-
consola.success(` 创建的新目录为: ${pathVercelOutputStatic} `);
|
|
349
|
-
}
|
|
49
|
+
export type {
|
|
50
|
+
VercelDeployConfig,
|
|
51
|
+
DeployTarget,
|
|
52
|
+
DeployTargetBase,
|
|
53
|
+
DeployTargetWithUserCommands,
|
|
54
|
+
DeployTargetType,
|
|
55
|
+
} from "./types";
|
|
350
56
|
|
|
351
|
-
|
|
352
|
-
consola.start(` 开始文件复制任务 `);
|
|
353
|
-
consola.info(` 从 ${pathOutputDirectory} 开始 `);
|
|
354
|
-
consola.info(` 复制到 ${pathVercelOutputStatic} 内`);
|
|
355
|
-
cpSync(pathOutputDirectory, pathVercelOutputStatic, { recursive: true });
|
|
356
|
-
consola.success(` 完成文件复制任务 `);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
const resTasks = [delVercelOutputStatic, createVercelOutputStatic, cpyDistToVercelOutputStatic].map((asyncFn) => {
|
|
360
|
-
return generateSimpleAsyncTask(asyncFn);
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
return resTasks;
|
|
364
|
-
}
|
|
57
|
+
// ==================== 核心功能 ====================
|
|
365
58
|
|
|
366
59
|
/**
|
|
367
|
-
*
|
|
60
|
+
* 执行部署工作流
|
|
368
61
|
* @description
|
|
369
|
-
*
|
|
62
|
+
* 编程式调用部署流程
|
|
370
63
|
*
|
|
371
|
-
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* import { executeDeploymentWorkflow, loadConfig } from "@ruan-cat/vercel-deploy-tool";
|
|
372
67
|
*
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
*
|
|
68
|
+
* const config = await loadConfig();
|
|
69
|
+
* await executeDeploymentWorkflow(config);
|
|
70
|
+
* ```
|
|
376
71
|
*/
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
parameters: concat(getVercelTokenCommandArgument(), getVercelScopeCommandArgument()),
|
|
381
|
-
});
|
|
382
|
-
}
|
|
72
|
+
export { executeDeploymentWorkflow } from "./core/tasks";
|
|
73
|
+
|
|
74
|
+
// ==================== 工具函数 ====================
|
|
383
75
|
|
|
384
76
|
/**
|
|
385
|
-
*
|
|
386
|
-
* @description
|
|
387
|
-
* 旨在于封装类似于这样的命令:
|
|
388
|
-
*
|
|
389
|
-
* vc deploy --yes --prebuilt --prod --cwd=${{env.p1}} -t ${{env.vct}}
|
|
77
|
+
* Vercel 空配置
|
|
390
78
|
*/
|
|
391
|
-
|
|
392
|
-
return generateSpawnSync({
|
|
393
|
-
command: "vc deploy",
|
|
394
|
-
parameters: concat(
|
|
395
|
-
getYesCommandArgument(),
|
|
396
|
-
getPrebuiltCommandArgument(),
|
|
397
|
-
getProdCommandArgument(),
|
|
398
|
-
getTargetCWDCommandArgument(deployTarget),
|
|
399
|
-
getVercelTokenCommandArgument(),
|
|
400
|
-
),
|
|
401
|
-
// 部署任务不需要流式输出
|
|
402
|
-
isFlow: false,
|
|
403
|
-
});
|
|
404
|
-
}
|
|
79
|
+
export { VERCEL_NULL_CONFIG, VERCEL_NULL_CONFIG_PATH, VERCEL_OUTPUT_STATIC } from "./utils/vercel-null-config";
|
|
405
80
|
|
|
406
81
|
/**
|
|
407
|
-
*
|
|
408
|
-
* @description
|
|
409
|
-
* 这里返回的是具体的 Task 任务配置 不是异步函数
|
|
82
|
+
* 类型守卫
|
|
410
83
|
*/
|
|
411
|
-
|
|
412
|
-
|
|
84
|
+
export {
|
|
85
|
+
isDeployTargetBase,
|
|
86
|
+
isDeployTargetWithUserCommands,
|
|
87
|
+
getIsCopyDist,
|
|
88
|
+
isNeedVercelBuild,
|
|
89
|
+
} from "./utils/type-guards";
|
|
413
90
|
|
|
414
|
-
|
|
415
|
-
return {
|
|
416
|
-
type: "single",
|
|
417
|
-
tasks: generateSimpleAsyncTask(() => consola.warn(` 当前没有有意义的 afterBuildTasks 任务配置 `)),
|
|
418
|
-
};
|
|
419
|
-
} else {
|
|
420
|
-
return {
|
|
421
|
-
type: "queue",
|
|
422
|
-
tasks: afterBuildTasks!.map((command) => {
|
|
423
|
-
return generateSimpleAsyncTask(async () => {
|
|
424
|
-
const userCommand = generateSpawnSync({
|
|
425
|
-
command,
|
|
426
|
-
parameters: [],
|
|
427
|
-
});
|
|
428
|
-
consola.start(` 开始用户 afterBuildTasks 命令任务 `);
|
|
429
|
-
const { stdout } = await userCommand();
|
|
430
|
-
// consola.success(` 完成用户 afterBuildTasks 命令任务 ${code} `);
|
|
431
|
-
consola.success(` 完成用户 afterBuildTasks 命令任务 `);
|
|
432
|
-
// consola.box(stdout);
|
|
433
|
-
});
|
|
434
|
-
}),
|
|
435
|
-
};
|
|
436
|
-
}
|
|
437
|
-
}
|
|
91
|
+
// ==================== CLI 命令工厂 ====================
|
|
438
92
|
|
|
439
93
|
/**
|
|
440
|
-
*
|
|
441
|
-
* @
|
|
94
|
+
* 命令工厂函数(供编程式调用)
|
|
95
|
+
* @description
|
|
96
|
+
* 可以在代码中创建和使用命令
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* import { createDeployCommand } from "@ruan-cat/vercel-deploy-tool";
|
|
101
|
+
*
|
|
102
|
+
* const deployCmd = createDeployCommand();
|
|
103
|
+
* // 使用 commander 的 API
|
|
104
|
+
* ```
|
|
442
105
|
*/
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
const config = getConfig();
|
|
447
|
-
const { deployTargets } = config;
|
|
448
|
-
|
|
449
|
-
const promiseTasks = definePromiseTasks({
|
|
450
|
-
type: "queue",
|
|
451
|
-
|
|
452
|
-
tasks: [
|
|
453
|
-
// 全部的link链接任务
|
|
454
|
-
{
|
|
455
|
-
type: "parallel",
|
|
456
|
-
tasks: deployTargets.map((deployTarget) => {
|
|
457
|
-
return generateSimpleAsyncTask(async () => {
|
|
458
|
-
const link = generateLinkTask(deployTarget);
|
|
459
|
-
consola.start(` 开始link任务 `);
|
|
460
|
-
await link();
|
|
461
|
-
consola.success(` 完成link任务 `);
|
|
462
|
-
});
|
|
463
|
-
}),
|
|
464
|
-
},
|
|
465
|
-
|
|
466
|
-
// 全部的build构建任务
|
|
467
|
-
{
|
|
468
|
-
type: "parallel",
|
|
469
|
-
tasks: deployTargets.map((deployTarget) => {
|
|
470
|
-
return generateSimpleAsyncTask(async () => {
|
|
471
|
-
/** 当前部署目标 是否需要 vercel 的 build 任务? */
|
|
472
|
-
const isNeedBuildTask = isNeedVercelBuild(deployTarget);
|
|
473
|
-
if (!isNeedBuildTask) {
|
|
474
|
-
consola.warn(` 当前部署目标不需要执行build任务 `);
|
|
475
|
-
return;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
const build = generateBuildTask(deployTarget);
|
|
479
|
-
consola.start(` 开始build任务 `);
|
|
480
|
-
const { stdout } = await build();
|
|
481
|
-
consola.success(` 完成build任务 `);
|
|
482
|
-
});
|
|
483
|
-
}),
|
|
484
|
-
},
|
|
485
|
-
|
|
486
|
-
// afterBuildTasks 在build命令阶段后 执行的用户命令
|
|
487
|
-
generateAfterBuildTasksConfig(config),
|
|
488
|
-
|
|
489
|
-
// 全部的用户命令任务
|
|
490
|
-
{
|
|
491
|
-
type: "parallel",
|
|
492
|
-
tasks: deployTargets.map((deployTarget) => {
|
|
493
|
-
return {
|
|
494
|
-
type: "queue",
|
|
495
|
-
tasks: [
|
|
496
|
-
// 用户命令任务
|
|
497
|
-
// 如果没有用户命令
|
|
498
|
-
!isDeployTargetsWithUserCommands(deployTarget)
|
|
499
|
-
? generateSimpleAsyncTask(() => {
|
|
500
|
-
consola.warn(" 当前目标不属于需要执行一系列用户自定义命令。 ");
|
|
501
|
-
})
|
|
502
|
-
: // 否则有用户命令
|
|
503
|
-
{
|
|
504
|
-
type: "queue",
|
|
505
|
-
tasks: deployTarget.userCommands.map((command) => {
|
|
506
|
-
return generateSimpleAsyncTask(async () => {
|
|
507
|
-
const userCommand = generateSpawnSync({
|
|
508
|
-
command,
|
|
509
|
-
parameters: [],
|
|
510
|
-
});
|
|
511
|
-
consola.start(` 开始用户命令任务 `);
|
|
512
|
-
await userCommand();
|
|
513
|
-
consola.success(` 完成用户命令任务 `);
|
|
514
|
-
});
|
|
515
|
-
}),
|
|
516
|
-
},
|
|
517
|
-
|
|
518
|
-
// 复制移动文件任务
|
|
519
|
-
// 是否需要移动文件?
|
|
520
|
-
isNeedCopyDist(deployTarget) &&
|
|
521
|
-
// 这一行判断其实是冗余的 仅用于满足下面的类型检查
|
|
522
|
-
isDeployTargetsWithUserCommands(deployTarget)
|
|
523
|
-
? {
|
|
524
|
-
type: "queue",
|
|
525
|
-
tasks: generateCopyDistTasks(deployTarget),
|
|
526
|
-
}
|
|
527
|
-
: generateSimpleAsyncTask(() => {
|
|
528
|
-
consola.warn(" 不需要移动文件 ");
|
|
529
|
-
}),
|
|
530
|
-
],
|
|
531
|
-
};
|
|
532
|
-
}),
|
|
533
|
-
},
|
|
534
|
-
|
|
535
|
-
// 全部的部署任务
|
|
536
|
-
{
|
|
537
|
-
type: "parallel",
|
|
538
|
-
tasks: deployTargets.map((deployTarget) => {
|
|
539
|
-
return {
|
|
540
|
-
type: "queue",
|
|
541
|
-
// 串行执行部署任务和别名任务
|
|
542
|
-
tasks: [
|
|
543
|
-
// 部署任务
|
|
544
|
-
generateSimpleAsyncTask(async () => {
|
|
545
|
-
const deploy = generateDeployTask(deployTarget);
|
|
546
|
-
consola.start(` 开始部署任务 `);
|
|
547
|
-
const { stdout, error, stderr } = await deploy();
|
|
548
|
-
|
|
549
|
-
if (error) {
|
|
550
|
-
consola.error(" 部署失败了 \n");
|
|
551
|
-
consola.error(error);
|
|
552
|
-
return;
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
const vercelUrl = stdout.toString();
|
|
556
|
-
consola.success(` 完成部署任务 检查生成的url为 \n `);
|
|
557
|
-
consola.box(vercelUrl);
|
|
558
|
-
|
|
559
|
-
consola.success(` 部署任务输出如下: \n`);
|
|
560
|
-
console.log(`\n`);
|
|
561
|
-
|
|
562
|
-
return vercelUrl;
|
|
563
|
-
}),
|
|
564
|
-
|
|
565
|
-
// 并发的别名任务
|
|
566
|
-
{
|
|
567
|
-
type: "parallel",
|
|
568
|
-
tasks: deployTarget.url.map((userUrl) => {
|
|
569
|
-
return generateSimpleAsyncTask(async (vercelUrl: string) => {
|
|
570
|
-
const alias = generateAliasTask(vercelUrl, userUrl);
|
|
571
|
-
consola.start(` 开始别名任务 `);
|
|
572
|
-
const { stdout } = await alias();
|
|
573
|
-
// consola.success(` 执行了: ${command} `);
|
|
574
|
-
consola.success(` 完成别名任务 可用的别名地址为 \n`);
|
|
575
|
-
consola.box(`https://${userUrl}`);
|
|
576
|
-
});
|
|
577
|
-
}),
|
|
578
|
-
},
|
|
579
|
-
],
|
|
580
|
-
};
|
|
581
|
-
}),
|
|
582
|
-
},
|
|
583
|
-
],
|
|
584
|
-
});
|
|
585
|
-
|
|
586
|
-
await executePromiseTasks(promiseTasks);
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
main();
|
|
106
|
+
export { createDeployCommand } from "./commands/deploy";
|
|
107
|
+
export { createInitCommand } from "./commands/init";
|