@cloudbase/manager-node 5.8.2 → 5.8.4

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/lib/database/index.js +11 -6
  3. package/lib/deploy/DeployOrchestrator.js +170 -278
  4. package/lib/deploy/FunctionDeployer.js +310 -52
  5. package/lib/deploy/StaticDeployer.js +7 -1
  6. package/lib/deploy/function/artifact.js +55 -41
  7. package/lib/deploy/function/builders/cloud.js +58 -359
  8. package/lib/deploy/function/cam-preflight.js +2 -1
  9. package/lib/deploy/function/cloud-build-service.js +2 -16
  10. package/lib/deploy/function/config-guard.js +210 -55
  11. package/lib/deploy/function/enterprise-tcr.js +195 -0
  12. package/lib/deploy/function/image-tag.js +31 -0
  13. package/lib/deploy/function/local-builder.js +178 -32
  14. package/lib/deploy/function/personal-tcr.js +153 -0
  15. package/lib/deploy/function/preflight.js +3 -2
  16. package/lib/deploy/types.js +11 -0
  17. package/lib/hosting/index.js +27 -0
  18. package/lib/projectValidator/index.js +22 -23
  19. package/package.json +2 -2
  20. package/types/database/index.d.ts +1 -0
  21. package/types/deploy/DeployOrchestrator.d.ts +19 -25
  22. package/types/deploy/FunctionDeployer.d.ts +35 -3
  23. package/types/deploy/StaticDeployer.d.ts +11 -0
  24. package/types/deploy/function/artifact.d.ts +0 -5
  25. package/types/deploy/function/builders/cloud.d.ts +6 -39
  26. package/types/deploy/function/config-guard.d.ts +18 -0
  27. package/types/deploy/function/enterprise-tcr.d.ts +32 -0
  28. package/types/deploy/function/image-tag.d.ts +10 -0
  29. package/types/deploy/function/local-builder.d.ts +35 -6
  30. package/types/deploy/function/personal-tcr.d.ts +35 -0
  31. package/types/deploy/types.d.ts +110 -28
  32. package/types/hosting/index.d.ts +13 -0
  33. package/types/projectValidator/index.d.ts +3 -2
  34. package/types/projectValidator/types.d.ts +0 -1
  35. package/lib/deploy/StateStore.js +0 -328
  36. package/types/deploy/StateStore.d.ts +0 -174
@@ -269,5 +269,6 @@ export declare class DatabaseService {
269
269
  * @returns 任务状态详情(TaskType、Status、Phase、Reason 等)
270
270
  */
271
271
  describeTaskResult(options: IDescribeTaskResultOptions): Promise<IDescribeTaskResultResult>;
272
+ private getDefaultDatabaseInstanceId;
272
273
  }
273
274
  export {};
@@ -1,4 +1,5 @@
1
1
  import { Environment } from '../environment';
2
+ import { IDeployProgressEvent } from './types';
2
3
  /** 可编排的资源类型 */
3
4
  export type ResourceType = 'database' | 'functions' | 'app' | 'hosting' | 'gateway';
4
5
  /** 声明式部署选项 */
@@ -18,12 +19,15 @@ export interface IDeployOptions {
18
19
  yes?: boolean;
19
20
  /** 已存在资源(函数)的覆盖更新确认回调:返回 true 部署、false 跳过(CLI 注入 autoConfirm) */
20
21
  confirmUpdate?: (item: IDeployPlanItem) => Promise<boolean>;
21
- /** 强制云端对比(漂移检测):忽略本地 state 快照的 skip 判定,强制重新对比/部署 */
22
- refresh?: boolean;
23
22
  /** 同类型资源最大并行数,默认 1(串行)。仅作用于同类型连续实例之间,跨类型依赖顺序不变 */
24
23
  concurrency?: number;
25
24
  /** 失败后继续部署其余资源(database 失败仍强制中断) */
26
25
  continueOnError?: boolean;
26
+ /** 函数资源内部部署阶段进度(校验、构建、推送、部署、等待可用、访问配置) */
27
+ onProgress?: (event: IDeployProgressEvent & {
28
+ resourceType: ResourceType;
29
+ resourceName: string;
30
+ }) => void;
27
31
  log?: {
28
32
  info?: (msg: string) => void;
29
33
  success?: (msg: string) => void;
@@ -45,13 +49,6 @@ export interface IDeployPlanItem {
45
49
  from?: string;
46
50
  to?: string;
47
51
  }>;
48
- /** hosting 文件级 diff(新增/修改/删除,前 N 条 + 统计) */
49
- fileDiff?: {
50
- added: string[];
51
- modified: string[];
52
- deleted: string[];
53
- totalChanged: number;
54
- };
55
52
  /** 资源级详情子行(dry-run 树状渲染用):如函数 runtime/构建策略、迁移逐条状态等 */
56
53
  details?: Array<{
57
54
  label: string;
@@ -66,7 +63,11 @@ export interface IDeployResult {
66
63
  name: string;
67
64
  ok: boolean;
68
65
  url?: string;
66
+ /** 资源部署器返回的结构化详情(函数包含策略、镜像、访问地址、阶段状态和耗时) */
67
+ detail?: Record<string, any>;
69
68
  error?: string;
69
+ errorCode?: string;
70
+ failedStage?: string;
70
71
  /** 原始异常中的请求 ID(若可提取),用于定位平台侧接口报错 */
71
72
  requestId?: string;
72
73
  /** 未执行原因:skip=未变更自动跳过;no-confirm=无确认机制保守跳过;skipped-by-user=用户拒绝覆盖 */
@@ -99,6 +100,11 @@ export declare class DeployOrchestrator {
99
100
  * - database 失败始终强制中断(无论是否 continueOnError)
100
101
  */
101
102
  deploy(options: IDeployOptions): Promise<IDeployResult>;
103
+ /**
104
+ * 归一化声明式函数配置:直接消费 cloudbaserc 的嵌套形状(imageConfig.build),
105
+ * 不做字段平铺映射;非 HTTP 函数原样返回。
106
+ */
107
+ private normalizeFunctionConfigs;
102
108
  /**
103
109
  * 将扁平 plan 按「连续相同资源类型」切成有序 segments
104
110
  *
@@ -107,22 +113,14 @@ export declare class DeployOrchestrator {
107
113
  * → [[db], [fnA, fnB], [hostingX, hostingY], [gateway]]
108
114
  */
109
115
  private segmentPlan;
110
- /**
111
- * 部署成功后写回本地 state 快照
112
- *
113
- * - hosting:成功部署/未变更(skip)的项重算产物指纹;失败项保留旧快照
114
- * - app:成功部署写 buildAppConfig 快照;skip 复用旧快照
115
- * - gateway:保留旧快照(本轮不做路由级实时快照)
116
- */
117
- private persistState;
118
116
  /**
119
117
  * 构建完整部署计划(按依赖顺序 + only/skip 过滤)
120
118
  *
121
119
  * 通过查询云端状态判定每个资源的动作:
122
120
  * - database:先按迁移文件做 preview,再聚合成单条资源级计划项(pending→create,存在 conflict→conflict,全部 applied→不出现在 plan)
123
121
  * - functions:ListFunctions 判断是否已存在 → create / update(不做本地 hash / 字段 diff)
124
- * - app:describeAppInfo 判断是否已存在 → create / update;本地 state 配置一致 → skip
125
- * - hosting:本地 state 指纹 diff → 一致 skip(不重新上传)/ 有差异 deploy(带文件级明细)
122
+ * - app:describeAppInfo 判断是否已存在 → create / update
123
+ * - hosting:直传覆盖(无存在性概念)
126
124
  * - gateway:planRoutes 对比云端路由 → create / update / skip(含变更字段明细)
127
125
  * 云端查询失败时降级为保守判定(全 create),不影响 dry-run 展示。
128
126
  */
@@ -136,11 +134,11 @@ export declare class DeployOrchestrator {
136
134
  */
137
135
  private buildDatabasePlan;
138
136
  /**
139
- * app 计划:本地 state 配置一致 → skip;否则按云端存在性 → create / update
137
+ * app 计划:按云端存在性 → create / update
140
138
  */
141
139
  private buildAppPlan;
142
140
  /**
143
- * hosting 计划:本地 state 指纹 diff → 一致 skip / 有差异 deploy(带文件级明细)
141
+ * hosting 计划:每次直传覆盖(无本地指纹 skip)
144
142
  */
145
143
  private buildHostingPlans;
146
144
  /**
@@ -159,10 +157,6 @@ export declare class DeployOrchestrator {
159
157
  * 执行单个计划步骤
160
158
  */
161
159
  private executeStep;
162
- /** 深比较(JSON 快照语义):仅用于 app 配置快照等简单对象 */
163
- private deepEqual;
164
- /** app 配置差异明细(from → to) */
165
- private appConfigChanges;
166
160
  /**
167
161
  * 轻量 inline 守卫:配置合法 + 目录存在(validateProject 接线点)
168
162
  */
@@ -1,6 +1,9 @@
1
1
  import { Environment } from '../environment';
2
2
  import { ICloudBuildService } from './function/builders/cloud';
3
3
  import { IImagePreflightDeps } from './function/image-preflight';
4
+ import { ILocalBuilderDeps } from './function/local-builder';
5
+ import { ITcrApiService } from './function/enterprise-tcr';
6
+ import { IPersonalTcrService } from './function/personal-tcr';
4
7
  import { ICheckReport, IFunctionDeployConfig, IFunctionDeployOptions, IFunctionDeployPlan, IFunctionDeployResult, INormalizedDeployConfig } from './types';
5
8
  interface ILegacyFunctionDeployResult {
6
9
  name: string;
@@ -16,7 +19,7 @@ interface ILegacyFunctionDeployResult {
16
19
  *
17
20
  * 已支持代码包、已有镜像、云端构建、本地构建、匿名访问与网关路径收敛;
18
21
  * 函数类型、运行时或协议等创建期字段变化时不会自动删除函数,而是引导用户
19
- * 在控制台确认并手工删除后重新部署。local 企业版 TCR 等未实现能力会显式报错。
22
+ * 在控制台确认并手工删除后重新部署。
20
23
  */
21
24
  export declare class FunctionDeployer {
22
25
  private readonly environment;
@@ -28,9 +31,15 @@ export declare class FunctionDeployer {
28
31
  * 测试可注入以替换打包/网络/tcb API,避免真实 IO
29
32
  */
30
33
  private readonly cloudBuildServiceFactory;
34
+ private readonly localBuilderDeps?;
35
+ private readonly tcrServiceFactory;
36
+ private readonly personalTcrServiceFactory;
31
37
  constructor(environment: Environment, deps?: {
32
38
  imagePreflightDeps?: IImagePreflightDeps;
33
39
  cloudBuildServiceFactory?: () => ICloudBuildService;
40
+ localBuilderDeps?: ILocalBuilderDeps;
41
+ tcrServiceFactory?: () => ITcrApiService;
42
+ personalTcrServiceFactory?: () => IPersonalTcrService;
34
43
  });
35
44
  /**
36
45
  * 兼容既有声明式部署入口
@@ -71,6 +80,20 @@ export declare class FunctionDeployer {
71
80
  * 只做纯函数、无 IO 的配置契约校验,一次返回全部问题
72
81
  */
73
82
  checkConfig(config: IFunctionDeployConfig): ICheckReport;
83
+ /**
84
+ * 计算最小化部署配置的默认值,不执行网络或云端变更。
85
+ */
86
+ applyMinimalConfigDefaults(config: IFunctionDeployConfig, context?: import('./types').IMinimalDeployConfigContext): IFunctionDeployConfig;
87
+ /**
88
+ * 返回最小化配置仍缺失的字段,不执行网络或云端变更。
89
+ */
90
+ getMissingConfigInputs(config: IFunctionDeployConfig, context?: {
91
+ envId?: string;
92
+ }): import('./types').IDeployInputField[];
93
+ /**
94
+ * 应用安全默认值并返回缺失字段,供 CLI/MCP 逐步收集用户输入。
95
+ */
96
+ prepareMinimalConfig(config: IFunctionDeployConfig, context?: import('./types').IMinimalDeployConfigContext): import('./types').IMinimalDeployConfigResult;
74
97
  /**
75
98
  * 生成部署计划
76
99
  *
@@ -101,6 +124,8 @@ export declare class FunctionDeployer {
101
124
  * 由image-preflight 自动跳过地域校验,不误报。
102
125
  */
103
126
  private resolveDeployRegion;
127
+ private resolveEnvironmentId;
128
+ private requireDeployRegion;
104
129
  /**
105
130
  * 构造镜像拉取授权 Preflight 所需的 CAM 适配器
106
131
  *
@@ -125,6 +150,8 @@ export declare class FunctionDeployer {
125
150
  * 未实现的能力必须显式报错,避免用户误认为访问规则或镜像构建已经生效
126
151
  */
127
152
  private assertPlanExecutable;
153
+ private prepareEnterpriseBuildConfig;
154
+ private preparePersonalBuildConfig;
128
155
  /**
129
156
  * 准备部署物
130
157
  *
@@ -133,14 +160,19 @@ export declare class FunctionDeployer {
133
160
  * 其余策略走同步的 pack。
134
161
  */
135
162
  private prepareArtifact;
163
+ private resolveLocalRegistryCredential;
164
+ private resolveRegistryFromRepository;
136
165
  /** 生成部署物 */
137
166
  private createArtifact;
138
167
  /** 执行部署计划 */
139
168
  private applyPlan;
140
169
  /** 收敛 HTTP 函数访问配置(匿名访问 + 网关路由) */
141
170
  private applyAccessPlan;
142
- /** 执行单个步骤并记录耗时与进度 */
171
+ /** 执行普通步骤并记录耗时与进度 */
143
172
  private runStep;
173
+ /** 执行带具体名称的步骤并记录耗时与进度 */
174
+ private runLabeledStep;
175
+ private executeStep;
144
176
  /** 上报进度,回调异常不影响部署流程 */
145
177
  private emitProgress;
146
178
  /** 汇总部署结果 */
@@ -148,7 +180,7 @@ export declare class FunctionDeployer {
148
180
  private emitProgressDone;
149
181
  }
150
182
  export * from './types';
151
- export { assertDeployConfig, checkDeployConfig, isCustomImageRuntime, normalizeDeployConfig, normalizeGatewayPath, parseImageReference } from './function/config-guard';
183
+ export { assertDeployConfig, checkDeployConfig, applyMinimalDeployConfigDefaults, getMissingDeployInputs, prepareMinimalDeployConfig, isCustomImageRuntime, normalizeDeployConfig, normalizeGatewayPath, parseImageReference } from './function/config-guard';
152
184
  export { createDeployPlan, toCurrentState } from './function/planner';
153
185
  export { createCodeArtifact, createImageArtifactFromConfig, toCloudFunction } from './function/artifact';
154
186
  export { buildImageOnCloud } from './function/builders/cloud';
@@ -28,6 +28,17 @@ export interface IHostingDeployConfig {
28
28
  ignore?: string[];
29
29
  /** 构建时环境变量(注入本地构建进程,非敏感) */
30
30
  envVariables?: Record<string, string | number | boolean>;
31
+ /**
32
+ * 多页应用(MPA)入口文件列表,相对于产物目录,默认 ["index.html"]。
33
+ * 一致性上传时用于识别入口文件(内部映射为 uploadFiles 的 entryFiles)。
34
+ */
35
+ entryFile?: string[];
36
+ /** 发布后校验远端文件与本地产物一致(开启后走一致性上传) */
37
+ verify?: boolean;
38
+ /** 发布前备份并在上传或校验失败时自动回滚(开启后走一致性上传) */
39
+ safe?: boolean;
40
+ /** 发布成功后清理远端冗余文件(危险操作,开启后走一致性上传) */
41
+ prune?: boolean;
31
42
  }
32
43
  export interface IStaticDeployResult {
33
44
  name: string;
@@ -1,10 +1,5 @@
1
1
  import { ICloudFunction } from '../../interfaces';
2
2
  import { ICodeArtifact, IFunctionArtifact, IImageArtifact, INormalizedDeployConfig, INormalizedHttpCloudConfig, INormalizedHttpImageConfig, INormalizedHttpLocalConfig } from '../types';
3
- /**
4
- * 部署物构造与 SCF 参数映射
5
- *
6
- * 四种构建策略最终都产出统一的部署物,之后走同一条 SCF 创建或更新流程
7
- */
8
3
  /** 由本地代码来源构造代码类部署物 */
9
4
  export declare function createCodeArtifact(config: INormalizedDeployConfig): ICodeArtifact;
10
5
  /** 由已有镜像配置构造镜像类部署物 */
@@ -1,5 +1,6 @@
1
1
  import { ICustomBuildEnv, ICustomBuildSecret, ICustomBuildStep, CloudAppArtifact, CloudAppBuildStep } from '../../../cloudApp/types';
2
2
  import { INormalizedHttpCloudConfig } from '../../types';
3
+ import { IEnterpriseTcrCredential } from '../enterprise-tcr';
3
4
  export interface ICloudBuildResult {
4
5
  imageUri: string;
5
6
  imageDigest?: string;
@@ -39,26 +40,13 @@ export interface ICloudVersionStatus {
39
40
  /** DescribeCloudAppVersion 接口返回的 RequestId,便于把构建问题反馈给平台后端定位 */
40
41
  requestId?: string;
41
42
  }
42
- /** 需要额外注入到构建 zip 的文件条目(zip 内路径 + 内容 + 可选 unix 权限位) */
43
- export interface ICloudBuildExtraEntry {
44
- /** zip 包内的相对路径,如 scripts/tcr-login-and-push.sh */
45
- zipPath: string;
46
- /** 文件文本内容 */
47
- content: string;
48
- /** unix 权限位(八进制),如 0o755;脚本需可执行 */
49
- mode?: number;
50
- }
51
43
  /**
52
44
  * 云端构建所需的外部能力,由编排器注入
53
45
  *每个方法对应构建方案(https://iwiki.woa.com/p/4020519533)的一个 API/IO 步骤
54
46
  */
55
47
  export interface ICloudBuildService {
56
- /**
57
- * 打包构建上下文为 ZIP,返回本地临时 zip 路径
58
- * @param cwd 构建上下文目录
59
- * @param extraEntries 额外注入zip 的文件(如 push 脚本),不写入用户源码目录
60
- */
61
- packContext: (cwd: string, extraEntries?: ICloudBuildExtraEntry[]) => Promise<string>;
48
+ /** 打包构建上下文为 ZIP,返回本地临时 zip 路径 */
49
+ packContext: (cwd: string) => Promise<string>;
62
50
  /** 获取 COS 上传凭证(DescribeCloudAppCosInfo,DeployType:custom) */
63
51
  getCosInfo: (serviceName: string) => Promise<ICloudCosInfo>;
64
52
  /** PUT 上传 zip 到 COS,必须携带全部 uploadHeaders */
@@ -72,39 +60,18 @@ export interface ICloudBuildService {
72
60
  /** 延时(便于测试注入立即返回) */
73
61
  delay: (ms: number) => Promise<void>;
74
62
  }
75
- /** 注入到构建上下文 zip 中的推送脚本相对路径(与 CustomSteps 的 push命令一致) */
76
- export declare const TCR_PUSH_SCRIPT_ZIP_PATH = "scripts/tcr-login-and-push.sh";
77
- /**
78
- * 注入到构建 zip 的 TCR/CCR 登录推送脚本(完整可运行)
79
- *
80
- * 对应构建方案(https://iwiki.woa.com/p/4020519533)「阶段 A」的 push 步骤:
81
- * push-image 步骤执行 `bash./scripts/tcr-login-and-push.sh`,该脚本必须随源码
82
- * 一同打进zip 根目录,否则云端会 `No such file or directory` 秒挂。
83
- *
84
- * 关键设计:
85
- * - 地域参数化:REGION 读环境变量 $TCR_REGION(由 buildEnv 按部署地域注入),
86
- * 避免硬编码 ap-shanghai跨地域时 AuthFailure.SignatureFailure。
87
- * - 双仓库兼容:设置了 $TCR_INSTANCE_ID 走企业版 TCR CreateInstanceToken;
88
- * 否则走个人版 CCR,用户名来自普通 Env,固定密码来自 CloudApp Secrets。
89
- * - 安全红线:凭证一律经 --password-stdin 传入,绝不出现在 ps/日志;
90
- * 不打印任何 $API_SECRET_* / token / $SECRET_TCR_PASSWORD_B64 或解码后的密码。
91
- *
92
- * 脚本内容为SDK 固定模板,不拼接任何用户输入(镜像地址等均由已校验的
93
- * 环境变量在容器内组装),无命令注入面。
94
- */
95
- export declare const TCR_LOGIN_PUSH_SCRIPT = "#!/usr/bin/env bash\n# scripts/tcr-login-and-push.sh\n# \u7531 CloudBase SDK \u81EA\u52A8\u6CE8\u5165\uFF1A\u4F01\u4E1A\u7248\u4F7F\u7528 STS \u6362\u53D6\u4E34\u65F6 token\uFF0C\u4E2A\u4EBA\u7248\u4F7F\u7528 CloudApp Secret\nset -euo pipefail\n\n: \"${TCR_REGISTRY:?TCR_REGISTRY \u672A\u8BBE\u7F6E}\"\n: \"${TCR_NAMESPACE:?TCR_NAMESPACE \u672A\u8BBE\u7F6E}\"\n: \"${CLOUDBASE_SERVICE_NAME:?\u5E73\u53F0\u53D8\u91CF\u7F3A\u5931}\"\n: \"${CLOUDBASE_VERSION_NAME:?\u5E73\u53F0\u53D8\u91CF\u7F3A\u5931}\"\n\nREGION=\"${TCR_REGION:-ap-shanghai}\"\nIMAGE=\"${TCR_REGISTRY}/${TCR_NAMESPACE}/${CLOUDBASE_SERVICE_NAME}:${CLOUDBASE_VERSION_NAME}\"\nIS_PERSONAL_REGISTRY=0\n\nif [ -n \"${TCR_INSTANCE_ID:-}\" ]; then\n : \"${API_SECRET_ID:?STS \u51ED\u8BC1\u7F3A\u5931}\"\n : \"${API_SECRET_KEY:?STS \u51ED\u8BC1\u7F3A\u5931}\"\n : \"${API_TOKEN:?STS \u51ED\u8BC1\u7F3A\u5931}\"\n\n # ---- \u4F01\u4E1A\u7248 TCR\uFF1ACreateInstanceToken \u6362\u767B\u5F55\u6001 ----\n HOST=\"tcr.tencentcloudapi.com\"\n SERVICE=\"tcr\"\n VERSION=\"2019-09-24\"\n ACTION=\"CreateInstanceToken\"\n ALGORITHM=\"TC3-HMAC-SHA256\"\n TIMESTAMP=$(date +%s)\n DATE=$(date -u -d \"@${TIMESTAMP}\" +\"%Y-%m-%d\" 2>/dev/null || date -u -r \"${TIMESTAMP}\" +\"%Y-%m-%d\")\n\n # \u6784\u5EFA\u9636\u6BB5\u53EA\u9700\u8981\u4E00\u6B21 docker login/push\uFF0C\u4F7F\u7528 1 \u5C0F\u65F6\u4E34\u65F6\u51ED\u8BC1\uFF0C\u907F\u514D\u521B\u5EFA\u957F\u671F\u51ED\u8BC1\u3002\n PAYLOAD=$(printf '{\"RegistryId\":\"%s\",\"TokenType\":\"temp\"}' \"${TCR_INSTANCE_ID}\")\n HASHED_PAYLOAD=$(printf '%s' \"${PAYLOAD}\" | openssl dgst -sha256 -hex | awk '{print $NF}')\n CANONICAL_HEADERS=\"content-type:application/json; charset=utf-8\\nhost:${HOST}\\nx-tc-action:$(echo \"${ACTION}\" | tr '[:upper:]' '[:lower:]')\\n\"\n SIGNED_HEADERS=\"content-type;host;x-tc-action\"\n CANONICAL_REQUEST=\"POST\\n/\\n\\n${CANONICAL_HEADERS}\\n${SIGNED_HEADERS}\\n${HASHED_PAYLOAD}\"\n\n CREDENTIAL_SCOPE=\"${DATE}/${SERVICE}/tc3_request\"\n HASHED_CR=$(printf \"${CANONICAL_REQUEST}\" | openssl dgst -sha256 -hex | awk '{print $NF}')\n STRING_TO_SIGN=\"${ALGORITHM}\\n${TIMESTAMP}\\n${CREDENTIAL_SCOPE}\\n${HASHED_CR}\"\n\n secret_date=$(printf '%s' \"${DATE}\" | openssl dgst -sha256 -hmac \"TC3${API_SECRET_KEY}\" -hex | awk '{print $NF}')\n secret_svc=$(printf '%s' \"${SERVICE}\" | openssl dgst -sha256 -mac HMAC -macopt hexkey:\"${secret_date}\" -hex | awk '{print $NF}')\n secret_sign=$(printf '%s' \"tc3_request\" | openssl dgst -sha256 -mac HMAC -macopt hexkey:\"${secret_svc}\" -hex | awk '{print $NF}')\n SIGNATURE=$(printf \"${STRING_TO_SIGN}\" | openssl dgst -sha256 -mac HMAC -macopt hexkey:\"${secret_sign}\" -hex | awk '{print $NF}')\n\n AUTHZ=\"${ALGORITHM} Credential=${API_SECRET_ID}/${CREDENTIAL_SCOPE}, SignedHeaders=${SIGNED_HEADERS}, Signature=${SIGNATURE}\"\n\n RESP=$(curl -sS -X POST \"https://${HOST}\" \\\n -H \"Authorization: ${AUTHZ}\" \\\n -H \"Content-Type: application/json; charset=utf-8\" \\\n -H \"Host: ${HOST}\" \\\n -H \"X-TC-Action: ${ACTION}\" \\\n -H \"X-TC-Timestamp: ${TIMESTAMP}\" \\\n -H \"X-TC-Version: ${VERSION}\" \\\n -H \"X-TC-Region: ${REGION}\" \\\n -H \"X-TC-Token: ${API_TOKEN}\" \\\n --data \"${PAYLOAD}\")\n\n # CloudApp custom Runner \u5DF2\u63D0\u4F9B awk\uFF08\u4E0A\u9762\u7684 TC3 \u7B7E\u540D\u4E5F\u4F9D\u8D56\u5B83\uFF09\uFF0C\u4F46\u4E0D\u4FDD\u8BC1\u5B89\u88C5 jq\u3002\n # \u8FD9\u91CC\u5148\u9650\u5B9A\u9876\u5C42 Response \u5BF9\u8C61\uFF0C\u518D\u89E3\u6790\u5176\u4E2D\u7684\u975E\u7A7A JSON \u5B57\u7B26\u4E32\u5B57\u6BB5\uFF1B\u51ED\u8BC1\u5B57\u6BB5\n # \u4E0D\u5141\u8BB8 JSON \u8F6C\u4E49\uFF0C\u907F\u514D\u7528 sed/grep \u5BF9\u8BA4\u8BC1\u54CD\u5E94\u505A\u5BBD\u677E\u5339\u914D\u3002\n extract_json_string() {\n local field=\"$1\"\n printf '%s' \"${RESP}\" | JSON_FIELD=\"${field}\" awk '\n BEGIN {\n field = ENVIRON[\"JSON_FIELD\"]\n quote = sprintf(\"%c\", 34)\n backslash = sprintf(\"%c\", 92)\n json = \"\"\n }\n { json = json $0 }\n END {\n response_needle = quote \"Response\" quote \"[[:space:]]*:[[:space:]]*\\{\"\n if (!match(json, response_needle)) exit 1\n response_start = RSTART + RLENGTH - 1\n response = \"\"\n depth = 0\n in_string = 0\n escaped = 0\n for (i = response_start; i <= length(json); i++) {\n ch = substr(json, i, 1)\n response = response ch\n if (in_string) {\n if (escaped) escaped = 0\n else if (ch == backslash) escaped = 1\n else if (ch == quote) in_string = 0\n continue\n }\n if (ch == quote) in_string = 1\n else if (ch == \"{\") depth++\n else if (ch == \"}\") {\n depth--\n if (depth == 0) break\n }\n }\n if (depth != 0) exit 1\n\n depth = 1\n for (i = 2; i < length(response); i++) {\n ch = substr(response, i, 1)\n if (ch == \"{\") depth++\n else if (ch == \"}\") depth--\n else if (ch == quote) {\n key = \"\"\n escaped = 0\n for (j = i + 1; j <= length(response); j++) {\n current = substr(response, j, 1)\n if (escaped) {\n escaped = 0\n key = key current\n } else if (current == backslash) {\n escaped = 1\n key = key current\n } else if (current == quote) break\n else key = key current\n }\n if (j > length(response)) exit 1\n k = j + 1\n while (substr(response, k, 1) ~ /[[:space:]]/) k++\n if (depth == 1 && substr(response, k, 1) == \":\" && key == field) {\n k++\n while (substr(response, k, 1) ~ /[[:space:]]/) k++\n if (substr(response, k, 1) != quote) exit 1\n value = \"\"\n for (k = k + 1; k <= length(response); k++) {\n current = substr(response, k, 1)\n if (current == quote) {\n if (length(value) == 0) exit 1\n printf \"%s\", value\n exit 0\n }\n if (current == backslash) exit 2\n value = value current\n }\n exit 1\n }\n i = j\n }\n }\n exit 1\n }\n '\n }\n\n extract_tcr_error_code() {\n printf '%s' \"${RESP}\" | awk '\n BEGIN {\n quote = sprintf(\"%c\", 34)\n json = \"\"\n }\n { json = json $0 }\n END {\n error_needle = quote \"Error\" quote \"[[:space:]]*:[[:space:]]*\\{\"\n if (!match(json, error_needle)) exit 1\n error_json = substr(json, RSTART + RLENGTH)\n code_needle = quote \"Code\" quote \"[[:space:]]*:[[:space:]]*\" quote\n if (!match(error_json, code_needle)) exit 1\n rest = substr(error_json, RSTART + RLENGTH)\n value = \"\"\n for (i = 1; i <= length(rest); i++) {\n ch = substr(rest, i, 1)\n if (ch == quote) {\n if (length(value) == 0) exit 1\n printf \"%s\", value\n exit 0\n }\n if (ch == backslash) exit 1\n value = value ch\n }\n exit 1\n }\n '\n }\n\n ERROR_CODE=$(extract_tcr_error_code || true)\n if [ -n \"${ERROR_CODE}\" ]; then\n case \"${ERROR_CODE}\" in\n AuthFailure*|UnauthorizedOperation*|FailedOperation.NoPermission*)\n echo \"\u4F01\u4E1A\u7248 TCR \u9274\u6743\u5931\u8D25\uFF0C\u8BF7\u786E\u8BA4\u5F53\u524D\u8EAB\u4EFD\u6709\u6743\u8BBF\u95EE\u8BE5\u5B9E\u4F8B\u5E76\u8C03\u7528 CreateInstanceToken\" >&2\n exit 42\n ;;\n ResourceNotFound*|InvalidParameterValue.RegistryId*)\n echo \"\u4F01\u4E1A\u7248 TCR \u5B9E\u4F8B\u4E0D\u5B58\u5728\u6216\u5B9E\u4F8B ID \u65E0\u6548\" >&2\n exit 43\n ;;\n *)\n echo \"\u4F01\u4E1A\u7248 TCR \u83B7\u53D6\u767B\u5F55\u51ED\u8BC1\u5931\u8D25\uFF1A${ERROR_CODE}\" >&2\n exit 1\n ;;\n esac\n fi\n\n if ! TOKEN_USER=$(extract_json_string \"Username\"); then\n ERROR_CODE=$(extract_tcr_error_code || true)\n echo \"CreateInstanceToken \u672A\u8FD4\u56DE\u6709\u6548 Username${ERROR_CODE:+\uFF0C\u9519\u8BEF\u7801\uFF1A${ERROR_CODE}}\" >&2\n exit 42\n fi\n if ! TOKEN_PASS=$(extract_json_string \"Token\"); then\n ERROR_CODE=$(extract_tcr_error_code || true)\n echo \"CreateInstanceToken \u672A\u8FD4\u56DE\u6709\u6548 Token${ERROR_CODE:+\uFF0C\u9519\u8BEF\u7801\uFF1A${ERROR_CODE}}\" >&2\n exit 42\n fi\n\n printf '%s' \"${TOKEN_PASS}\" | docker login -u \"${TOKEN_USER}\" --password-stdin \"${TCR_REGISTRY}\"\nelse\n # ---- \u4E2A\u4EBA\u7248 CCR\uFF1A\u8D26\u53F7 ID + \u56FA\u5B9A\u5BC6\u7801\uFF08Base64 \u5C01\u88C5\u540E\u7531 CloudApp Secrets \u6CE8\u5165\uFF09 ----\n IS_PERSONAL_REGISTRY=1\n : \"${TCR_USERNAME:?TCR_USERNAME \u672A\u8BBE\u7F6E}\"\n : \"${SECRET_TCR_PASSWORD_B64:?TCR_PASSWORD \u672A\u8BBE\u7F6E}\"\n printf '%s' \"${SECRET_TCR_PASSWORD_B64}\" | base64 --decode | docker login -u \"${TCR_USERNAME}\" --password-stdin \"${TCR_REGISTRY}\"\nfi\n\nPUSH_LOG=$(mktemp)\ntrap 'rm -f \"${PUSH_LOG}\"' EXIT\nset +e\ndocker push \"${IMAGE}\" 2>&1 | tee \"${PUSH_LOG}\"\nPUSH_STATUS=${PIPESTATUS[0]}\nset -e\n\nif [ \"${PUSH_STATUS}\" -ne 0 ]; then\n if [ \"${IS_PERSONAL_REGISTRY}\" -eq 1 ] && {\n grep -Fq 'LimitExceeded.ErrRepoMaxLimit' \"${PUSH_LOG}\" ||\n grep -Fq '\u7528\u6237\u4ED3\u5E93\u5DF2\u7ECF\u8FBE\u5230\u6700\u5927\u914D\u989D' \"${PUSH_LOG}\"\n }; then\n echo \"\u4E2A\u4EBA\u7248 TCR \u955C\u50CF\u4ED3\u5E93\u6570\u91CF\u5DF2\u8FBE\u5230\u5F53\u524D\u5730\u57DF\u914D\u989D\uFF0C\u65E0\u6CD5\u81EA\u52A8\u521B\u5EFA\u76EE\u6807\u4ED3\u5E93\" >&2\n exit 44\n fi\n exit 1\nfi\n\necho \"::output::tag=${CLOUDBASE_VERSION_NAME}\"\n";
96
63
  /** buildImageOnCloud 可选项 */
97
64
  export interface IBuildImageOnCloudOptions {
98
65
  /** 日志回调,用于透出构建进度(不含凭证) */
99
66
  onLog?: (line: string) => void;
100
- /** 部署地域,注入构建环境供推送脚本换取仓库登录态(跨地域必需) */
101
- region?: string;
67
+ /** 企业版 TCR 临时登录凭证,由 manager-node 在 CreateCloudApp 前换取 */
68
+ enterpriseCredential?: IEnterpriseTcrCredential;
102
69
  }
103
70
  /**
104
71
  * 执行云端构建并推送镜像
105
72
  *
106
73
  * @param config 规范化的 cloud 部署配置
107
74
  * @param service 注入的外部能力(打包/tcb API/COS 上传)
108
- * @param options 可选项:日志回调 onLog、部署地域 region
75
+ * @param options 可选项:日志回调 onLog、企业版临时登录凭证
109
76
  */
110
77
  export declare function buildImageOnCloud(config: INormalizedHttpCloudConfig, service: ICloudBuildService, options?: IBuildImageOnCloudOptions): Promise<ICloudBuildResult>;
@@ -22,6 +22,24 @@ export declare function parseImageReference(reference: string): IParsedImageRefe
22
22
  export declare function normalizeGatewayPath(input: string): string | null;
23
23
  /** 判断是否为自定义镜像运行时 */
24
24
  export declare function isCustomImageRuntime(runtime?: string): boolean;
25
+ /**
26
+ * 应用最小化镜像配置的可安全默认值,不执行 IO,不生成凭证。
27
+ * 仅填充构建上下文、仓库名、namespace 和运行时固定值;用户凭证必须显式传入。
28
+ *
29
+ * 直接在 cloudbaserc 的嵌套形状上操作:镜像字段位于 imageConfig,构建目标位于
30
+ * imageConfig.build,不再做字段平铺映射。
31
+ */
32
+ export declare function applyMinimalDeployConfigDefaults(config: IFunctionDeployConfig, context?: import('../types').IMinimalDeployConfigContext): IFunctionDeployConfig;
33
+ /**
34
+ * 返回最小化部署在当前配置下仍缺失的输入字段;不执行网络、文件或凭证操作。
35
+ */
36
+ export declare function getMissingDeployInputs(config: IFunctionDeployConfig, context?: {
37
+ envId?: string;
38
+ }): import('../types').IDeployInputField[];
39
+ /**
40
+ * 生成最小化配置准备结果:先应用安全默认值,再返回剩余缺失字段和默认值路径。
41
+ */
42
+ export declare function prepareMinimalDeployConfig(config: IFunctionDeployConfig, context?: import('../types').IMinimalDeployConfigContext): import('../types').IMinimalDeployConfigResult;
25
43
  /**
26
44
  * 规范化部署配置
27
45
  *
@@ -0,0 +1,32 @@
1
+ import { INormalizedHttpCloudConfig, INormalizedHttpLocalConfig } from '../types';
2
+ type EnterpriseBuildConfig = INormalizedHttpCloudConfig | INormalizedHttpLocalConfig;
3
+ export interface ITcrApiService {
4
+ call: (options: {
5
+ Action: string;
6
+ Param: Record<string, unknown>;
7
+ }) => Promise<any>;
8
+ }
9
+ export interface IEnterpriseTcrTarget {
10
+ registryId: string;
11
+ registry: string;
12
+ namespace: string;
13
+ repository: string;
14
+ imageRepository: string;
15
+ }
16
+ export interface IEnterpriseTcrCredential {
17
+ username: string;
18
+ token: string;
19
+ }
20
+ export declare function prepareEnterpriseTcrTarget<T extends EnterpriseBuildConfig>(config: T, options: {
21
+ envId: string;
22
+ region: string;
23
+ service: ITcrApiService;
24
+ }): Promise<{
25
+ config: T;
26
+ target: IEnterpriseTcrTarget;
27
+ }>;
28
+ export declare function createEnterpriseTcrCredential(service: ITcrApiService, registryId: string): Promise<IEnterpriseTcrCredential>;
29
+ export declare function createTcrApiService(environment: {
30
+ getCommonService: (serviceType: string, serviceVersion: string) => ITcrApiService;
31
+ }): ITcrApiService;
32
+ export {};
@@ -0,0 +1,10 @@
1
+ export interface IResolveImageTagOptions {
2
+ explicitTag?: string;
3
+ cwd: string;
4
+ now?: () => number;
5
+ readGitShortSha?: (cwd: string) => Promise<string | undefined>;
6
+ }
7
+ /**
8
+ * 生成镜像 tag:显式配置优先,其次 Git short SHA,最后回退到毫秒时间戳。
9
+ */
10
+ export declare function resolveImageTag(options: IResolveImageTagOptions): Promise<string>;
@@ -2,25 +2,54 @@ import { INormalizedHttpLocalConfig } from '../types';
2
2
  export interface ILocalBuildResult {
3
3
  imageUri: string;
4
4
  imageDigest?: string;
5
+ buildDurationMs: number;
6
+ pushDurationMs: number;
7
+ durationMs: number;
5
8
  }
6
9
  export interface IExecResult {
7
10
  ok: boolean;
8
11
  stdout: string;
9
12
  stderr: string;
10
13
  }
14
+ export interface ILocalCommandOptions {
15
+ env?: NodeJS.ProcessEnv;
16
+ input?: string;
17
+ }
11
18
  /** 可注入依赖:命令执行与文件系统检查 */
12
19
  export interface ILocalBuilderDeps {
13
- runCommand: (command: string, args: string[]) => Promise<IExecResult>;
20
+ runCommand: (command: string, args: string[], options?: ILocalCommandOptions) => Promise<IExecResult>;
14
21
  existsSync: (target: string) => boolean;
15
22
  isDirectory: (target: string) => boolean;
16
23
  isFile: (target: string) => boolean;
17
24
  }
25
+ /** 本地镜像构建阶段结果 */
26
+ export interface ILocalImageBuildResult {
27
+ imageUri: string;
28
+ buildDurationMs: number;
29
+ }
30
+ export interface ILocalBuilderOptions {
31
+ deps?: ILocalBuilderDeps;
32
+ commandOptions?: ILocalCommandOptions;
33
+ }
34
+ /** 本地构建镜像,不执行推送。 */
35
+ export declare function buildLocalImage(config: INormalizedHttpLocalConfig, onLog?: (line: string) => void, options?: ILocalBuilderOptions): Promise<ILocalImageBuildResult>;
36
+ /** 推送已构建镜像,并尽力查询远端 digest。 */
37
+ export declare function pushLocalImage(imageUri: string, onLog?: (line: string) => void, options?: ILocalBuilderOptions): Promise<{
38
+ imageDigest?: string;
39
+ pushDurationMs: number;
40
+ }>;
41
+ export declare function loginDockerRegistry(registry: string, credential: {
42
+ username: string;
43
+ secret: string;
44
+ }, options?: ILocalBuilderOptions): Promise<void>;
45
+ export declare function createTemporaryDockerConfig(): {
46
+ env: NodeJS.ProcessEnv;
47
+ cleanup: () => void;
48
+ };
18
49
  /**
19
- * 本地构建镜像并推送到目标仓库
50
+ * 本地构建镜像并推送到目标仓库。
20
51
  *
21
- * @param config 规范化的 local 部署配置
22
- * @param onLog 可选日志回调,用于透出构建输出(不含凭证)
23
- * @param deps 可注入依赖,默认真实命令与 fs;测试可传 mock
24
- * @returns 最终镜像引用与 digest
52
+ * 保留组合入口以兼容已有调用;需要实时阶段进度的编排器应分别调用
53
+ * buildLocalImage 与 pushLocalImage。
25
54
  */
26
55
  export declare function buildAndPushImage(config: INormalizedHttpLocalConfig, onLog?: (line: string) => void, deps?: ILocalBuilderDeps): Promise<ILocalBuildResult>;
@@ -0,0 +1,35 @@
1
+ import { Environment } from '../../environment';
2
+ export declare const DEFAULT_PERSONAL_TCR_REGISTRY = "ccr.ccs.tencentyun.com";
3
+ export interface IPersonalTcrService {
4
+ ensurePushTarget: (options: {
5
+ namespace: string;
6
+ repository: string;
7
+ ensureNamespace?: boolean;
8
+ ensureRepository?: boolean;
9
+ }) => Promise<void>;
10
+ cleanupTags: (options: {
11
+ namespace: string;
12
+ repository: string;
13
+ retain?: number;
14
+ }) => Promise<void>;
15
+ }
16
+ export declare class PersonalTcrService implements IPersonalTcrService {
17
+ private readonly request;
18
+ constructor(environment: Environment);
19
+ ensurePushTarget(options: {
20
+ namespace: string;
21
+ repository: string;
22
+ ensureNamespace?: boolean;
23
+ ensureRepository?: boolean;
24
+ }): Promise<void>;
25
+ cleanupTags(options: {
26
+ namespace: string;
27
+ repository: string;
28
+ retain?: number;
29
+ }): Promise<void>;
30
+ private namespaceExists;
31
+ private repositoryExists;
32
+ private createIgnoringExisting;
33
+ private listAllTags;
34
+ }
35
+ export declare function createPersonalTcrService(environment: Environment): IPersonalTcrService;