From d05724d0ed9113ed1343620150a23e30be6087f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E9=AD=8F=E6=B4=AA?= Date: Wed, 6 May 2026 11:29:41 +0800 Subject: [PATCH] fix: build runit --- __tests__/ut/commands/model_test.ts | 2 +- package-lock.json | 124 ++++++++++++++++++ package.json | 5 + publish.yaml | 2 +- src/commands-help/build.ts | 12 +- src/commands-help/index.ts | 2 + src/commands-help/model.ts | 6 +- src/index.ts | 4 + src/interface/index.ts | 1 + src/subCommands/build/index.ts | 100 ++++++++++++++ src/subCommands/build/runit/index.ts | 43 ++++++ .../build/runit/interface/index.ts | 29 ++++ src/subCommands/model/index.ts | 4 +- 13 files changed, 326 insertions(+), 8 deletions(-) create mode 100644 src/subCommands/build/runit/index.ts create mode 100644 src/subCommands/build/runit/interface/index.ts diff --git a/__tests__/ut/commands/model_test.ts b/__tests__/ut/commands/model_test.ts index 9eba5f65..db4bc5b8 100644 --- a/__tests__/ut/commands/model_test.ts +++ b/__tests__/ut/commands/model_test.ts @@ -146,7 +146,7 @@ describe('Model', () => { }); expect(() => new Model(mockInputs)).toThrow( - 'Command "invalid" not found, Please use "s cli fc3 layer -h" to query how to use the command', + 'Command "invalid" not found, Please use "s cli fc3 model -h" to query how to use the command', ); }); }); diff --git a/package-lock.json b/package-lock.json index 604ddee6..b947601b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@serverless-cd/srm-aliyun-ram20150501": "^0.0.2-beta.9", "@serverless-cd/srm-aliyun-sls20201230": "0.0.5-beta.3", "@serverless-devs/diff": "^0.0.3-beta.6", + "@serverless-devs/docker-image-builder": "^0.0.0-20260518-164317-160dd89efac1", "@serverless-devs/downloads": "^0.0.7", "@serverless-devs/load-component": "^0.0.9", "@serverless-devs/utils": "^0.0.17", @@ -41,6 +42,7 @@ "string-random": "^0.1.3", "temp-dir": "^2.0.0", "tty-table": "^4.2.3", + "undici": "^5.28.5", "uuid": "^9.0.1", "uuid-by-string": "^4.0.0" }, @@ -1908,6 +1910,15 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.5.0", "resolved": "https://registry.npmmirror.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", @@ -2665,6 +2676,17 @@ "lodash": "^4.17.21" } }, + "node_modules/@serverless-devs/docker-image-builder": { + "version": "0.0.0-20260518-164317-160dd89efac1", + "resolved": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/@serverless-devs/docker-image-builder/-/@serverless-devs/docker-image-builder-0.0.0-20260518-164317-160dd89efac1.tgz", + "integrity": "sha512-apRIF4jQlkhMbaMdAYES50WvEhcAQcRiXQ0ZwnuN7OPoSocfWv9cDQA7Swti1zId4YkT3MnTSAVZpB3+6jy3Pw==", + "dependencies": { + "node-fetch": "^2.7.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@serverless-devs/downloads": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/@serverless-devs/downloads/-/downloads-0.0.7.tgz", @@ -11160,6 +11182,26 @@ "debug": "^2.1.0" } }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-hex": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/node-hex/-/node-hex-1.0.1.tgz", @@ -14054,6 +14096,12 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, "node_modules/trim-newlines": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/trim-newlines/-/trim-newlines-3.0.1.tgz", @@ -14673,6 +14721,18 @@ "through": "^2.3.8" } }, + "node_modules/undici": { + "version": "5.29.0", + "resolved": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/undici/-/undici-5.29.0.tgz", + "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, "node_modules/undici-types": { "version": "6.19.8", "resolved": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/undici-types/-/undici-types-6.19.8.tgz", @@ -15132,6 +15192,22 @@ "defaults": "^1.0.3" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/which/-/which-2.0.2.tgz", @@ -17011,6 +17087,11 @@ } } }, + "@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==" + }, "@humanwhocodes/config-array": { "version": "0.5.0", "resolved": "https://registry.npmmirror.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", @@ -17597,6 +17678,14 @@ "lodash": "^4.17.21" } }, + "@serverless-devs/docker-image-builder": { + "version": "0.0.0-20260518-164317-160dd89efac1", + "resolved": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/@serverless-devs/docker-image-builder/-/@serverless-devs/docker-image-builder-0.0.0-20260518-164317-160dd89efac1.tgz", + "integrity": "sha512-apRIF4jQlkhMbaMdAYES50WvEhcAQcRiXQ0ZwnuN7OPoSocfWv9cDQA7Swti1zId4YkT3MnTSAVZpB3+6jy3Pw==", + "requires": { + "node-fetch": "^2.7.0" + } + }, "@serverless-devs/downloads": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/@serverless-devs/downloads/-/downloads-0.0.7.tgz", @@ -23749,6 +23838,14 @@ "debug": "^2.1.0" } }, + "node-fetch": { + "version": "2.7.0", + "resolved": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, "node-hex": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/node-hex/-/node-hex-1.0.1.tgz", @@ -25798,6 +25895,11 @@ "is-number": "^7.0.0" } }, + "tr46": { + "version": "0.0.3", + "resolved": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "trim-newlines": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/trim-newlines/-/trim-newlines-3.0.1.tgz", @@ -26198,6 +26300,14 @@ "through": "^2.3.8" } }, + "undici": { + "version": "5.29.0", + "resolved": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/undici/-/undici-5.29.0.tgz", + "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "requires": { + "@fastify/busboy": "^2.0.0" + } + }, "undici-types": { "version": "6.19.8", "resolved": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/undici-types/-/undici-types-6.19.8.tgz", @@ -26502,6 +26612,20 @@ "defaults": "^1.0.3" } }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index afb14869..d0d623e4 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,8 @@ "temp-dir": "^2.0.0", "tty-table": "^4.2.3", "uuid": "^9.0.1", + "undici": "^5.28.5", + "@serverless-devs/docker-image-builder": "^0.0.0-20260518-164317-160dd89efac1", "uuid-by-string": "^4.0.0" }, "devDependencies": { @@ -76,6 +78,9 @@ "resolutions": { "@alicloud/sls20191023": { "registry": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/" + }, + "@serverless-devs/docker-image-builder": { + "registry": "https://packages.aliyun.com/670e108663cd360abfe4be65/npm/npm-registry/" } } } diff --git a/publish.yaml b/publish.yaml index 79f79f37..4c1a0c2b 100644 --- a/publish.yaml +++ b/publish.yaml @@ -3,7 +3,7 @@ Type: Component Name: fc3 Provider: - 阿里云 -Version: 0.1.20 +Version: 0.1.21 Description: 阿里云函数计算全生命周期管理 HomePage: https://github.com/devsapp/fc3 Organization: 阿里云函数计算(FC) diff --git a/src/commands-help/build.ts b/src/commands-help/build.ts index 43157c82..16bc8193 100644 --- a/src/commands-help/build.ts +++ b/src/commands-help/build.ts @@ -8,7 +8,9 @@ Examples: $ s build --dockerfile ./code/Dockerfile --context ./code $ s build --custom-env "{\\"myenv\\": \\"test\\"}" --custom-args="-i https://pypi.tuna.tsinghua.edu.cn/simple" $ s build --command="pip install -t . flask -i https://pypi.tuna.tsinghua.edu.cn/simple" - $ s build --script-file my_script.sh`, + $ s build --script-file my_script.sh + $ s build --cloud-build-config fc3-cloud-build.yaml + $ s build --cloud-build-config fc3-cloud-build.yaml --debug-instance`, summary: 'Build the dependencies', option: [ ['--publish-layer', '[Optional] Publishing the built artifact as a layer'], @@ -20,6 +22,14 @@ Examples: ], ['--command ', '[Optional] Using custom commands'], ['--script-file ', '[Optional] Using custom shell scripts'], + [ + '--cloud-build-config ', + '[Optional] Cloud based build configuration file, default to search for the current directory fc3-cloud-build.yaml.', + ], + [ + '--debug-instance', + '[Optional] Only for cloud building, start the interactive debugging window after the build is complete.', + ], [ '-f, --dockerfile ', '[Optional] Specify the dockerfile path, Use docker to build the image of the custom container runtime', diff --git a/src/commands-help/index.ts b/src/commands-help/index.ts index 977df2bd..c32d4f0e 100644 --- a/src/commands-help/index.ts +++ b/src/commands-help/index.ts @@ -17,6 +17,7 @@ import logs from './logs'; import session from './session'; import scaling from './scaling'; import list from './list'; +import model from './model'; export default { deploy, @@ -38,4 +39,5 @@ export default { session, scaling, list, + model, }; diff --git a/src/commands-help/model.ts b/src/commands-help/model.ts index 3043d358..3afff8d7 100644 --- a/src/commands-help/model.ts +++ b/src/commands-help/model.ts @@ -1,13 +1,13 @@ export default { help: { - description: 'Resource layer operation ', - summary: 'Resource layer operation ', + description: 'Resource model operation ', + summary: 'Resource model operation ', }, subCommands: { download: { help: { description: `Download model`, - summary: 'Publish new layer version', + summary: 'Download model', option: [], }, }, diff --git a/src/index.ts b/src/index.ts index bc96c3d0..93f69dd4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -133,6 +133,10 @@ export default class Fc extends Base { public async build(inputs: IInputs) { await super.handlePreRun(inputs, false); + const build = new BuilderFactory(inputs); + if (build.findCloudBuildYaml()) { + return await build.runit(); + } const runtime = _.get(inputs, 'props.runtime'); if (FC.isCustomContainerRuntime(runtime)) { diff --git a/src/interface/index.ts b/src/interface/index.ts index 0292d1e7..5ad6e0d0 100644 --- a/src/interface/index.ts +++ b/src/interface/index.ts @@ -23,6 +23,7 @@ export interface IProps extends IFunction { endpoint?: string; supplement?: any; annotations?: any; + buildDir?: string; } export interface IInputs extends _IInputs { diff --git a/src/subCommands/build/index.ts b/src/subCommands/build/index.ts index f1456dac..35913cb5 100644 --- a/src/subCommands/build/index.ts +++ b/src/subCommands/build/index.ts @@ -5,8 +5,15 @@ import { ImageDockerBuilder } from './impl/imageDockerBuilder'; import { ImageKanikoBuilder } from './impl/imageKanikoBuilder'; import { DefaultBuilder } from './impl/defaultBuilder'; import { Builder } from './impl/baseBuilder'; +import { parseArgv } from '@serverless-devs/utils'; +import fs from 'fs'; +import yaml from 'js-yaml'; +import path from 'path'; +import { yellow } from 'chalk'; import logger from '../../logger'; +import Runit from './runit'; +import { IProps as RunitProps } from './runit/interface'; export enum BuildType { ImageDocker = 'IAMGE_BULD_DOCKER', @@ -16,6 +23,99 @@ export enum BuildType { } export default class BuilderFactory { + private inputs: IInputs; + private debugInstance: boolean; + cloudBuildYamlPath: string; + private cloudBuildYamlAbsPath: string | null; + + constructor(inputs: IInputs) { + this.inputs = inputs; + const opts = parseArgv(inputs.args, { + alias: { help: 'h', 'assume-yes': 'y' }, + boolean: ['help', 'debug-instance'], + string: ['cloud-build-config'], + }); + const { 'debug-instance': debugInstance, 'cloud-build-config': cloudBuildConfig } = opts; + this.debugInstance = debugInstance; + this.cloudBuildYamlPath = cloudBuildConfig; + this.cloudBuildYamlAbsPath = null; + } + + findCloudBuildYaml(): string | null { + if (this.cloudBuildYamlPath) { + const absolutePath = path.isAbsolute(this.cloudBuildYamlPath) + ? this.cloudBuildYamlPath + : path.resolve(this.cloudBuildYamlPath); + + if (!fs.existsSync(absolutePath)) { + logger.error(`User-specified config not found: ${absolutePath}`); + throw new Error(`Cloud build config not found: ${absolutePath}`); + } + + logger.debug(`Using user-specified config: ${absolutePath}`); + this.cloudBuildYamlAbsPath = absolutePath; + return absolutePath; + } + + const defaultPath = path.join(process.cwd(), 'fc3-cloud-build.yaml'); + if (fs.existsSync(defaultPath)) { + logger.debug(`Found fc3-cloud-build.yaml in current directory: ${defaultPath}`); + this.cloudBuildYamlAbsPath = defaultPath; + return defaultPath; + } + + logger.debug('fc3-cloud-build.yaml not found'); + return null; + } + + async runit() { + const buildYamlPath = this.cloudBuildYamlAbsPath; + + try { + const buildYamlContent = fs.readFileSync(buildYamlPath, 'utf8'); + const buildConfig = yaml.load(buildYamlContent) as any; + + // 从build.yaml中提取配置,支持多种格式 + let config = buildConfig; + if (buildConfig && typeof buildConfig === 'object') { + const keys = Object.keys(buildConfig); + + const firstKey = keys[0]; + const firstValue = buildConfig[firstKey]; + + if (firstValue && typeof firstValue === 'object' && 'props' in firstValue) { + config = firstValue.props; + } else if (keys.length === 1 || keys.includes('default')) { + const targetKey = keys.includes('default') ? 'default' : firstKey; + const extractedConfig = buildConfig[targetKey]; + config = + extractedConfig && 'props' in extractedConfig ? extractedConfig.props : extractedConfig; + } + } + logger.debug(`Extracted config: ${JSON.stringify(config, null, 2)}`); + + const credential = await this.inputs.getCredential(); + + const runitInputs = { + ...this.inputs, + region: this.inputs.props.region, + credential, + props: config as RunitProps, + userAgent: this.inputs.userAgent || '', + }; + + logger.debug(`RunitInputs: ${JSON.stringify(runitInputs, null, 2)}`); + const runit = new Runit(runitInputs); + const result = await runit.deploy(this.debugInstance); + + logger.write(yellow(`Please replace customContainerConfig.image: ${result.image}`)); + return result; + } catch (error) { + logger.error(`Failed to execute runit: ${error.message}`); + throw error; + } + } + public static getBuilder(buildType: BuildType, inputs: IInputs): Builder { switch (buildType) { case BuildType.ImageDocker: diff --git a/src/subCommands/build/runit/index.ts b/src/subCommands/build/runit/index.ts new file mode 100644 index 00000000..58e362bc --- /dev/null +++ b/src/subCommands/build/runit/index.ts @@ -0,0 +1,43 @@ +import { RunitInput } from './interface'; +import { build } from '@serverless-devs/docker-image-builder'; + +export default class Runit { + inputs: RunitInput; + + constructor(inputs: RunitInput) { + this.inputs = inputs; + } + + async deploy(debugInstance: boolean) { + const { registryMode, image, username, password, cpu, memory } = this.inputs.props.runtime; + const { code: codeUri, setup, timeoutMinutes, baseContainerConfig } = this.inputs.props.build; + + const { + AccountID: accountId, + AccessKeyID: accessKeyId, + AccessKeySecret: accessKeySecret, + } = this.inputs.credential; + + await build({ + uid: accountId, + ak: accessKeyId, + sk: accessKeySecret, + region: this.inputs.props.region, + image, + username, + password, + timeoutMinutes, + registryMode, + dir: codeUri, + setupScript: setup, + enableSsh: debugInstance, + cpu, + memory, + baseImage: baseContainerConfig?.image, + }); + + return { + image, + }; + } +} diff --git a/src/subCommands/build/runit/interface/index.ts b/src/subCommands/build/runit/interface/index.ts new file mode 100644 index 00000000..92cef945 --- /dev/null +++ b/src/subCommands/build/runit/interface/index.ts @@ -0,0 +1,29 @@ +import { IInputs as _IInputs, ICredentials } from '@serverless-devs/component-interface'; +import { ICustomContainerConfig } from '../../../../interface'; + +export interface RunitInput extends _IInputs { + region: string; + credential: ICredentials; + props: IProps; + userAgent: string; + baseDir: string; +} + +export interface IProps { + region: string; + build: { + setup: string; + code: string; + timeoutMinutes?: number; + buildSpec?: string; + baseContainerConfig?: ICustomContainerConfig; + }; + runtime: { + registryMode?: 'oci' | 'fc-registry'; + image: string; + username?: string; + password?: string; + cpu?: string | number; + memory?: string | number; + }; +} diff --git a/src/subCommands/model/index.ts b/src/subCommands/model/index.ts index 7dbd2485..b917d1f0 100644 --- a/src/subCommands/model/index.ts +++ b/src/subCommands/model/index.ts @@ -6,7 +6,7 @@ import VPC_NAS from '../../resources/vpc-nas'; import { ICredentials } from '@serverless-devs/component-interface'; import { yellow } from 'chalk'; import { getEnvVariable } from '../../default/resources'; -import commandsHelp from '../../commands-help/layer'; +import commandsHelp from '../../commands-help/model'; import { parseArgv } from '@serverless-devs/utils'; import assert from 'assert'; import OSS from '../../resources/oss'; @@ -43,7 +43,7 @@ export class Model { const subCommand = _.get(subCommands, '[0]'); if (!subCommand || !commandsList.includes(subCommand)) { throw new Error( - `Command "${subCommand}" not found, Please use "s cli fc3 layer -h" to query how to use the command`, + `Command "${subCommand}" not found, Please use "s cli fc3 model -h" to query how to use the command`, ); } this.subCommand = subCommand;