esa-cli 1.0.1 → 1.0.2-beta.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 +2 -2
- package/dist/commands/commit/index.js +6 -1
- package/dist/commands/common/utils.js +84 -4
- package/dist/commands/deploy/index.js +18 -2
- package/dist/commands/login/index.js +22 -14
- package/dist/docs/Commands_en.md +261 -140
- package/dist/docs/Commands_zh_CN.md +256 -144
- package/dist/docs/Config_en.md +13 -7
- package/dist/docs/Config_zh_CN.md +13 -7
- package/dist/i18n/locales.json +5 -1
- package/dist/utils/compress.js +9 -3
- package/dist/utils/fileUtils/index.js +1 -1
- package/package.json +1 -1
- package/zh_CN.md +2 -2
package/README.md
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
ESA CLI is a command-line tool for building with Alibaba Cloud ESA Functions and Pages.
|
|
4
4
|
|
|
5
5
|
<p>
|
|
6
|
-
<a href="https://discord.gg/
|
|
6
|
+
<a href="https://discord.gg/BxcRVEeh">
|
|
7
7
|
<img alt="Discord CN" src="https://img.shields.io/badge/Discord-中文-5865F2?logo=discord&logoColor=white" />
|
|
8
8
|
</a>
|
|
9
|
-
<a href="https://discord.gg/
|
|
9
|
+
<a href="https://discord.gg/SHYe5926" style="margin-left:8px;">
|
|
10
10
|
<img alt="Discord EN" src="https://img.shields.io/badge/Discord-English-5865F2?logo=discord&logoColor=white" />
|
|
11
11
|
</a>
|
|
12
12
|
</p>
|
|
@@ -39,6 +39,11 @@ const commit = {
|
|
|
39
39
|
alias: 'n',
|
|
40
40
|
describe: t('commit_option_name').d('Functions& Pages name'),
|
|
41
41
|
type: 'string'
|
|
42
|
+
})
|
|
43
|
+
.option('bundle', {
|
|
44
|
+
describe: 'Bundle with esbuild (use --no-bundle to skip)',
|
|
45
|
+
type: 'boolean',
|
|
46
|
+
default: true
|
|
42
47
|
});
|
|
43
48
|
},
|
|
44
49
|
handler: (argv) => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -68,7 +73,7 @@ export function handleCommit(argv) {
|
|
|
68
73
|
}));
|
|
69
74
|
}
|
|
70
75
|
logger.startSubStep('Generating code version');
|
|
71
|
-
const res = yield generateCodeVersion(projectName, description, argv === null || argv === void 0 ? void 0 : argv.entry, argv === null || argv === void 0 ? void 0 : argv.assets, argv === null || argv === void 0 ? void 0 : argv.minify);
|
|
76
|
+
const res = yield generateCodeVersion(projectName, description, argv === null || argv === void 0 ? void 0 : argv.entry, argv === null || argv === void 0 ? void 0 : argv.assets, argv === null || argv === void 0 ? void 0 : argv.minify, undefined, (argv.bundle === false));
|
|
72
77
|
const { isSuccess } = res || {};
|
|
73
78
|
if (!isSuccess) {
|
|
74
79
|
logger.endSubStep('Generate version failed');
|
|
@@ -120,9 +120,9 @@ export function getRoutineDetails(projectName) {
|
|
|
120
120
|
* 支持assets和普通代码两种模式
|
|
121
121
|
*/
|
|
122
122
|
export function generateCodeVersion(projectName_1, description_1, entry_1, assets_1) {
|
|
123
|
-
return __awaiter(this, arguments, void 0, function* (projectName, description, entry, assets, minify = false, projectPath) {
|
|
123
|
+
return __awaiter(this, arguments, void 0, function* (projectName, description, entry, assets, minify = false, projectPath, noBundle = false) {
|
|
124
124
|
var _a;
|
|
125
|
-
const { zip, sourceList, dynamicSources } = yield compress(entry, assets, minify, projectPath);
|
|
125
|
+
const { zip, sourceList, dynamicSources } = yield compress(entry, assets, minify, projectPath, noBundle);
|
|
126
126
|
// Pretty print upload directory tree
|
|
127
127
|
const buildTree = (paths, decorateTopLevel) => {
|
|
128
128
|
const root = { children: new Map(), isFile: false };
|
|
@@ -260,7 +260,7 @@ export function deployToEnvironments(name, codeVersion, env) {
|
|
|
260
260
|
* 结合了压缩、提交和部署的完整流程
|
|
261
261
|
*/
|
|
262
262
|
export function commitAndDeployVersion(projectName_1, scriptEntry_1, assets_1) {
|
|
263
|
-
return __awaiter(this, arguments, void 0, function* (projectName, scriptEntry, assets, description = '', projectPath, env = 'production', minify = false, version) {
|
|
263
|
+
return __awaiter(this, arguments, void 0, function* (projectName, scriptEntry, assets, description = '', projectPath, env = 'production', minify = false, version, noBundle = false) {
|
|
264
264
|
var _a, _b, _c;
|
|
265
265
|
const projectInfo = yield validateAndInitializeProject(projectName, projectPath);
|
|
266
266
|
if (!projectInfo) {
|
|
@@ -274,7 +274,7 @@ export function commitAndDeployVersion(projectName_1, scriptEntry_1, assets_1) {
|
|
|
274
274
|
logger.endSubStep(deployed ? 'Deploy finished' : 'Deploy failed');
|
|
275
275
|
return deployed;
|
|
276
276
|
}
|
|
277
|
-
const res = yield generateCodeVersion(projectInfo.projectName, description, scriptEntry || (projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.entry), assets || ((_a = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.assets) === null || _a === void 0 ? void 0 : _a.directory), minify || (projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.minify), projectPath);
|
|
277
|
+
const res = yield generateCodeVersion(projectInfo.projectName, description, scriptEntry || (projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.entry), assets || ((_a = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.assets) === null || _a === void 0 ? void 0 : _a.directory), minify || (projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.minify), projectPath, noBundle);
|
|
278
278
|
const isCommitSuccess = res === null || res === void 0 ? void 0 : res.isSuccess;
|
|
279
279
|
if (!isCommitSuccess) {
|
|
280
280
|
logger.endSubStep('Generate version failed');
|
|
@@ -317,6 +317,32 @@ export function deployCodeVersion(name, codeVersion, environment) {
|
|
|
317
317
|
}
|
|
318
318
|
});
|
|
319
319
|
}
|
|
320
|
+
/**
|
|
321
|
+
* 部署指定的多个版本及其百分比
|
|
322
|
+
*/
|
|
323
|
+
export function deployCodeVersions(name, versions, env) {
|
|
324
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
325
|
+
const server = yield ApiService.getInstance();
|
|
326
|
+
const doDeploy = (targetEnv) => __awaiter(this, void 0, void 0, function* () {
|
|
327
|
+
const res = yield server.createRoutineCodeDeployment({
|
|
328
|
+
Name: name,
|
|
329
|
+
CodeVersions: versions.map((v) => ({
|
|
330
|
+
Percentage: v.percentage,
|
|
331
|
+
CodeVersion: v.codeVersion
|
|
332
|
+
})),
|
|
333
|
+
Strategy: 'percentage',
|
|
334
|
+
Env: targetEnv
|
|
335
|
+
});
|
|
336
|
+
return !!res;
|
|
337
|
+
});
|
|
338
|
+
if (env === 'all') {
|
|
339
|
+
const s = yield doDeploy('staging');
|
|
340
|
+
const p = yield doDeploy('production');
|
|
341
|
+
return s && p;
|
|
342
|
+
}
|
|
343
|
+
return yield doDeploy(env);
|
|
344
|
+
});
|
|
345
|
+
}
|
|
320
346
|
/**
|
|
321
347
|
* Poll routine code version status until it becomes ready
|
|
322
348
|
*/
|
|
@@ -417,3 +443,57 @@ export function displayDeploySuccess(projectName_1) {
|
|
|
417
443
|
logger.block();
|
|
418
444
|
});
|
|
419
445
|
}
|
|
446
|
+
/**
|
|
447
|
+
* 解析 --versions 参数并执行按百分比分发部署;成功后打印展示和百分比分配
|
|
448
|
+
*/
|
|
449
|
+
export function deployWithVersionPercentages(nameArg, versionsArg, env, projectPath) {
|
|
450
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
451
|
+
const raw = (versionsArg || [])
|
|
452
|
+
.flatMap((v) => String(v).split(','))
|
|
453
|
+
.map((s) => s.trim())
|
|
454
|
+
.filter(Boolean);
|
|
455
|
+
const pairs = raw.map((s) => {
|
|
456
|
+
const [codeVersion, percentStr] = s.split(':');
|
|
457
|
+
return {
|
|
458
|
+
codeVersion: codeVersion === null || codeVersion === void 0 ? void 0 : codeVersion.trim(),
|
|
459
|
+
percentage: Number((percentStr || '').trim())
|
|
460
|
+
};
|
|
461
|
+
});
|
|
462
|
+
if (pairs.length > 2) {
|
|
463
|
+
logger.error('Deploy failed: at most two versions are supported');
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
if (pairs.some((p) => !p.codeVersion || Number.isNaN(p.percentage) || p.percentage < 0)) {
|
|
467
|
+
logger.error('Deploy failed: invalid --versions format. Use v1:80,v2:20');
|
|
468
|
+
return false;
|
|
469
|
+
}
|
|
470
|
+
if (pairs.length === 1) {
|
|
471
|
+
if (pairs[0].percentage !== 100) {
|
|
472
|
+
logger.error('Deploy failed: single version must be 100%');
|
|
473
|
+
return false;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
else if (pairs.length === 2) {
|
|
477
|
+
const sum = pairs[0].percentage + pairs[1].percentage;
|
|
478
|
+
if (sum !== 100) {
|
|
479
|
+
logger.error('Deploy failed: percentages must sum to 100');
|
|
480
|
+
return false;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
const projectInfo = yield validateAndInitializeProject(nameArg, projectPath);
|
|
484
|
+
if (!projectInfo) {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
const ok = yield deployCodeVersions(projectInfo.projectName, pairs, env);
|
|
488
|
+
if (!ok)
|
|
489
|
+
return false;
|
|
490
|
+
yield displayDeploySuccess(projectInfo.projectName, true, true);
|
|
491
|
+
logger.block();
|
|
492
|
+
logger.log('📦 Versions rollout:');
|
|
493
|
+
pairs.forEach((p) => {
|
|
494
|
+
logger.log(`- ${p.codeVersion}: ${p.percentage}%`);
|
|
495
|
+
});
|
|
496
|
+
logger.block();
|
|
497
|
+
return true;
|
|
498
|
+
});
|
|
499
|
+
}
|
|
@@ -12,7 +12,7 @@ import { intro, outro } from '@clack/prompts';
|
|
|
12
12
|
import t from '../../i18n/index.js';
|
|
13
13
|
import { getRoot } from '../../utils/fileUtils/base.js';
|
|
14
14
|
import { getProjectConfig } from '../../utils/fileUtils/index.js';
|
|
15
|
-
import { commitAndDeployVersion, displayDeploySuccess } from '../common/utils.js';
|
|
15
|
+
import { commitAndDeployVersion, displayDeploySuccess, deployWithVersionPercentages } from '../common/utils.js';
|
|
16
16
|
const deploy = {
|
|
17
17
|
command: 'deploy [entry]',
|
|
18
18
|
builder: (yargs) => {
|
|
@@ -52,6 +52,15 @@ const deploy = {
|
|
|
52
52
|
alias: 'm',
|
|
53
53
|
describe: t('deploy_option_minify').d('Minify the code'),
|
|
54
54
|
type: 'boolean'
|
|
55
|
+
})
|
|
56
|
+
.option('bundle', {
|
|
57
|
+
describe: 'Bundle with esbuild (use --no-bundle to skip)',
|
|
58
|
+
type: 'boolean',
|
|
59
|
+
default: true
|
|
60
|
+
})
|
|
61
|
+
.option('versions', {
|
|
62
|
+
describe: 'Deploy two versions with percentages, format: v1:80,v2:20 or repeat --versions v1:80 --versions v2:20',
|
|
63
|
+
type: 'array'
|
|
55
64
|
});
|
|
56
65
|
},
|
|
57
66
|
describe: `🚀 ${t('deploy_describe').d('Deploy your project')}`,
|
|
@@ -65,8 +74,15 @@ export function handleDeploy(argv) {
|
|
|
65
74
|
var _a;
|
|
66
75
|
const entry = argv.entry;
|
|
67
76
|
const assets = (_a = argv.assets) !== null && _a !== void 0 ? _a : undefined;
|
|
77
|
+
const versionsArg = argv.versions || [];
|
|
68
78
|
intro(`Deploy an application with ESA`);
|
|
69
|
-
|
|
79
|
+
if (versionsArg.length > 0) {
|
|
80
|
+
const env = argv.environment || 'all';
|
|
81
|
+
const ok = yield deployWithVersionPercentages(argv.name || undefined, versionsArg, env, getRoot());
|
|
82
|
+
outro(ok ? 'Deploy finished' : 'Deploy failed');
|
|
83
|
+
exit(ok ? 0 : 1);
|
|
84
|
+
}
|
|
85
|
+
const success = yield commitAndDeployVersion(argv.name || undefined, entry, assets, argv.description || '', getRoot(), argv.environment || 'all', argv.minify, argv.version, (argv.bundle === false));
|
|
70
86
|
outro(success ? 'Deploy finished' : 'Deploy failed');
|
|
71
87
|
if (success) {
|
|
72
88
|
const projectConfig = getProjectConfig(getRoot());
|
|
@@ -17,7 +17,7 @@ const login = {
|
|
|
17
17
|
command: 'login',
|
|
18
18
|
describe: `🔑 ${t('login_describe').d('Login to the server')}`,
|
|
19
19
|
builder: (yargs) => {
|
|
20
|
-
var _a, _b;
|
|
20
|
+
var _a, _b, _c;
|
|
21
21
|
return yargs
|
|
22
22
|
.option('access-key-id', {
|
|
23
23
|
alias: 'ak',
|
|
@@ -28,6 +28,11 @@ const login = {
|
|
|
28
28
|
alias: 'sk',
|
|
29
29
|
describe: (_b = t('login_option_access_key_secret')) === null || _b === void 0 ? void 0 : _b.d('AccessKey Secret'),
|
|
30
30
|
type: 'string'
|
|
31
|
+
})
|
|
32
|
+
.option('endpoint', {
|
|
33
|
+
alias: 'e',
|
|
34
|
+
describe: (_c = t('login_option_endpoint')) === null || _c === void 0 ? void 0 : _c.d('Endpoint'),
|
|
35
|
+
type: 'string'
|
|
31
36
|
});
|
|
32
37
|
},
|
|
33
38
|
handler: (argv) => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -40,13 +45,14 @@ export function handleLogin(argv) {
|
|
|
40
45
|
generateDefaultConfig();
|
|
41
46
|
const accessKeyId = argv === null || argv === void 0 ? void 0 : argv['access-key-id'];
|
|
42
47
|
const accessKeySecret = argv === null || argv === void 0 ? void 0 : argv['access-key-secret'];
|
|
48
|
+
const endpoint = (argv === null || argv === void 0 ? void 0 : argv['endpoint']) || process.env.ESA_ENDPOINT;
|
|
43
49
|
if (accessKeyId && accessKeySecret) {
|
|
44
|
-
yield handleLoginWithAKSK(accessKeyId, accessKeySecret);
|
|
50
|
+
yield handleLoginWithAKSK(accessKeyId, accessKeySecret, endpoint);
|
|
45
51
|
return;
|
|
46
52
|
}
|
|
47
53
|
if (process.env.ESA_ACCESS_KEY_ID && process.env.ESA_ACCESS_KEY_SECRET) {
|
|
48
54
|
logger.log(`🔑 ${t('login_get_from_env').d(`Get AccessKey ID and AccessKey Secret from environment variables.`)}`);
|
|
49
|
-
yield handleLoginWithAKSK(process.env.ESA_ACCESS_KEY_ID, process.env.ESA_ACCESS_KEY_SECRET);
|
|
55
|
+
yield handleLoginWithAKSK(process.env.ESA_ACCESS_KEY_ID, process.env.ESA_ACCESS_KEY_SECRET, endpoint);
|
|
50
56
|
return;
|
|
51
57
|
}
|
|
52
58
|
const cliConfig = getCliConfig();
|
|
@@ -73,31 +79,32 @@ export function handleLogin(argv) {
|
|
|
73
79
|
if (isCancel(selected) || selected === 'exit') {
|
|
74
80
|
return;
|
|
75
81
|
}
|
|
76
|
-
yield getUserInputAuthInfo();
|
|
82
|
+
yield getUserInputAuthInfo(endpoint);
|
|
77
83
|
}
|
|
78
84
|
else {
|
|
79
85
|
logger.error(t('pre_login_failed').d('The previously entered Access Key ID (AK) and Secret Access Key (SK) are incorrect. Please enter them again.'));
|
|
80
86
|
logger.log(`${t('login_logging').d('Logging in')}...`);
|
|
81
|
-
yield getUserInputAuthInfo();
|
|
87
|
+
yield getUserInputAuthInfo(endpoint);
|
|
82
88
|
}
|
|
83
89
|
}
|
|
84
90
|
else {
|
|
85
91
|
logger.log(`${t('login_logging').d('Logging in')}...`);
|
|
86
|
-
yield getUserInputAuthInfo();
|
|
92
|
+
yield getUserInputAuthInfo(endpoint);
|
|
87
93
|
}
|
|
88
94
|
});
|
|
89
95
|
}
|
|
90
|
-
function handleLoginWithAKSK(accessKeyId, accessKeySecret) {
|
|
96
|
+
function handleLoginWithAKSK(accessKeyId, accessKeySecret, endpoint) {
|
|
91
97
|
return __awaiter(this, void 0, void 0, function* () {
|
|
92
98
|
let apiConfig = getApiConfig();
|
|
93
99
|
apiConfig.auth = {
|
|
94
100
|
accessKeyId,
|
|
95
101
|
accessKeySecret
|
|
96
102
|
};
|
|
103
|
+
if (endpoint) {
|
|
104
|
+
apiConfig.endpoint = endpoint;
|
|
105
|
+
}
|
|
97
106
|
try {
|
|
98
|
-
yield updateCliConfigFile({
|
|
99
|
-
auth: apiConfig.auth
|
|
100
|
-
});
|
|
107
|
+
yield updateCliConfigFile(Object.assign({ auth: apiConfig.auth }, (endpoint ? { endpoint } : {})));
|
|
101
108
|
const service = yield ApiService.getInstance();
|
|
102
109
|
service.updateConfig(apiConfig);
|
|
103
110
|
const loginStatus = yield service.checkLogin();
|
|
@@ -113,7 +120,7 @@ function handleLoginWithAKSK(accessKeyId, accessKeySecret) {
|
|
|
113
120
|
}
|
|
114
121
|
});
|
|
115
122
|
}
|
|
116
|
-
export function getUserInputAuthInfo() {
|
|
123
|
+
export function getUserInputAuthInfo(endpoint) {
|
|
117
124
|
return __awaiter(this, void 0, void 0, function* () {
|
|
118
125
|
const styledUrl = chalk.underline.blue('https://ram.console.aliyun.com/manage/ak');
|
|
119
126
|
logger.log(`🔑 ${chalk.underline(t('login_get_ak_sk').d(`Please go to the following link to get your account's AccessKey ID and AccessKey Secret`))}`);
|
|
@@ -127,10 +134,11 @@ export function getUserInputAuthInfo() {
|
|
|
127
134
|
accessKeyId,
|
|
128
135
|
accessKeySecret
|
|
129
136
|
};
|
|
137
|
+
if (endpoint) {
|
|
138
|
+
apiConfig.endpoint = endpoint;
|
|
139
|
+
}
|
|
130
140
|
try {
|
|
131
|
-
yield updateCliConfigFile({
|
|
132
|
-
auth: apiConfig.auth
|
|
133
|
-
});
|
|
141
|
+
yield updateCliConfigFile(Object.assign({ auth: apiConfig.auth }, (endpoint ? { endpoint } : {})));
|
|
134
142
|
const service = yield ApiService.getInstance();
|
|
135
143
|
service.updateConfig(apiConfig);
|
|
136
144
|
const loginStatus = yield service.checkLogin();
|