@lark-apaas/miaoda-cli 0.1.2 → 0.1.3-alpha.2a09432
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 +8 -7
- package/dist/api/app/api.js +25 -0
- package/dist/api/app/index.js +15 -0
- package/dist/api/app/schemas.js +79 -0
- package/dist/api/app/types.js +58 -0
- package/dist/api/db/api.js +361 -54
- package/dist/api/db/client.js +60 -24
- package/dist/api/db/index.js +11 -1
- package/dist/api/db/parsers.js +20 -20
- package/dist/api/db/sql-keywords.js +87 -87
- package/dist/api/deploy/api.js +60 -0
- package/dist/api/deploy/index.js +16 -0
- package/dist/api/deploy/schemas.js +105 -0
- package/dist/api/deploy/types.js +22 -0
- package/dist/api/file/api.js +89 -87
- package/dist/api/file/client.js +62 -22
- package/dist/api/file/detect.js +3 -3
- package/dist/api/file/index.js +2 -1
- package/dist/api/file/parsers.js +18 -7
- package/dist/api/index.js +7 -1
- package/dist/api/observability/api.js +52 -0
- package/dist/api/observability/index.js +16 -0
- package/dist/api/observability/schemas.js +60 -0
- package/dist/api/observability/types.js +27 -0
- package/dist/api/plugin/api.js +31 -31
- package/dist/cli/commands/app/index.js +62 -0
- package/dist/cli/commands/db/index.js +599 -59
- package/dist/cli/commands/deploy/index.js +155 -0
- package/dist/cli/commands/file/index.js +90 -62
- package/dist/cli/commands/index.js +10 -6
- package/dist/cli/commands/observability/index.js +240 -0
- package/dist/cli/commands/plugin/index.js +27 -27
- package/dist/cli/commands/shared.js +86 -10
- package/dist/cli/handlers/app/get.js +47 -0
- package/dist/cli/handlers/app/index.js +7 -0
- package/dist/cli/handlers/app/update.js +59 -0
- package/dist/cli/handlers/db/_operator.js +35 -0
- package/dist/cli/handlers/db/audit.js +303 -0
- package/dist/cli/handlers/db/changelog.js +132 -0
- package/dist/cli/handlers/db/data.js +34 -34
- package/dist/cli/handlers/db/index.js +17 -1
- package/dist/cli/handlers/db/migration.js +235 -0
- package/dist/cli/handlers/db/quota.js +68 -0
- package/dist/cli/handlers/db/recovery.js +357 -0
- package/dist/cli/handlers/db/schema.js +35 -36
- package/dist/cli/handlers/db/sql.js +70 -71
- package/dist/cli/handlers/deploy/deploy.js +84 -0
- package/dist/cli/handlers/deploy/error-log.js +60 -0
- package/dist/cli/handlers/deploy/format.js +39 -0
- package/dist/cli/handlers/deploy/get.js +71 -0
- package/dist/cli/handlers/deploy/helpers.js +41 -0
- package/dist/cli/handlers/deploy/history.js +70 -0
- package/dist/cli/handlers/deploy/index.js +14 -0
- package/dist/cli/handlers/deploy/polling.js +162 -0
- package/dist/cli/handlers/file/cp.js +31 -32
- package/dist/cli/handlers/file/index.js +3 -1
- package/dist/cli/handlers/file/ls.js +6 -7
- package/dist/cli/handlers/file/quota.js +66 -0
- package/dist/cli/handlers/file/rm.js +25 -26
- package/dist/cli/handlers/file/sign.js +4 -5
- package/dist/cli/handlers/file/stat.js +11 -11
- package/dist/cli/handlers/observability/analytics.js +212 -0
- package/dist/cli/handlers/observability/helpers.js +66 -0
- package/dist/cli/handlers/observability/index.js +12 -0
- package/dist/cli/handlers/observability/log.js +94 -0
- package/dist/cli/handlers/observability/metric.js +208 -0
- package/dist/cli/handlers/observability/trace.js +102 -0
- package/dist/cli/handlers/plugin/plugin-local.js +53 -53
- package/dist/cli/handlers/plugin/plugin.js +15 -15
- package/dist/cli/help.js +16 -16
- package/dist/main.js +13 -9
- package/dist/utils/args.js +8 -0
- package/dist/utils/colors.js +2 -2
- package/dist/utils/config.js +2 -2
- package/dist/utils/devops-error.js +28 -0
- package/dist/utils/error.js +2 -2
- package/dist/utils/git.js +29 -0
- package/dist/utils/http.js +119 -1
- package/dist/utils/index.js +15 -1
- package/dist/utils/output.js +373 -20
- package/dist/utils/poll.js +27 -0
- package/dist/utils/render.js +27 -27
- package/dist/utils/time.js +208 -0
- package/package.json +7 -5
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.handleDeployErrorLog = handleDeployErrorLog;
|
|
37
|
+
const api = __importStar(require("../../../api/index"));
|
|
38
|
+
const output_1 = require("../../../utils/output");
|
|
39
|
+
const args_1 = require("../../../utils/args");
|
|
40
|
+
const index_1 = require("../../../api/deploy/index");
|
|
41
|
+
const helpers_1 = require("./helpers");
|
|
42
|
+
/** miaoda deploy error-log <deploy-id> */
|
|
43
|
+
async function handleDeployErrorLog(opts) {
|
|
44
|
+
if (!opts.deployId)
|
|
45
|
+
(0, args_1.failArgs)('<deploy-id> 必填');
|
|
46
|
+
const appID = opts.appId;
|
|
47
|
+
(0, helpers_1.parseDeployId)(opts.deployId); // 仅校验数字形式;URL 直接用原字符串
|
|
48
|
+
const instanceID = opts.deployId;
|
|
49
|
+
const resp = await api.deploy.getErrorLog({ appID, instanceID });
|
|
50
|
+
(0, output_1.emit)({
|
|
51
|
+
data: resp.errorJobs,
|
|
52
|
+
next_cursor: null,
|
|
53
|
+
has_more: false,
|
|
54
|
+
}, index_1.errorJobSchema);
|
|
55
|
+
// pretty 模式额外打一行整体状态。
|
|
56
|
+
if (!process.stdout.isTTY)
|
|
57
|
+
return;
|
|
58
|
+
const statusText = (0, index_1.nodeStatusText)(resp.status) ?? String(resp.status);
|
|
59
|
+
process.stdout.write(`\n— pipeline status: ${statusText}\n`);
|
|
60
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatStatusMetadata = formatStatusMetadata;
|
|
4
|
+
exports.formatSimpleInstance = formatSimpleInstance;
|
|
5
|
+
exports.formatPipelineInstance = formatPipelineInstance;
|
|
6
|
+
const index_1 = require("../../../api/deploy/index");
|
|
7
|
+
function formatStatusMetadata(statusCode) {
|
|
8
|
+
return {
|
|
9
|
+
status: (0, index_1.nodeStatusText)(statusCode) ?? `unknown(${String(statusCode)})`,
|
|
10
|
+
status_code: statusCode,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function formatSimpleInstance(instance) {
|
|
14
|
+
if (instance.status === undefined)
|
|
15
|
+
return { ...instance };
|
|
16
|
+
return {
|
|
17
|
+
...instance,
|
|
18
|
+
...formatStatusMetadata(instance.status),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function formatPipelineInstance(detail) {
|
|
22
|
+
const stages = Array.isArray(detail.stages) ? detail.stages : [];
|
|
23
|
+
return {
|
|
24
|
+
...detail,
|
|
25
|
+
...formatStatusMetadata(detail.status),
|
|
26
|
+
stages: stages.map((stage) => ({
|
|
27
|
+
...stage,
|
|
28
|
+
...formatStatusMetadata(stage.status),
|
|
29
|
+
jobs: stage.jobs.map((group) => group.map((job) => ({
|
|
30
|
+
...job,
|
|
31
|
+
...formatStatusMetadata(job.status),
|
|
32
|
+
steps: job.steps?.map((step) => ({
|
|
33
|
+
...step,
|
|
34
|
+
...formatStatusMetadata(step.status),
|
|
35
|
+
})),
|
|
36
|
+
}))),
|
|
37
|
+
})),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.handleDeployGet = handleDeployGet;
|
|
37
|
+
const api = __importStar(require("../../../api/index"));
|
|
38
|
+
const output_1 = require("../../../utils/output");
|
|
39
|
+
const args_1 = require("../../../utils/args");
|
|
40
|
+
const error_1 = require("../../../utils/error");
|
|
41
|
+
const index_1 = require("../../../api/deploy/index");
|
|
42
|
+
const helpers_1 = require("./helpers");
|
|
43
|
+
const format_1 = require("./format");
|
|
44
|
+
/**
|
|
45
|
+
* 单页拉取上限:BAM listPipelineInstances 限制 1~500,取 500 让 deploy get
|
|
46
|
+
* 在最近 500 条记录里按 ID 命中。
|
|
47
|
+
*/
|
|
48
|
+
const DEPLOY_GET_LOOKUP_LIMIT = 500;
|
|
49
|
+
/**
|
|
50
|
+
* miaoda deploy get <deploy-id>
|
|
51
|
+
*
|
|
52
|
+
* BAM 没有 by-ID 的查询接口,复用 listPipelineInstances 在最近窗口里按 ID 筛一条。
|
|
53
|
+
* 命中失败时抛 DEPLOY_NOT_FOUND,提示用户用 history 查窗口。
|
|
54
|
+
*/
|
|
55
|
+
async function handleDeployGet(opts) {
|
|
56
|
+
if (!opts.deployId)
|
|
57
|
+
(0, args_1.failArgs)('<deploy-id> 必填');
|
|
58
|
+
const appID = opts.appId;
|
|
59
|
+
const deployId = (0, helpers_1.parseDeployId)(opts.deployId);
|
|
60
|
+
const resp = await api.deploy.listPipelineInstances({
|
|
61
|
+
appID,
|
|
62
|
+
limit: DEPLOY_GET_LOOKUP_LIMIT,
|
|
63
|
+
});
|
|
64
|
+
const instance = resp.instances?.find((it) => Number(it.ID) === deployId);
|
|
65
|
+
if (!instance) {
|
|
66
|
+
throw new error_1.AppError('DEPLOY_NOT_FOUND', `未在最近 ${String(DEPLOY_GET_LOOKUP_LIMIT)} 条记录中找到 deploy-id=${opts.deployId}`, {
|
|
67
|
+
next_actions: ['运行 `miaoda deploy history` 确认 deploy-id 是否在最近窗口内'],
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
(0, output_1.emit)({ data: (0, format_1.formatSimpleInstance)(instance), next_cursor: null, has_more: false }, index_1.deployGetSchema);
|
|
71
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseStatusFlag = parseStatusFlag;
|
|
4
|
+
exports.validateLimit = validateLimit;
|
|
5
|
+
exports.parseDeployId = parseDeployId;
|
|
6
|
+
const args_1 = require("../../../utils/args");
|
|
7
|
+
const index_1 = require("../../../api/deploy/index");
|
|
8
|
+
/**
|
|
9
|
+
* 把 CLI --status 字符串映射成 BAM NodeStatus 数字;非法值抛 ARGS_INVALID。
|
|
10
|
+
*
|
|
11
|
+
* 历史接口(CliListPipelineInstances)返回 SimpleInstance,状态语义是 pipeline 节点状态,
|
|
12
|
+
* 取值 todo / running / success / failed / canceled / hold_on。
|
|
13
|
+
*/
|
|
14
|
+
function parseStatusFlag(text) {
|
|
15
|
+
const value = (0, index_1.nodeStatusFromText)(text);
|
|
16
|
+
if (value === undefined) {
|
|
17
|
+
(0, args_1.failArgs)(`--status 无效:'${text}'。可选值:todo | running | success | failed | canceled | hold_on`);
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
/** limit/pageSize 校验(API 限制 1~100) */
|
|
22
|
+
function validateLimit(limit, defaultLimit = 50) {
|
|
23
|
+
const n = Number.isFinite(limit) ? limit : defaultLimit;
|
|
24
|
+
if (n <= 0 || n > 100) {
|
|
25
|
+
(0, args_1.failArgs)(`--limit 必须在 1~100 之间,收到 ${String(n)}`);
|
|
26
|
+
}
|
|
27
|
+
return n;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 把 CLI <deploy-id> 字符串转成 i64 number。
|
|
31
|
+
*
|
|
32
|
+
* 语义上 deploy-id 即 pipelineTaskID(pipeline 实例 ID);BAM CLIGetReleaseLogs
|
|
33
|
+
* IDL 历史命名为 releaseID,但传入的就是这同一个值。
|
|
34
|
+
*/
|
|
35
|
+
function parseDeployId(text) {
|
|
36
|
+
const n = Number(text);
|
|
37
|
+
if (!Number.isFinite(n) || !/^\d+$/.test(text)) {
|
|
38
|
+
(0, args_1.failArgs)(`<deploy-id> 必须是数字 ID,收到 '${text}'`);
|
|
39
|
+
}
|
|
40
|
+
return n;
|
|
41
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.handleDeployHistory = handleDeployHistory;
|
|
37
|
+
const api = __importStar(require("../../../api/index"));
|
|
38
|
+
const output_1 = require("../../../utils/output");
|
|
39
|
+
const time_1 = require("../../../utils/time");
|
|
40
|
+
const index_1 = require("../../../api/deploy/index");
|
|
41
|
+
const helpers_1 = require("./helpers");
|
|
42
|
+
const format_1 = require("./format");
|
|
43
|
+
/** miaoda deploy history */
|
|
44
|
+
async function handleDeployHistory(opts) {
|
|
45
|
+
const appID = opts.appId;
|
|
46
|
+
const limit = (0, helpers_1.validateLimit)(opts.limit ?? 50);
|
|
47
|
+
const req = {
|
|
48
|
+
appID,
|
|
49
|
+
limit,
|
|
50
|
+
pageToken: opts.cursor,
|
|
51
|
+
};
|
|
52
|
+
if (opts.status)
|
|
53
|
+
req.status = [(0, helpers_1.parseStatusFlag)(opts.status)];
|
|
54
|
+
// BAM startTimestamp / endTimestamp 单位是秒(IDL desc:单位:秒)
|
|
55
|
+
if (opts.since !== undefined)
|
|
56
|
+
req.startTimestamp = msToSec((0, time_1.parseToMs)(opts.since));
|
|
57
|
+
if (opts.until !== undefined)
|
|
58
|
+
req.endTimestamp = msToSec((0, time_1.parseToMs)(opts.until));
|
|
59
|
+
const resp = await api.deploy.listPipelineInstances(req);
|
|
60
|
+
(0, output_1.emit)({
|
|
61
|
+
data: (resp.instances ?? []).map(format_1.formatSimpleInstance),
|
|
62
|
+
next_cursor: resp.hasMore ? (resp.nextPageToken ?? null) : null,
|
|
63
|
+
has_more: resp.hasMore ?? false,
|
|
64
|
+
}, index_1.deployHistorySchema);
|
|
65
|
+
}
|
|
66
|
+
function msToSec(ms) {
|
|
67
|
+
if (ms === undefined)
|
|
68
|
+
return undefined;
|
|
69
|
+
return Math.floor(ms / 1000);
|
|
70
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_POLL_INTERVAL_MS = exports.waitForPipeline = exports.handleDeployErrorLog = exports.handleDeployHistory = exports.handleDeployGet = exports.handleDeploy = void 0;
|
|
4
|
+
var deploy_1 = require("./deploy");
|
|
5
|
+
Object.defineProperty(exports, "handleDeploy", { enumerable: true, get: function () { return deploy_1.handleDeploy; } });
|
|
6
|
+
var get_1 = require("./get");
|
|
7
|
+
Object.defineProperty(exports, "handleDeployGet", { enumerable: true, get: function () { return get_1.handleDeployGet; } });
|
|
8
|
+
var history_1 = require("./history");
|
|
9
|
+
Object.defineProperty(exports, "handleDeployHistory", { enumerable: true, get: function () { return history_1.handleDeployHistory; } });
|
|
10
|
+
var error_log_1 = require("./error-log");
|
|
11
|
+
Object.defineProperty(exports, "handleDeployErrorLog", { enumerable: true, get: function () { return error_log_1.handleDeployErrorLog; } });
|
|
12
|
+
var polling_1 = require("./polling");
|
|
13
|
+
Object.defineProperty(exports, "waitForPipeline", { enumerable: true, get: function () { return polling_1.waitForPipeline; } });
|
|
14
|
+
Object.defineProperty(exports, "DEFAULT_POLL_INTERVAL_MS", { enumerable: true, get: function () { return polling_1.DEFAULT_POLL_INTERVAL_MS; } });
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.DEFAULT_POLL_INTERVAL_MS = void 0;
|
|
40
|
+
exports.waitForPipeline = waitForPipeline;
|
|
41
|
+
const ora_1 = __importDefault(require("ora"));
|
|
42
|
+
const api = __importStar(require("../../../api/index"));
|
|
43
|
+
const error_1 = require("../../../utils/error");
|
|
44
|
+
const output_1 = require("../../../utils/output");
|
|
45
|
+
const index_1 = require("../../../api/deploy/index");
|
|
46
|
+
/** 默认轮询间隔(毫秒) */
|
|
47
|
+
exports.DEFAULT_POLL_INTERVAL_MS = 2_000;
|
|
48
|
+
const TERMINAL_STATUSES = [
|
|
49
|
+
index_1.NodeStatus.SUCCESS,
|
|
50
|
+
index_1.NodeStatus.FAILED,
|
|
51
|
+
index_1.NodeStatus.CANCELED,
|
|
52
|
+
];
|
|
53
|
+
function defaultSleep(ms) {
|
|
54
|
+
return new Promise((res) => setTimeout(res, ms));
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 轮询 pipeline 状态直到终态或超时。
|
|
58
|
+
*
|
|
59
|
+
* - JSON 模式:轮询期间静默;终态后由 caller 输出最终信封。
|
|
60
|
+
* - Pretty 非 TTY:同 JSON。
|
|
61
|
+
* - Pretty TTY:底部行用 braille spinner 显示当前正在跑的 stage(每 80ms 跳一帧),
|
|
62
|
+
* stage 转终态时把 ✓ stage(12.3s) 打到 spinner 上方然后清掉 spinner 行。
|
|
63
|
+
*
|
|
64
|
+
* 终态返回最终 PipelineInstance,调用方再决定怎么 emit。
|
|
65
|
+
*/
|
|
66
|
+
async function waitForPipeline(opts) {
|
|
67
|
+
const interval = opts.intervalMs ?? exports.DEFAULT_POLL_INTERVAL_MS;
|
|
68
|
+
const timeoutMs = opts.timeoutSec * 1000;
|
|
69
|
+
const sleep = opts.sleep ?? defaultSleep;
|
|
70
|
+
const now = opts.now ?? Date.now;
|
|
71
|
+
const start = now();
|
|
72
|
+
// ora 自身在非 TTY 下会降级为不动画,但我们额外加 isJsonMode 闸门:JSON / 字段选择
|
|
73
|
+
// 模式下完全静默。
|
|
74
|
+
const showProgress = !(0, output_1.isJsonMode)() && process.stdout.isTTY;
|
|
75
|
+
const printedStages = new Set();
|
|
76
|
+
const spinner = showProgress
|
|
77
|
+
? (0, ora_1.default)({ text: '等待调度', spinner: 'dots', stream: process.stdout }).start()
|
|
78
|
+
: null;
|
|
79
|
+
try {
|
|
80
|
+
for (;;) {
|
|
81
|
+
const resp = await api.deploy.queryPipelineInstance({
|
|
82
|
+
appID: opts.appID,
|
|
83
|
+
instanceID: opts.pipelineTaskID,
|
|
84
|
+
});
|
|
85
|
+
const detail = normalizePipelineInstance(resp);
|
|
86
|
+
if (spinner)
|
|
87
|
+
advanceProgress(detail, printedStages, spinner);
|
|
88
|
+
if (TERMINAL_STATUSES.includes(detail.status)) {
|
|
89
|
+
return detail;
|
|
90
|
+
}
|
|
91
|
+
if (now() - start >= timeoutMs) {
|
|
92
|
+
throw new error_1.AppError('DEPLOY_TIMEOUT', `轮询发布状态超时(${String(opts.timeoutSec)}s)`, {
|
|
93
|
+
retryable: true,
|
|
94
|
+
next_actions: [
|
|
95
|
+
`Run \`miaoda deploy get <deploy-id>\` 查看最新状态`,
|
|
96
|
+
`加大 --timeout 后重试`,
|
|
97
|
+
],
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
await sleep(interval);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
spinner?.stop();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 每轮 poll 的进度推进:刚转终态的 stage 用 stopAndPersist 落定为永久行,
|
|
109
|
+
* 再把 spinner 文本切到当前 running stage;没有 running 时显示"等待调度"。
|
|
110
|
+
*/
|
|
111
|
+
function advanceProgress(detail, printed, spinner) {
|
|
112
|
+
const stages = Array.isArray(detail.stages) ? detail.stages : [];
|
|
113
|
+
for (const stage of stages) {
|
|
114
|
+
if (printed.has(stage.id))
|
|
115
|
+
continue;
|
|
116
|
+
if (!TERMINAL_STATUSES.includes(stage.status))
|
|
117
|
+
continue;
|
|
118
|
+
spinner.stopAndPersist({
|
|
119
|
+
symbol: stageSymbol(stage),
|
|
120
|
+
text: formatStageBody(stage),
|
|
121
|
+
});
|
|
122
|
+
printed.add(stage.id);
|
|
123
|
+
}
|
|
124
|
+
const running = stages.find((s) => s.status === index_1.NodeStatus.RUNNING);
|
|
125
|
+
const text = running ? `${running.name} 执行中` : '等待调度';
|
|
126
|
+
if (spinner.isSpinning) {
|
|
127
|
+
spinner.text = text;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
spinner.start(text);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function normalizePipelineInstance(resp) {
|
|
134
|
+
const keyedDetail = readPipelineDetail(resp, 'pipelineInstanceDetail') ?? readPipelineDetail(resp, 'detail');
|
|
135
|
+
if (keyedDetail)
|
|
136
|
+
return keyedDetail;
|
|
137
|
+
if (isPipelineInstance(resp))
|
|
138
|
+
return resp;
|
|
139
|
+
throw new error_1.AppError('DEPLOY_RESPONSE_INVALID', '发布状态响应缺少 pipeline detail', {
|
|
140
|
+
next_actions: ['使用 --verbose 重试以查看请求 logid,并联系平台排查响应结构'],
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
function readPipelineDetail(resp, key) {
|
|
144
|
+
if (!(key in resp))
|
|
145
|
+
return undefined;
|
|
146
|
+
const detail = resp[key];
|
|
147
|
+
return isPipelineInstance(detail) ? detail : undefined;
|
|
148
|
+
}
|
|
149
|
+
function isPipelineInstance(value) {
|
|
150
|
+
if (typeof value !== 'object' || value === null)
|
|
151
|
+
return false;
|
|
152
|
+
const item = value;
|
|
153
|
+
return typeof item.status === 'number';
|
|
154
|
+
}
|
|
155
|
+
function stageSymbol(stage) {
|
|
156
|
+
return stage.status === index_1.NodeStatus.SUCCESS ? '✓' : stage.status === index_1.NodeStatus.FAILED ? '✗' : '•';
|
|
157
|
+
}
|
|
158
|
+
function formatStageBody(stage) {
|
|
159
|
+
const cost = stage.costTime >= 0 ? `(${(stage.costTime / 1000).toFixed(1)}s)` : '';
|
|
160
|
+
const status = (0, index_1.nodeStatusText)(stage.status) ?? String(stage.status);
|
|
161
|
+
return `${stage.name}${cost ? ` ${cost}` : ''} ${status}`.trim();
|
|
162
|
+
}
|
|
@@ -44,7 +44,6 @@ const api = __importStar(require("../../../api/index"));
|
|
|
44
44
|
const output_1 = require("../../../utils/output");
|
|
45
45
|
const render_1 = require("../../../utils/render");
|
|
46
46
|
const error_1 = require("../../../utils/error");
|
|
47
|
-
const shared_1 = require("../../../cli/commands/shared");
|
|
48
47
|
const colors_1 = require("../../../utils/colors");
|
|
49
48
|
const MAX_UPLOAD_BYTES = 100 * 1024 * 1024;
|
|
50
49
|
/**
|
|
@@ -57,9 +56,9 @@ const MAX_UPLOAD_BYTES = 100 * 1024 * 1024;
|
|
|
57
56
|
* 不存在即远程 path(download,由 resolveRemotePath 处理)。
|
|
58
57
|
*/
|
|
59
58
|
function isLocalSrc(src) {
|
|
60
|
-
if (src.startsWith(
|
|
59
|
+
if (src.startsWith('./') || src.startsWith('../') || src.startsWith('~/'))
|
|
61
60
|
return true;
|
|
62
|
-
if (!src.includes(
|
|
61
|
+
if (!src.includes('/'))
|
|
63
62
|
return true;
|
|
64
63
|
// `/` 开头:可能是本地绝对路径,也可能是远程 path;交给 fs 探测。
|
|
65
64
|
const expanded = expandHome(src);
|
|
@@ -71,38 +70,38 @@ function isLocalSrc(src) {
|
|
|
71
70
|
}
|
|
72
71
|
}
|
|
73
72
|
function expandHome(p) {
|
|
74
|
-
if (p.startsWith(
|
|
73
|
+
if (p.startsWith('~/'))
|
|
75
74
|
return node_path_1.default.join(node_os_1.default.homedir(), p.slice(2));
|
|
76
75
|
return p;
|
|
77
76
|
}
|
|
78
77
|
function detectMime(filePath) {
|
|
79
78
|
const ext = node_path_1.default.extname(filePath).toLowerCase();
|
|
80
79
|
const map = {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
80
|
+
'.png': 'image/png',
|
|
81
|
+
'.jpg': 'image/jpeg',
|
|
82
|
+
'.jpeg': 'image/jpeg',
|
|
83
|
+
'.gif': 'image/gif',
|
|
84
|
+
'.webp': 'image/webp',
|
|
85
|
+
'.svg': 'image/svg+xml',
|
|
86
|
+
'.pdf': 'application/pdf',
|
|
87
|
+
'.json': 'application/json',
|
|
88
|
+
'.csv': 'text/csv',
|
|
89
|
+
'.txt': 'text/plain',
|
|
90
|
+
'.html': 'text/html',
|
|
91
|
+
'.zip': 'application/zip',
|
|
92
|
+
'.tar': 'application/x-tar',
|
|
93
|
+
'.gz': 'application/gzip',
|
|
94
|
+
'.mp4': 'video/mp4',
|
|
95
|
+
'.mp3': 'audio/mpeg',
|
|
97
96
|
};
|
|
98
|
-
return map[ext] ??
|
|
97
|
+
return map[ext] ?? 'application/octet-stream';
|
|
99
98
|
}
|
|
100
99
|
/** 把 src 的远程形式(`/path` / `file_name`)解析成后端 sign 可用的 remote path。 */
|
|
101
100
|
async function resolveRemotePath(appId, input) {
|
|
102
|
-
if (input.startsWith(
|
|
101
|
+
if (input.startsWith('/'))
|
|
103
102
|
return input;
|
|
104
103
|
const [resolved] = await api.file.resolveInputs({ appId, inputs: [input] });
|
|
105
|
-
if (resolved.status ===
|
|
104
|
+
if (resolved.status === 'error') {
|
|
106
105
|
throw new error_1.AppError(resolved.error.code, resolved.error.message, {
|
|
107
106
|
next_actions: resolved.error.hint ? [resolved.error.hint] : undefined,
|
|
108
107
|
});
|
|
@@ -112,15 +111,15 @@ async function resolveRemotePath(appId, input) {
|
|
|
112
111
|
async function handleUpload(appId, localRaw, remoteRaw, rename) {
|
|
113
112
|
const localPath = expandHome(localRaw);
|
|
114
113
|
if (!node_fs_1.default.existsSync(localPath) || !node_fs_1.default.statSync(localPath).isFile()) {
|
|
115
|
-
throw new error_1.AppError(
|
|
114
|
+
throw new error_1.AppError('FILE_SRC_NOT_FOUND', `Local file '${localRaw}' does not exist`, {
|
|
116
115
|
// 引导本地路径自检;远程下载请用 `/path` 形态,避免裸名/相对路径误入上传分支
|
|
117
|
-
next_actions: [
|
|
116
|
+
next_actions: ['Check the local file path; use `/path` prefix for remote download.'],
|
|
118
117
|
});
|
|
119
118
|
}
|
|
120
119
|
const stat = node_fs_1.default.statSync(localPath);
|
|
121
120
|
if (stat.size > MAX_UPLOAD_BYTES) {
|
|
122
|
-
throw new error_1.AppError(
|
|
123
|
-
next_actions: [
|
|
121
|
+
throw new error_1.AppError('FILE_SIZE_EXCEEDED', `File size ${(0, render_1.formatSize)(stat.size)} exceeds the 100 MB upload limit`, {
|
|
122
|
+
next_actions: ['Split the file, or use the web console for large uploads.'],
|
|
124
123
|
});
|
|
125
124
|
}
|
|
126
125
|
// PRD:path 末段**始终**由平台生成 16 位 ID 确保唯一,不受 dst 形态或
|
|
@@ -135,12 +134,12 @@ async function handleUpload(appId, localRaw, remoteRaw, rename) {
|
|
|
135
134
|
// 完整对象 key 模式。--rename 始终覆盖 file_name 推断结果(PRD 优先级)。
|
|
136
135
|
let fileName;
|
|
137
136
|
let remotePath;
|
|
138
|
-
if (remoteRaw ===
|
|
137
|
+
if (remoteRaw === '' || remoteRaw.endsWith('/')) {
|
|
139
138
|
fileName = rename ?? node_path_1.default.basename(localPath);
|
|
140
139
|
remotePath = remoteRaw;
|
|
141
140
|
}
|
|
142
141
|
else {
|
|
143
|
-
const lastSlash = remoteRaw.lastIndexOf(
|
|
142
|
+
const lastSlash = remoteRaw.lastIndexOf('/');
|
|
144
143
|
fileName = rename ?? remoteRaw.slice(lastSlash + 1);
|
|
145
144
|
remotePath = remoteRaw.slice(0, lastSlash + 1);
|
|
146
145
|
}
|
|
@@ -188,7 +187,7 @@ async function handleUpload(appId, localRaw, remoteRaw, rename) {
|
|
|
188
187
|
lines.push(`download_url\t${result.download_url}`);
|
|
189
188
|
}
|
|
190
189
|
}
|
|
191
|
-
(0, output_1.emit)(lines.join(
|
|
190
|
+
(0, output_1.emit)(lines.join('\n'));
|
|
192
191
|
}
|
|
193
192
|
async function handleDownload(appId, remoteRaw, localRaw) {
|
|
194
193
|
const filePath = await resolveRemotePath(appId, remoteRaw);
|
|
@@ -199,7 +198,7 @@ async function handleDownload(appId, remoteRaw, localRaw) {
|
|
|
199
198
|
});
|
|
200
199
|
const baseName = node_path_1.default.basename(filePath);
|
|
201
200
|
let localTarget = expandHome(localRaw);
|
|
202
|
-
if (localTarget ===
|
|
201
|
+
if (localTarget === './' || localTarget === '.' || localTarget.endsWith('/')) {
|
|
203
202
|
localTarget = node_path_1.default.join(localTarget, baseName);
|
|
204
203
|
}
|
|
205
204
|
else if (node_fs_1.default.existsSync(localTarget) && node_fs_1.default.statSync(localTarget).isDirectory()) {
|
|
@@ -233,7 +232,7 @@ async function handleDownload(appId, remoteRaw, localRaw) {
|
|
|
233
232
|
}
|
|
234
233
|
}
|
|
235
234
|
async function handleFileCp(src, dst, opts) {
|
|
236
|
-
const appId =
|
|
235
|
+
const appId = opts.appId;
|
|
237
236
|
// src 本地存在 → upload;其他情况(file_ref / `/path` / 裸文件名)→ download
|
|
238
237
|
if (isLocalSrc(src)) {
|
|
239
238
|
return handleUpload(appId, src, dst, opts.rename);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.handleFileSign = exports.handleFileRm = exports.handleFileCp = exports.handleFileStat = exports.handleFileLs = void 0;
|
|
3
|
+
exports.handleFileQuota = exports.handleFileSign = exports.handleFileRm = exports.handleFileCp = exports.handleFileStat = exports.handleFileLs = void 0;
|
|
4
4
|
var ls_1 = require("./ls");
|
|
5
5
|
Object.defineProperty(exports, "handleFileLs", { enumerable: true, get: function () { return ls_1.handleFileLs; } });
|
|
6
6
|
var stat_1 = require("./stat");
|
|
@@ -11,3 +11,5 @@ var rm_1 = require("./rm");
|
|
|
11
11
|
Object.defineProperty(exports, "handleFileRm", { enumerable: true, get: function () { return rm_1.handleFileRm; } });
|
|
12
12
|
var sign_1 = require("./sign");
|
|
13
13
|
Object.defineProperty(exports, "handleFileSign", { enumerable: true, get: function () { return sign_1.handleFileSign; } });
|
|
14
|
+
var quota_1 = require("./quota");
|
|
15
|
+
Object.defineProperty(exports, "handleFileQuota", { enumerable: true, get: function () { return quota_1.handleFileQuota; } });
|