@cloudbase/cli 2.0.0 → 2.0.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.
- package/.editorconfig +9 -9
- package/.eslintignore +7 -7
- package/.eslintrc +35 -35
- package/.prettierrc.js +29 -29
- package/.vscode/launch.json +16 -16
- package/LICENSE +5 -5
- package/README.md +35 -35
- package/bin/cloudbase.js +5 -5
- package/bin/tcb.js +6 -4
- package/changelog.md +6 -6
- package/jest.config.js +17 -17
- package/lib/commands/account/login.js +18 -18
- package/lib/commands/storage/storage.js +1 -1
- package/lib/env/login.js +7 -7
- package/lib/run/service/deployPackage.js +6 -4
- package/lib/utils/net/http-request.js +4 -4
- package/lib/utils/tcbrApi/tcbr-cloud-api/request.js +3 -3
- package/package.json +16 -16
- package/post-install.js +61 -61
- package/runtime/nodejs/bootstrap.js +255 -255
- package/runtime/nodejs/runtime.js +183 -183
- package/src/auth/index.ts +1 -1
- package/src/auth/login.ts +91 -91
- package/src/auth/logout.ts +7 -7
- package/src/commands/account/index.ts +2 -2
- package/src/commands/account/login.ts +192 -192
- package/src/commands/account/logout.ts +24 -24
- package/src/commands/common.ts +246 -246
- package/src/commands/env/base.ts +90 -90
- package/src/commands/env/create.ts +92 -92
- package/src/commands/env/domain.ts +186 -186
- package/src/commands/env/index.ts +4 -4
- package/src/commands/env/login.ts +235 -235
- package/src/commands/framework/index.ts +124 -124
- package/src/commands/functions/alias/getRoute.ts +76 -76
- package/src/commands/functions/alias/index.ts +2 -2
- package/src/commands/functions/alias/setRoute.ts +82 -82
- package/src/commands/functions/code-download.ts +100 -100
- package/src/commands/functions/code-update.ts +62 -62
- package/src/commands/functions/concurrency/delete.ts +45 -45
- package/src/commands/functions/concurrency/index.ts +2 -2
- package/src/commands/functions/concurrency/list.ts +58 -58
- package/src/commands/functions/concurrency/set.ts +47 -47
- package/src/commands/functions/config-update.ts +76 -76
- package/src/commands/functions/copy.ts +62 -62
- package/src/commands/functions/delete.ts +79 -79
- package/src/commands/functions/deploy.ts +293 -293
- package/src/commands/functions/detail.ts +138 -138
- package/src/commands/functions/index.ts +16 -16
- package/src/commands/functions/invoke.ts +121 -121
- package/src/commands/functions/layer/bind.ts +182 -182
- package/src/commands/functions/layer/common.ts +8 -8
- package/src/commands/functions/layer/create.ts +49 -49
- package/src/commands/functions/layer/delete.ts +73 -73
- package/src/commands/functions/layer/download.ts +92 -92
- package/src/commands/functions/layer/index.ts +7 -7
- package/src/commands/functions/layer/list.ts +94 -94
- package/src/commands/functions/layer/sort.ts +76 -76
- package/src/commands/functions/list.ts +68 -68
- package/src/commands/functions/log.ts +148 -148
- package/src/commands/functions/run.ts +249 -249
- package/src/commands/functions/trigger-create.ts +79 -79
- package/src/commands/functions/trigger-delete.ts +105 -105
- package/src/commands/functions/version/index.ts +1 -1
- package/src/commands/functions/version/list.ts +73 -73
- package/src/commands/functions/version/publish.ts +43 -43
- package/src/commands/gateway/create.ts +109 -109
- package/src/commands/gateway/delete.ts +81 -81
- package/src/commands/gateway/domain.ts +159 -159
- package/src/commands/gateway/index.ts +5 -5
- package/src/commands/gateway/list.ts +76 -76
- package/src/commands/gateway/switch.ts +107 -107
- package/src/commands/helpers/index.ts +2 -2
- package/src/commands/helpers/init.ts +431 -431
- package/src/commands/helpers/new.ts +117 -117
- package/src/commands/helpers/open.ts +67 -67
- package/src/commands/hosting/hosting.ts +360 -360
- package/src/commands/index.ts +13 -13
- package/src/commands/lowcode/app.ts +34 -34
- package/src/commands/lowcode/comps.ts +322 -322
- package/src/commands/lowcode/index.ts +1 -1
- package/src/commands/lowcode/utils.ts +24 -24
- package/src/commands/run/image/index.ts +4 -4
- package/src/commands/run/standalonegateway/common.ts +7 -7
- package/src/commands/run/standalonegateway/create.ts +85 -85
- package/src/commands/run/standalonegateway/destroy.ts +59 -59
- package/src/commands/run/standalonegateway/index.ts +4 -4
- package/src/commands/run/standalonegateway/list.ts +53 -53
- package/src/commands/run/standalonegateway/package.ts +62 -62
- package/src/commands/run/standalonegateway/turn.ts +63 -63
- package/src/commands/run/version/index.ts +4 -4
- package/src/commands/smart.ts +132 -132
- package/src/commands/storage/storage.ts +464 -464
- package/src/commands/third/thirdAttach.ts +49 -49
- package/src/completion/index.ts +13 -13
- package/src/decorators/captureError.ts +25 -25
- package/src/decorators/constants.ts +12 -12
- package/src/decorators/deprecate.ts +25 -25
- package/src/decorators/guard.ts +42 -42
- package/src/decorators/index.ts +7 -7
- package/src/decorators/injectParams.ts +54 -54
- package/src/decorators/params/common.ts +28 -28
- package/src/decorators/params/index.ts +35 -35
- package/src/env/domain.ts +33 -33
- package/src/env/index.ts +63 -63
- package/src/env/login.ts +80 -80
- package/src/error.ts +36 -36
- package/src/function/alias.ts +43 -43
- package/src/function/base.ts +253 -253
- package/src/function/code.ts +55 -55
- package/src/function/concurrency.ts +57 -57
- package/src/function/create.ts +78 -78
- package/src/function/delete.ts +42 -42
- package/src/function/index.ts +10 -10
- package/src/function/layer/attach.ts +68 -68
- package/src/function/layer/create.ts +63 -63
- package/src/function/layer/delete.ts +21 -21
- package/src/function/layer/download.ts +54 -54
- package/src/function/layer/index.ts +7 -7
- package/src/function/layer/list.ts +32 -32
- package/src/function/layer/sort.ts +24 -24
- package/src/function/trigger.ts +97 -97
- package/src/function/update.ts +35 -35
- package/src/function/version.ts +38 -38
- package/src/function/vpc.ts +22 -22
- package/src/gateway/index.ts +137 -137
- package/src/hosting.ts +212 -212
- package/src/index.ts +13 -13
- package/src/logger.ts +17 -17
- package/src/run/create.ts +23 -23
- package/src/run/delete.ts +15 -15
- package/src/run/image/build.ts +36 -36
- package/src/run/image/delete.ts +13 -13
- package/src/run/image/index.ts +3 -3
- package/src/run/image/info.ts +26 -26
- package/src/run/list.ts +29 -29
- package/src/run/repo.ts +24 -24
- package/src/run/service/deployPackage.ts +6 -4
- package/src/run/standalonegateway/create.ts +24 -24
- package/src/run/standalonegateway/destroy.ts +19 -19
- package/src/run/standalonegateway/index.ts +4 -4
- package/src/run/standalonegateway/list.ts +74 -74
- package/src/run/standalonegateway/package/list.ts +24 -24
- package/src/run/standalonegateway/turn/index.ts +1 -1
- package/src/run/standalonegateway/turn/off.ts +19 -19
- package/src/run/standalonegateway/turn/on.ts +19 -19
- package/src/run/version/create.ts +68 -68
- package/src/run/version/delete.ts +15 -15
- package/src/run/version/index.ts +5 -5
- package/src/run/version/list.ts +16 -16
- package/src/run/version/modify.ts +16 -16
- package/src/run/version/repo.ts +27 -27
- package/src/run/version/update.ts +58 -58
- package/src/storage.ts +114 -114
- package/src/third/index.ts +12 -12
- package/src/utils/auth.ts +15 -15
- package/src/utils/cli-table.ts +23 -23
- package/src/utils/config.ts +39 -39
- package/src/utils/env.ts +244 -244
- package/src/utils/fs/del.ts +5 -5
- package/src/utils/fs/index.ts +71 -71
- package/src/utils/function-packer.ts +97 -97
- package/src/utils/log.ts +81 -81
- package/src/utils/net/cloud-api-request.ts +62 -62
- package/src/utils/net/credential.ts +53 -53
- package/src/utils/net/http-request.ts +84 -84
- package/src/utils/net/index.ts +4 -4
- package/src/utils/net/manager-service.ts +36 -36
- package/src/utils/net/proxy.ts +6 -6
- package/src/utils/notice.ts +28 -28
- package/src/utils/output/highlight.ts +5 -5
- package/src/utils/output/index.ts +2 -2
- package/src/utils/output/link.ts +10 -10
- package/src/utils/output/loading.ts +82 -82
- package/src/utils/parallel.ts +82 -82
- package/src/utils/platform/index.ts +2 -2
- package/src/utils/platform/mac.ts +21 -21
- package/src/utils/platform/os.ts +64 -64
- package/src/utils/platform/port.ts +10 -10
- package/src/utils/progress-bar.ts +38 -38
- package/src/utils/prompt/select.ts +59 -59
- package/src/utils/reporter/agree.ts +20 -20
- package/src/utils/reporter/download.ts +26 -26
- package/src/utils/reporter/index.ts +3 -3
- package/src/utils/reporter/usage.ts +20 -20
- package/src/utils/store/auth.ts +49 -49
- package/src/utils/store/common.ts +8 -8
- package/src/utils/store/db.ts +68 -68
- package/src/utils/store/index.ts +4 -4
- package/src/utils/store/usage.ts +12 -12
- package/src/utils/tcbrApi/tcbr-cloud-api/request.ts +13 -13
- package/src/utils/template.ts +170 -170
- package/src/utils/tools/encoding.ts +8 -8
- package/src/utils/tools/index.ts +4 -4
- package/src/utils/tools/object.ts +33 -33
- package/src/utils/tools/time.ts +38 -38
- package/src/utils/tools/uid.ts +19 -19
- package/templates/html/loginFail.html +90 -90
- package/templates/html/loginSuccess.html +86 -86
- package/templates/server/node/_gitignore +54 -54
- package/templates/server/node/cloudbaserc.json +10 -10
- package/templates/server/node/index.js +5 -5
- package/templates/server/node/package.json +9 -9
- package/tsconfig.json +19 -19
- package/tsconfig.test.json +13 -13
- package/.vscode/settings.json +0 -3
|
@@ -1,293 +1,293 @@
|
|
|
1
|
-
import path from 'path'
|
|
2
|
-
import inquirer from 'inquirer'
|
|
3
|
-
import { getRegion } from '@cloudbase/toolbox'
|
|
4
|
-
import { Command, ICommand } from '../common'
|
|
5
|
-
import { CloudBaseError } from '../../error'
|
|
6
|
-
import { createFunction } from '../../function'
|
|
7
|
-
import { queryGateway, createGateway } from '../../gateway'
|
|
8
|
-
import {
|
|
9
|
-
logger,
|
|
10
|
-
random,
|
|
11
|
-
isDirectory,
|
|
12
|
-
loadingFactory,
|
|
13
|
-
genClickableLink,
|
|
14
|
-
highlightCommand,
|
|
15
|
-
checkFullAccess,
|
|
16
|
-
AsyncTaskParallelController
|
|
17
|
-
} from '../../utils'
|
|
18
|
-
import { ICreateFunctionOptions } from '../../types'
|
|
19
|
-
import { DefaultFunctionDeployConfig } from '../../constant'
|
|
20
|
-
import { InjectParams, CmdContext, ArgsParams, Log, Logger } from '../../decorators'
|
|
21
|
-
|
|
22
|
-
const regionIdMap = {
|
|
23
|
-
'ap-guangzhou': 1,
|
|
24
|
-
'ap-shanghai': 4,
|
|
25
|
-
'ap-beijing': 8
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
@ICommand()
|
|
29
|
-
export class FunctionDeploy extends Command {
|
|
30
|
-
get options() {
|
|
31
|
-
return {
|
|
32
|
-
cmd: 'fn',
|
|
33
|
-
childCmd: 'deploy [name]',
|
|
34
|
-
deprecateCmd: 'functions:deploy [name]',
|
|
35
|
-
options: [
|
|
36
|
-
{
|
|
37
|
-
flags: '-e, --envId <envId>',
|
|
38
|
-
desc: '环境 Id'
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
flags: '--code-secret <codeSecret>',
|
|
42
|
-
desc: '传入此参数将保护代码,格式为 36 位大小写字母和数字'
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
flags: '--force',
|
|
46
|
-
desc: '如果存在同名函数,上传后覆盖同名函数'
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
flags: '--path <path>',
|
|
50
|
-
desc: '自动创建HTTP 访问服务访问路径'
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
flags: '--all',
|
|
54
|
-
desc: '部署配置文件中的包含的全部云函数'
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
flags: '--dir <dir>',
|
|
58
|
-
desc: '指定云函数的文件夹路径'
|
|
59
|
-
}
|
|
60
|
-
],
|
|
61
|
-
desc: '部署云函数'
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
@InjectParams()
|
|
66
|
-
async execute(@CmdContext() ctx, @ArgsParams() params, @Log() log: Logger) {
|
|
67
|
-
const { envId, config, options } = ctx
|
|
68
|
-
const { functions } = config
|
|
69
|
-
const { force, codeSecret, path: access, all, dir } = options
|
|
70
|
-
const functionRootPath = path.join(process.cwd(), config.functionRoot)
|
|
71
|
-
const name = params?.[0]
|
|
72
|
-
|
|
73
|
-
if (access && checkFullAccess(access)) {
|
|
74
|
-
log.warn('--path 参数已更换为HTTP 访问服务路径,请使用 --dir 指定部署函数的文件夹路径')
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (access && access[0] !== '/') {
|
|
78
|
-
throw new CloudBaseError('HTTP 访问服务路径必须以 / 开头')
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// 当没有指定函数名称或函数路径时,询问处理否部署全部云函数
|
|
82
|
-
if ((!name && !dir) || all) {
|
|
83
|
-
return this.deployAllFunction({
|
|
84
|
-
all,
|
|
85
|
-
envId,
|
|
86
|
-
force,
|
|
87
|
-
access,
|
|
88
|
-
functions,
|
|
89
|
-
codeSecret,
|
|
90
|
-
functionRootPath
|
|
91
|
-
})
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// 校验函数路径是否存在
|
|
95
|
-
if (dir) {
|
|
96
|
-
checkFullAccess(dir, true)
|
|
97
|
-
if (!isDirectory(dir)) {
|
|
98
|
-
throw new CloudBaseError('--dir 参数必须指定为云函数的文件夹路径')
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
let newFunction
|
|
103
|
-
if (functions && functions.length > 0) {
|
|
104
|
-
newFunction = functions.find((item) => item.name === name)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// 没有配置,使用默认配置
|
|
108
|
-
if (!newFunction || !newFunction.name) {
|
|
109
|
-
log.info('未找到函数发布配置,使用默认配置 => 运行时:Nodejs10.15/在线安装依赖')
|
|
110
|
-
newFunction = {
|
|
111
|
-
name,
|
|
112
|
-
...DefaultFunctionDeployConfig
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const loading = loadingFactory()
|
|
117
|
-
|
|
118
|
-
loading.start('云函数部署中...')
|
|
119
|
-
|
|
120
|
-
try {
|
|
121
|
-
await createFunction({
|
|
122
|
-
force,
|
|
123
|
-
envId,
|
|
124
|
-
codeSecret,
|
|
125
|
-
functionRootPath,
|
|
126
|
-
func: newFunction,
|
|
127
|
-
accessPath: access,
|
|
128
|
-
functionPath: dir
|
|
129
|
-
})
|
|
130
|
-
loading.succeed(`[${newFunction.name}] 云函数部署成功!`)
|
|
131
|
-
// await genApiGateway(envId, name)
|
|
132
|
-
this.printSuccessTips(envId)
|
|
133
|
-
} catch (e) {
|
|
134
|
-
// 询问是否覆盖同名函数
|
|
135
|
-
loading.stop()
|
|
136
|
-
await this.handleDeployFail(e, {
|
|
137
|
-
envId,
|
|
138
|
-
codeSecret,
|
|
139
|
-
functionRootPath,
|
|
140
|
-
func: newFunction,
|
|
141
|
-
accessPath: access,
|
|
142
|
-
functionPath: dir
|
|
143
|
-
})
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (access || newFunction.path) {
|
|
147
|
-
const link = genClickableLink(
|
|
148
|
-
`https://${envId}.service.tcloudbase.com${access || newFunction.path}`
|
|
149
|
-
)
|
|
150
|
-
console.log(`\n云函数HTTP 访问服务访问链接:${link}`)
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
async deployAllFunction(options: any) {
|
|
155
|
-
const { functions = [], envId, force, codeSecret, functionRootPath, all, access } = options
|
|
156
|
-
|
|
157
|
-
// 指定 all 参数,直接部署全部云函数
|
|
158
|
-
if (!all) {
|
|
159
|
-
const { isBatch } = await inquirer.prompt({
|
|
160
|
-
type: 'confirm',
|
|
161
|
-
name: 'isBatch',
|
|
162
|
-
message: '没有指定需要部署的云函数,是否部署配置文件中的全部云函数?',
|
|
163
|
-
default: false
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
// 用户不部署全部函数,报错
|
|
167
|
-
if (!isBatch) {
|
|
168
|
-
throw new CloudBaseError(
|
|
169
|
-
'请指定需要部署的云函数的名称或通过 --path 参数指定需要部署的函数的路径!'
|
|
170
|
-
)
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// 批量部署云函数
|
|
175
|
-
const loading = loadingFactory()
|
|
176
|
-
const tasks = functions.map((func) => async () => {
|
|
177
|
-
loading.start('云函数部署中')
|
|
178
|
-
try {
|
|
179
|
-
await createFunction({
|
|
180
|
-
func,
|
|
181
|
-
envId,
|
|
182
|
-
force,
|
|
183
|
-
codeSecret,
|
|
184
|
-
functionRootPath,
|
|
185
|
-
accessPath: access
|
|
186
|
-
})
|
|
187
|
-
loading.succeed(`[${func.name}] 云函数部署成功`)
|
|
188
|
-
} catch (e) {
|
|
189
|
-
loading.stop()
|
|
190
|
-
await this.handleDeployFail(e, {
|
|
191
|
-
func,
|
|
192
|
-
envId,
|
|
193
|
-
codeSecret,
|
|
194
|
-
functionRootPath,
|
|
195
|
-
accessPath: access
|
|
196
|
-
})
|
|
197
|
-
}
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
if (tasks.length > 5) {
|
|
201
|
-
logger.info('函数数量较多,将使用队列部署')
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// 控制函数创建并发
|
|
205
|
-
const asyncTaskController = new AsyncTaskParallelController(5, 50)
|
|
206
|
-
asyncTaskController.loadTasks(tasks)
|
|
207
|
-
const results = await asyncTaskController.run()
|
|
208
|
-
|
|
209
|
-
// 输出信息
|
|
210
|
-
const success = results.filter((_) => !_)
|
|
211
|
-
logger.success(`成功部署 ${success?.length} 个函数`)
|
|
212
|
-
// 部署失败
|
|
213
|
-
const err = results.filter((_) => _)
|
|
214
|
-
err?.length && logger.error(`${err?.length} 个云函数部署失败`)
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
async handleDeployFail(e: CloudBaseError, options: ICreateFunctionOptions) {
|
|
218
|
-
const { envId, codeSecret, functionRootPath, func, functionPath, accessPath } = options
|
|
219
|
-
const loading = loadingFactory()
|
|
220
|
-
|
|
221
|
-
if (e.code === 'ResourceInUse.FunctionName' || e.code === 'ResourceInUse.Function') {
|
|
222
|
-
const { force } = await inquirer.prompt({
|
|
223
|
-
type: 'confirm',
|
|
224
|
-
name: 'force',
|
|
225
|
-
message: `存在同名云函数:[${func.name}],是否覆盖原函数代码与配置`,
|
|
226
|
-
default: false
|
|
227
|
-
})
|
|
228
|
-
|
|
229
|
-
if (force) {
|
|
230
|
-
loading.start('云函数部署中...')
|
|
231
|
-
try {
|
|
232
|
-
await createFunction({
|
|
233
|
-
func,
|
|
234
|
-
envId,
|
|
235
|
-
codeSecret,
|
|
236
|
-
accessPath,
|
|
237
|
-
force: true,
|
|
238
|
-
functionPath,
|
|
239
|
-
functionRootPath
|
|
240
|
-
})
|
|
241
|
-
loading.succeed(`[${func.name}] 云函数部署成功!`)
|
|
242
|
-
// await genApiGateway(envId, name)
|
|
243
|
-
await this.printSuccessTips(envId)
|
|
244
|
-
} catch (e) {
|
|
245
|
-
loading.stop()
|
|
246
|
-
throw e
|
|
247
|
-
}
|
|
248
|
-
return
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
throw e
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
@InjectParams()
|
|
256
|
-
async printSuccessTips(envId: string, @Log() log?: Logger) {
|
|
257
|
-
let url = `https://console.cloud.tencent.com/tcb/scf?envId=${envId}`
|
|
258
|
-
const region = await getRegion()
|
|
259
|
-
url += `&rid=${regionIdMap[region]}`
|
|
260
|
-
const link = genClickableLink(url)
|
|
261
|
-
log.breakLine()
|
|
262
|
-
log.info(`控制台查看函数详情或创建HTTP 访问服务链接 🔗:${link}`)
|
|
263
|
-
log.info(`使用 ${highlightCommand('cloudbase functions:list')} 命令查看已部署云函数`)
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// 创建函数 API 网关
|
|
267
|
-
async genApiGateway(envId: string, name: string) {
|
|
268
|
-
const loading = loadingFactory()
|
|
269
|
-
// 检查是否绑定了 HTTP 网关
|
|
270
|
-
const res = await queryGateway({
|
|
271
|
-
name,
|
|
272
|
-
envId
|
|
273
|
-
})
|
|
274
|
-
// 未开启,不生成 HTTP 调用了链接
|
|
275
|
-
if (res?.EnableService === false) return
|
|
276
|
-
loading.start('生成云函数HTTP 访问服务中...')
|
|
277
|
-
|
|
278
|
-
let path
|
|
279
|
-
if (res?.APISet?.length > 0) {
|
|
280
|
-
path = res.APISet[0]?.Path
|
|
281
|
-
} else {
|
|
282
|
-
path = `/${random(12)}`
|
|
283
|
-
await createGateway({
|
|
284
|
-
envId,
|
|
285
|
-
name,
|
|
286
|
-
path
|
|
287
|
-
})
|
|
288
|
-
}
|
|
289
|
-
loading.stop()
|
|
290
|
-
const link = genClickableLink(`https://${envId}.service.tcloudbase.com${path}`)
|
|
291
|
-
console.log(`\n云函数HTTP 访问服务链接:${link}`)
|
|
292
|
-
}
|
|
293
|
-
}
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import inquirer from 'inquirer'
|
|
3
|
+
import { getRegion } from '@cloudbase/toolbox'
|
|
4
|
+
import { Command, ICommand } from '../common'
|
|
5
|
+
import { CloudBaseError } from '../../error'
|
|
6
|
+
import { createFunction } from '../../function'
|
|
7
|
+
import { queryGateway, createGateway } from '../../gateway'
|
|
8
|
+
import {
|
|
9
|
+
logger,
|
|
10
|
+
random,
|
|
11
|
+
isDirectory,
|
|
12
|
+
loadingFactory,
|
|
13
|
+
genClickableLink,
|
|
14
|
+
highlightCommand,
|
|
15
|
+
checkFullAccess,
|
|
16
|
+
AsyncTaskParallelController
|
|
17
|
+
} from '../../utils'
|
|
18
|
+
import { ICreateFunctionOptions } from '../../types'
|
|
19
|
+
import { DefaultFunctionDeployConfig } from '../../constant'
|
|
20
|
+
import { InjectParams, CmdContext, ArgsParams, Log, Logger } from '../../decorators'
|
|
21
|
+
|
|
22
|
+
const regionIdMap = {
|
|
23
|
+
'ap-guangzhou': 1,
|
|
24
|
+
'ap-shanghai': 4,
|
|
25
|
+
'ap-beijing': 8
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@ICommand()
|
|
29
|
+
export class FunctionDeploy extends Command {
|
|
30
|
+
get options() {
|
|
31
|
+
return {
|
|
32
|
+
cmd: 'fn',
|
|
33
|
+
childCmd: 'deploy [name]',
|
|
34
|
+
deprecateCmd: 'functions:deploy [name]',
|
|
35
|
+
options: [
|
|
36
|
+
{
|
|
37
|
+
flags: '-e, --envId <envId>',
|
|
38
|
+
desc: '环境 Id'
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
flags: '--code-secret <codeSecret>',
|
|
42
|
+
desc: '传入此参数将保护代码,格式为 36 位大小写字母和数字'
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
flags: '--force',
|
|
46
|
+
desc: '如果存在同名函数,上传后覆盖同名函数'
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
flags: '--path <path>',
|
|
50
|
+
desc: '自动创建HTTP 访问服务访问路径'
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
flags: '--all',
|
|
54
|
+
desc: '部署配置文件中的包含的全部云函数'
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
flags: '--dir <dir>',
|
|
58
|
+
desc: '指定云函数的文件夹路径'
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
desc: '部署云函数'
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@InjectParams()
|
|
66
|
+
async execute(@CmdContext() ctx, @ArgsParams() params, @Log() log: Logger) {
|
|
67
|
+
const { envId, config, options } = ctx
|
|
68
|
+
const { functions } = config
|
|
69
|
+
const { force, codeSecret, path: access, all, dir } = options
|
|
70
|
+
const functionRootPath = path.join(process.cwd(), config.functionRoot)
|
|
71
|
+
const name = params?.[0]
|
|
72
|
+
|
|
73
|
+
if (access && checkFullAccess(access)) {
|
|
74
|
+
log.warn('--path 参数已更换为HTTP 访问服务路径,请使用 --dir 指定部署函数的文件夹路径')
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (access && access[0] !== '/') {
|
|
78
|
+
throw new CloudBaseError('HTTP 访问服务路径必须以 / 开头')
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 当没有指定函数名称或函数路径时,询问处理否部署全部云函数
|
|
82
|
+
if ((!name && !dir) || all) {
|
|
83
|
+
return this.deployAllFunction({
|
|
84
|
+
all,
|
|
85
|
+
envId,
|
|
86
|
+
force,
|
|
87
|
+
access,
|
|
88
|
+
functions,
|
|
89
|
+
codeSecret,
|
|
90
|
+
functionRootPath
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 校验函数路径是否存在
|
|
95
|
+
if (dir) {
|
|
96
|
+
checkFullAccess(dir, true)
|
|
97
|
+
if (!isDirectory(dir)) {
|
|
98
|
+
throw new CloudBaseError('--dir 参数必须指定为云函数的文件夹路径')
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let newFunction
|
|
103
|
+
if (functions && functions.length > 0) {
|
|
104
|
+
newFunction = functions.find((item) => item.name === name)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 没有配置,使用默认配置
|
|
108
|
+
if (!newFunction || !newFunction.name) {
|
|
109
|
+
log.info('未找到函数发布配置,使用默认配置 => 运行时:Nodejs10.15/在线安装依赖')
|
|
110
|
+
newFunction = {
|
|
111
|
+
name,
|
|
112
|
+
...DefaultFunctionDeployConfig
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const loading = loadingFactory()
|
|
117
|
+
|
|
118
|
+
loading.start('云函数部署中...')
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
await createFunction({
|
|
122
|
+
force,
|
|
123
|
+
envId,
|
|
124
|
+
codeSecret,
|
|
125
|
+
functionRootPath,
|
|
126
|
+
func: newFunction,
|
|
127
|
+
accessPath: access,
|
|
128
|
+
functionPath: dir
|
|
129
|
+
})
|
|
130
|
+
loading.succeed(`[${newFunction.name}] 云函数部署成功!`)
|
|
131
|
+
// await genApiGateway(envId, name)
|
|
132
|
+
this.printSuccessTips(envId)
|
|
133
|
+
} catch (e) {
|
|
134
|
+
// 询问是否覆盖同名函数
|
|
135
|
+
loading.stop()
|
|
136
|
+
await this.handleDeployFail(e, {
|
|
137
|
+
envId,
|
|
138
|
+
codeSecret,
|
|
139
|
+
functionRootPath,
|
|
140
|
+
func: newFunction,
|
|
141
|
+
accessPath: access,
|
|
142
|
+
functionPath: dir
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (access || newFunction.path) {
|
|
147
|
+
const link = genClickableLink(
|
|
148
|
+
`https://${envId}.service.tcloudbase.com${access || newFunction.path}`
|
|
149
|
+
)
|
|
150
|
+
console.log(`\n云函数HTTP 访问服务访问链接:${link}`)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async deployAllFunction(options: any) {
|
|
155
|
+
const { functions = [], envId, force, codeSecret, functionRootPath, all, access } = options
|
|
156
|
+
|
|
157
|
+
// 指定 all 参数,直接部署全部云函数
|
|
158
|
+
if (!all) {
|
|
159
|
+
const { isBatch } = await inquirer.prompt({
|
|
160
|
+
type: 'confirm',
|
|
161
|
+
name: 'isBatch',
|
|
162
|
+
message: '没有指定需要部署的云函数,是否部署配置文件中的全部云函数?',
|
|
163
|
+
default: false
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
// 用户不部署全部函数,报错
|
|
167
|
+
if (!isBatch) {
|
|
168
|
+
throw new CloudBaseError(
|
|
169
|
+
'请指定需要部署的云函数的名称或通过 --path 参数指定需要部署的函数的路径!'
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// 批量部署云函数
|
|
175
|
+
const loading = loadingFactory()
|
|
176
|
+
const tasks = functions.map((func) => async () => {
|
|
177
|
+
loading.start('云函数部署中')
|
|
178
|
+
try {
|
|
179
|
+
await createFunction({
|
|
180
|
+
func,
|
|
181
|
+
envId,
|
|
182
|
+
force,
|
|
183
|
+
codeSecret,
|
|
184
|
+
functionRootPath,
|
|
185
|
+
accessPath: access
|
|
186
|
+
})
|
|
187
|
+
loading.succeed(`[${func.name}] 云函数部署成功`)
|
|
188
|
+
} catch (e) {
|
|
189
|
+
loading.stop()
|
|
190
|
+
await this.handleDeployFail(e, {
|
|
191
|
+
func,
|
|
192
|
+
envId,
|
|
193
|
+
codeSecret,
|
|
194
|
+
functionRootPath,
|
|
195
|
+
accessPath: access
|
|
196
|
+
})
|
|
197
|
+
}
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
if (tasks.length > 5) {
|
|
201
|
+
logger.info('函数数量较多,将使用队列部署')
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// 控制函数创建并发
|
|
205
|
+
const asyncTaskController = new AsyncTaskParallelController(5, 50)
|
|
206
|
+
asyncTaskController.loadTasks(tasks)
|
|
207
|
+
const results = await asyncTaskController.run()
|
|
208
|
+
|
|
209
|
+
// 输出信息
|
|
210
|
+
const success = results.filter((_) => !_)
|
|
211
|
+
logger.success(`成功部署 ${success?.length} 个函数`)
|
|
212
|
+
// 部署失败
|
|
213
|
+
const err = results.filter((_) => _)
|
|
214
|
+
err?.length && logger.error(`${err?.length} 个云函数部署失败`)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async handleDeployFail(e: CloudBaseError, options: ICreateFunctionOptions) {
|
|
218
|
+
const { envId, codeSecret, functionRootPath, func, functionPath, accessPath } = options
|
|
219
|
+
const loading = loadingFactory()
|
|
220
|
+
|
|
221
|
+
if (e.code === 'ResourceInUse.FunctionName' || e.code === 'ResourceInUse.Function') {
|
|
222
|
+
const { force } = await inquirer.prompt({
|
|
223
|
+
type: 'confirm',
|
|
224
|
+
name: 'force',
|
|
225
|
+
message: `存在同名云函数:[${func.name}],是否覆盖原函数代码与配置`,
|
|
226
|
+
default: false
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
if (force) {
|
|
230
|
+
loading.start('云函数部署中...')
|
|
231
|
+
try {
|
|
232
|
+
await createFunction({
|
|
233
|
+
func,
|
|
234
|
+
envId,
|
|
235
|
+
codeSecret,
|
|
236
|
+
accessPath,
|
|
237
|
+
force: true,
|
|
238
|
+
functionPath,
|
|
239
|
+
functionRootPath
|
|
240
|
+
})
|
|
241
|
+
loading.succeed(`[${func.name}] 云函数部署成功!`)
|
|
242
|
+
// await genApiGateway(envId, name)
|
|
243
|
+
await this.printSuccessTips(envId)
|
|
244
|
+
} catch (e) {
|
|
245
|
+
loading.stop()
|
|
246
|
+
throw e
|
|
247
|
+
}
|
|
248
|
+
return
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
throw e
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
@InjectParams()
|
|
256
|
+
async printSuccessTips(envId: string, @Log() log?: Logger) {
|
|
257
|
+
let url = `https://console.cloud.tencent.com/tcb/scf?envId=${envId}`
|
|
258
|
+
const region = await getRegion()
|
|
259
|
+
url += `&rid=${regionIdMap[region]}`
|
|
260
|
+
const link = genClickableLink(url)
|
|
261
|
+
log.breakLine()
|
|
262
|
+
log.info(`控制台查看函数详情或创建HTTP 访问服务链接 🔗:${link}`)
|
|
263
|
+
log.info(`使用 ${highlightCommand('cloudbase functions:list')} 命令查看已部署云函数`)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// 创建函数 API 网关
|
|
267
|
+
async genApiGateway(envId: string, name: string) {
|
|
268
|
+
const loading = loadingFactory()
|
|
269
|
+
// 检查是否绑定了 HTTP 网关
|
|
270
|
+
const res = await queryGateway({
|
|
271
|
+
name,
|
|
272
|
+
envId
|
|
273
|
+
})
|
|
274
|
+
// 未开启,不生成 HTTP 调用了链接
|
|
275
|
+
if (res?.EnableService === false) return
|
|
276
|
+
loading.start('生成云函数HTTP 访问服务中...')
|
|
277
|
+
|
|
278
|
+
let path
|
|
279
|
+
if (res?.APISet?.length > 0) {
|
|
280
|
+
path = res.APISet[0]?.Path
|
|
281
|
+
} else {
|
|
282
|
+
path = `/${random(12)}`
|
|
283
|
+
await createGateway({
|
|
284
|
+
envId,
|
|
285
|
+
name,
|
|
286
|
+
path
|
|
287
|
+
})
|
|
288
|
+
}
|
|
289
|
+
loading.stop()
|
|
290
|
+
const link = genClickableLink(`https://${envId}.service.tcloudbase.com${path}`)
|
|
291
|
+
console.log(`\n云函数HTTP 访问服务链接:${link}`)
|
|
292
|
+
}
|
|
293
|
+
}
|