diff --git a/packages/engine/package.json b/packages/engine/package.json index 1ba5def..4d1a739 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@serverless-devs/engine", - "version": "0.1.6-beta.3", + "version": "0.1.6-beta.12", "description": "a engine lib for serverless-devs", "main": "lib/index.js", "scripts": { diff --git a/packages/engine/src/actions/index.ts b/packages/engine/src/actions/index.ts index 37bf68c..2e8938c 100644 --- a/packages/engine/src/actions/index.ts +++ b/packages/engine/src/actions/index.ts @@ -1,5 +1,5 @@ import { IAction, IActionLevel, IActionType, IAllowFailure, IComponentAction, IHookType, IPluginAction, IRunAction, getInputs } from '@serverless-devs/parse-spec'; -import { isEmpty, filter, includes, set, get } from 'lodash'; +import { isEmpty, filter, includes, set, get, cloneDeep } from 'lodash'; import * as utils from '@serverless-devs/utils'; import { DevsError, ETrackerType } from '@serverless-devs/utils'; import fs from 'fs-extra'; @@ -27,7 +27,8 @@ interface IRecord { interface IOptions { hookLevel: `${IActionLevel}`; - projectName?: string; + projectName?: string; // 资源名称(resources下的key) + appName?: string; // 项目名称(s.yaml的name字段) logger: ILoggerInstance; skipActions?: boolean; } @@ -246,8 +247,29 @@ You can still use them now, but we suggest to modify them.`) const instance = await loadComponent(hook.value, { logger: this.logger }); // Determine the inputs for the plugin based on the record's pluginOutput. const inputs = isEmpty(this.record.pluginOutput) ? this.inputs : this.record.pluginOutput; + // 添加hook上下文信息 + // level: 'resource' 表示资源级别hook, 'project' 表示项目级别hook(全局) + const isResourceLevel = this.option.hookLevel === IActionLevel.PROJECT; + const command = this.record.command || ''; + const hookType = hook.hookType || ''; + const inputsWithHookContext = { + ...inputs, + hookContext: { + hookType: hookType, // 例如: 'pre', 'fail', 'success', 'complete' + hookName: command ? `${hookType}-${command}` : hookType, // 例如: 'fail-deploy', 'complete-deploy' + command: command, // 例如: 'deploy', 'remove' + actionType: hook.actionType || 'plugin', // 'plugin' + level: isResourceLevel ? 'resource' : 'project', // 'resource'=资源级别, 'project'=项目级别(全局) + projectName: this.option.appName || undefined, // 项目名称(s.yaml的name字段) + resourceName: isResourceLevel ? (this.option.projectName || undefined) : undefined, // 资源名称(仅resource级别有值) + }, + }; // Execute the plugin with the determined inputs and provided arguments. - this.record.pluginOutput = await instance(inputs, hook.args, this.logger); + this.record.pluginOutput = await instance(inputsWithHookContext, hook.args, this.logger); + // If prop 'replace_output' is true, replace the record's step output with the plugin output. + if (hook.replace_output) { + this.record.step.output = cloneDeep(this.record.pluginOutput); + } } catch (e) { const error = e as Error; // Check if the failure is allowed based on the record's allowFailure setting. diff --git a/packages/engine/src/index.ts b/packages/engine/src/index.ts index 39d3486..7569284 100644 --- a/packages/engine/src/index.ts +++ b/packages/engine/src/index.ts @@ -121,6 +121,7 @@ class Engine { // 初始化全局的 action this.globalActionInstance = new Actions(yaml.actions, { hookLevel: IActionLevel.GLOBAL, + appName: get(this.spec, 'yaml.appName'), // 项目名称 logger: this.logger, skipActions: this.spec.skipActions, }); @@ -393,19 +394,51 @@ class Engine { const projectInfo = get(this.info, item.projectName); if (!projectInfo || isEmpty(projectInfo) || isNil(projectInfo)) { this.logger.write(`${chalk.gray(`execute info command of [${item.projectName}]...`)}`); + let args = cloneDeep(this.options.args); + if (args) { + args[0] = 'info'; + } + // 20250520: support action for ${resources.xx.info.xx} + const newParseSpecInstance = new ParseSpec(get(this.spec, 'yaml.path'), { + argv: args, + logger: this.logger, + }); + newParseSpecInstance.start(); + const newAction = newParseSpecInstance.parseActions(item.actions, IActionLevel.PROJECT); + const newActionInstance = new Actions(newAction, { + hookLevel: IActionLevel.PROJECT, + projectName: item.projectName, // 资源名称 + appName: get(this.spec, 'yaml.appName'), // 项目名称 + logger: item.logger, + skipActions: this.spec.skipActions, + }); + newActionInstance.setValue('magic', await this.getFilterContext(item)); + newActionInstance.setValue('step', item); + newActionInstance.setValue('command', 'info'); + const newInputs = await this.getProps(item); + newActionInstance.setValue('componentProps', newInputs); + const pluginResult = await this.actionInstance?.start(IHookType.PRE, newInputs) || {}; const spec = cloneDeep(this.spec); spec['command'] = 'info'; // 20240912 when -f, don't throw error - const { f, force } = parseArgv(this.options.args); - let res = {} - if (f || force) { - try { - res = await this.doSrc(item, {}, spec); - } catch(e) { - this.logger.warn(get(e, 'data')); + // 20250521: remove previous logic + let res: any = {} + try { + res = await this.doSrc(item, pluginResult, spec); + set(newInputs, 'output', res); + const pluginSuccessResult = await newActionInstance?.start(IHookType.SUCCESS, newInputs); + if (!isEmpty(pluginSuccessResult)) { + res = get(pluginSuccessResult, 'step.output'); } - } else { - res = await this.doSrc(item, {}, spec); + } catch (e) { + this.logger.warn(get(e, 'data')); + // 将error信息添加到inputs中传递给fail hook + set(newInputs, 'errorContext', e); + res = get(await newActionInstance?.start(IHookType.FAIL, newInputs), 'step.output') || {}; + } + const pluginCompleteResult = await newActionInstance?.start(IHookType.COMPLETE, newInputs); + if (!isEmpty(pluginCompleteResult)) { + res = get(pluginCompleteResult, 'step.output'); } set(this.info, item.projectName, res); this.logger.write(`${chalk.gray(`[${item.projectName}] info command executed.`)}`); @@ -501,7 +534,12 @@ class Engine { } catch (error) { // On error, attempt to trigger the project's fail hook and update the recorded context. try { - const res = await this.actionInstance?.start(IHookType.FAIL, this.record.componentProps); + // 将error信息添加到inputs中传递给fail hook + const failInputs = { + ...this.record.componentProps, + errorContext: error, + }; + const res = await this.actionInstance?.start(IHookType.FAIL, failInputs); this.recordContext(item, get(res, 'pluginOutput', {})); } catch (error) { this.record.status = STEP_STATUS.FAILURE; @@ -529,10 +567,13 @@ class Engine { // Attempt to trigger the project's complete hook regardless of status. try { - const res = await this.actionInstance?.start(IHookType.COMPLETE, { + // complete hook需要包含error信息(如果有的话) + const completeInputs = { ...this.record.componentProps, output: get(item, 'output', {}), - }); + errorContext: get(item, 'error'), + }; + const res = await this.actionInstance?.start(IHookType.COMPLETE, completeInputs); this.recordContext(item, get(res, 'pluginOutput', {})); } catch (error) { this.record.status = STEP_STATUS.FAILURE; @@ -578,7 +619,8 @@ class Engine { debug(`project actions: ${JSON.stringify(newAction)}`); this.actionInstance = new Actions(newAction, { hookLevel: IActionLevel.PROJECT, - projectName: item.projectName, + projectName: item.projectName, // 资源名称 + appName: get(this.spec, 'yaml.appName'), // 项目名称 logger: item.logger, skipActions: this.spec.skipActions, }); diff --git a/packages/load-application/package.json b/packages/load-application/package.json index 56b12b2..44435f2 100644 --- a/packages/load-application/package.json +++ b/packages/load-application/package.json @@ -1,6 +1,6 @@ { "name": "@serverless-devs/load-application", - "version": "0.0.16-beta.1", + "version": "0.0.16-beta.3", "description": "load application for serverless-devs", "main": "lib/index.js", "scripts": { @@ -18,7 +18,7 @@ }, "dependencies": { "@serverless-cd/debug": "^4.3.4", - "@serverless-devs/art-template": "^4.13.16-beta.24", + "@serverless-devs/art-template": "^4.13.16-beta.39", "@serverless-devs/credential": "workspace:^", "@serverless-devs/downloads": "workspace:^", "@serverless-devs/secret": "workspace:^", diff --git a/packages/load-application/src/utils/index.ts b/packages/load-application/src/utils/index.ts index 3e98c10..4544c5e 100644 --- a/packages/load-application/src/utils/index.ts +++ b/packages/load-application/src/utils/index.ts @@ -34,6 +34,11 @@ export const getDefaultValue = (value: any) => { return replace(value, RANDOM_PATTERN, randomId()); }; +export const getNumberDefaultValue = (value: any) => { + if (typeof value !== 'number') return; + return value; +}; + export const getSecretManager = () => { const secretManager = SecretManager.getInstance(); return secretManager; diff --git a/packages/load-application/src/v3.ts b/packages/load-application/src/v3.ts index d151c3d..24e18f8 100644 --- a/packages/load-application/src/v3.ts +++ b/packages/load-application/src/v3.ts @@ -8,7 +8,7 @@ import { isEmpty, includes, split, get, has, set, sortBy, map, concat, keys, sta import axios from 'axios'; import parse from './parse'; import { IOptions } from './types'; -import { getInputs, getUrlWithLatest, getUrlWithVersion, getAllCredential, getDefaultValue, getSecretManager } from './utils'; +import { getInputs, getUrlWithLatest, getUrlWithVersion, getAllCredential, getDefaultValue, getSecretManager, getNumberDefaultValue } from './utils'; import YAML from 'yaml'; import inquirer from 'inquirer'; import chalk from 'chalk'; @@ -338,6 +338,16 @@ class LoadApplication { default: getDefaultValue(item.default), validate, }); + } else if (item.type === 'number') { + // number类型 + promptList.push({ + type: 'input', + message: item.title, + name, + prefix, + default: getNumberDefaultValue(item.default), + validate, + }); } } return { promptList, tmpResult }; diff --git a/packages/parse-spec/package.json b/packages/parse-spec/package.json index c935ccd..f715ad0 100644 --- a/packages/parse-spec/package.json +++ b/packages/parse-spec/package.json @@ -1,6 +1,6 @@ { "name": "@serverless-devs/parse-spec", - "version": "0.0.29", + "version": "0.0.30-beta.3", "description": "a parse yaml spec lib for serverless-devs", "main": "lib/index.js", "scripts": { @@ -22,7 +22,7 @@ }, "dependencies": { "@serverless-cd/debug": "^4.3.4", - "@serverless-devs/art-template": "^4.13.16-beta.24", + "@serverless-devs/art-template": "^4.13.16-beta.39", "@serverless-devs/credential": "workspace:^", "@serverless-devs/utils": "workspace:^", "chalk": "^4.1.2", diff --git a/packages/parse-spec/src/index.ts b/packages/parse-spec/src/index.ts index 98ff0e0..02e4cb4 100644 --- a/packages/parse-spec/src/index.ts +++ b/packages/parse-spec/src/index.ts @@ -62,11 +62,11 @@ class ParseSpec { const code = get(projects, `${i}.props.code`); if (code && isString(code)) { const codePath = utils.getAbsolutePath(get(projects, `${i}.props.code`, '')); - expand(dotenv.config({ path: path.join(codePath, '.env') })); + expand(dotenv.config({ path: path.join(codePath, '.env'), override: true })); } } - expand(dotenv.config({ path: path.join(path.dirname(this.yaml.path), '.env') })); + expand(dotenv.config({ path: path.join(path.dirname(this.yaml.path), '.env'), override: true })); } private async doExtend() { // this.yaml = { path: '' } diff --git a/packages/parse-spec/src/types.ts b/packages/parse-spec/src/types.ts index cde15a7..73ee006 100644 --- a/packages/parse-spec/src/types.ts +++ b/packages/parse-spec/src/types.ts @@ -41,6 +41,7 @@ export interface IPluginAction { level: `${IActionLevel}`; projectName: string; allow_failure?: boolean | IAllowFailure; + replace_output?: boolean; } export interface IComponentAction { hookType: `${IHookType}`; diff --git a/packages/registry/package.json b/packages/registry/package.json index 0dbcaf8..df95751 100644 --- a/packages/registry/package.json +++ b/packages/registry/package.json @@ -1,6 +1,6 @@ { "name": "@serverless-devs/registry", - "version": "0.0.12-beta.5", + "version": "0.0.12-beta.7", "description": "request for serverless-devs", "main": "lib/index.js", "scripts": { @@ -23,7 +23,7 @@ "dependencies": { "@serverless-devs/utils": "workspace:^", "@serverless-devs/zip": "workspace:^", - "@serverless-devs/art-template": "4.13.16-beta.38", + "@serverless-devs/art-template": "4.13.16-beta.39", "ajv": "^8.12.0", "chalk": "^5.3.0", "js-yaml": "^4.1.0", diff --git a/packages/registry/src/actions/constant.ts b/packages/registry/src/actions/constant.ts index 05f5262..cb7356e 100644 --- a/packages/registry/src/actions/constant.ts +++ b/packages/registry/src/actions/constant.ts @@ -34,24 +34,6 @@ export const publishSchema = { "type": "array", "items": { "type": "string", - "enum": [ - "阿里云", - "腾讯云", - "华为云", - "百度智能云", - "AWS", - "Azure", - "Google Cloud Platform", - "专有云", - "其它", - "火山引擎", - "Alibaba Cloud", - "Tencent Cloud", - "Huawei Cloud", - "Baidu Cloud", - "Private Cloud", - "Others" - ] } }, "Version": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f8dfbe7..80b1f96 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -221,8 +221,8 @@ importers: specifier: ^4.3.4 version: 4.3.4 '@serverless-devs/art-template': - specifier: ^4.13.16-beta.24 - version: 4.13.16-beta.24 + specifier: ^4.13.16-beta.39 + version: 4.13.16-beta.39 '@serverless-devs/credential': specifier: workspace:^ version: link:../credential @@ -344,8 +344,8 @@ importers: specifier: ^4.3.4 version: 4.3.4 '@serverless-devs/art-template': - specifier: ^4.13.16-beta.24 - version: 4.13.16-beta.24 + specifier: ^4.13.16-beta.39 + version: 4.13.16-beta.39 '@serverless-devs/credential': specifier: workspace:^ version: link:../credential @@ -394,8 +394,8 @@ importers: packages/registry: dependencies: '@serverless-devs/art-template': - specifier: 4.13.16-beta.38 - version: 4.13.16-beta.38 + specifier: 4.13.16-beta.39 + version: 4.13.16-beta.39 '@serverless-devs/utils': specifier: workspace:^ version: link:../utils @@ -851,12 +851,8 @@ packages: supports-color: optional: true - '@serverless-devs/art-template@4.13.16-beta.24': - resolution: {integrity: sha512-TKK3WBpa4shDLO9wJXtipdobnAv27Hdm3DhPgpSaSrz+rYXV3f1mY2Ln3ZrSoD/OY/YXAY3VYLKd8EMhIBswXQ==} - engines: {node: '>= 1.0.0'} - - '@serverless-devs/art-template@4.13.16-beta.38': - resolution: {integrity: sha512-4Sjc8UwsVhI2tDKunjS+2HUDCdyy9WU3uGc+0Wrl6gxHzjCy5o8FONzeKndj+BgySQj1Kp2VQBE1nfYTGw3z7A==} + '@serverless-devs/art-template@4.13.16-beta.39': + resolution: {integrity: sha512-mKPvRUi2jAlmC1xG0efeosaP6ltPK5XMdlhwJxZfxVIg2o+REQMqBU3yUVzESq5fHaQKxElX8mtI2HaRv8NdKw==} engines: {node: '>= 1.0.0'} '@serverless-devs/credentials@2.2.6': @@ -3565,23 +3561,7 @@ snapshots: dependencies: ms: 2.1.2 - '@serverless-devs/art-template@4.13.16-beta.24': - dependencies: - '@serverless-devs/secret': 0.0.2-beta.4 - '@serverless-devs/utils': 0.0.14 - acorn: 5.7.4 - escodegen: 1.14.3 - estraverse: 4.3.0 - fs-extra: 11.1.1 - html-minifier: 3.5.21 - is-keyword-js: 1.0.3 - js-tokens: 3.0.2 - js-yaml: 4.1.0 - lodash: 4.17.21 - merge-source-map: 1.1.0 - source-map: 0.5.7 - - '@serverless-devs/art-template@4.13.16-beta.38': + '@serverless-devs/art-template@4.13.16-beta.39': dependencies: '@serverless-devs/secret': 0.0.2-beta.4 '@serverless-devs/utils': 0.0.14