@serverless-devs/engine 0.0.1-beta.9 → 0.0.2
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/lib/actions/index.d.ts +79 -0
- package/lib/actions/index.js +191 -33
- package/lib/actions/index.js.map +1 -1
- package/lib/constants/index.js +4 -0
- package/lib/constants/index.js.map +1 -1
- package/lib/index.d.ts +74 -1
- package/lib/index.js +199 -82
- package/lib/index.js.map +1 -1
- package/lib/types.d.ts +10 -8
- package/lib/types.js +1 -1
- package/lib/types.js.map +1 -1
- package/lib/utils/index.js +6 -7
- package/lib/utils/index.js.map +1 -1
- package/package.json +13 -7
package/lib/index.js
CHANGED
|
@@ -22,6 +22,9 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
26
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
27
|
+
};
|
|
25
28
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
29
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
30
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -46,33 +49,49 @@ const actions_1 = __importDefault(require("./actions"));
|
|
|
46
49
|
const credential_1 = __importDefault(require("@serverless-devs/credential"));
|
|
47
50
|
const load_component_1 = __importDefault(require("@serverless-devs/load-component"));
|
|
48
51
|
const logger_1 = __importDefault(require("@serverless-devs/logger"));
|
|
49
|
-
const utils = __importStar(require("@serverless-devs/utils"));
|
|
50
52
|
const utils_2 = require("@serverless-devs/utils");
|
|
51
53
|
const constants_1 = require("./constants");
|
|
52
54
|
const assert_1 = __importDefault(require("assert"));
|
|
55
|
+
__exportStar(require("./types"), exports);
|
|
53
56
|
const debug = require('@serverless-cd/debug')('serverless-devs:engine');
|
|
57
|
+
/**
|
|
58
|
+
* Engine Class
|
|
59
|
+
*
|
|
60
|
+
* This class provides an engine to handle Serverless Devs operations and steps.
|
|
61
|
+
* It operates based on the xstate state machine library, ensuring that execution follows
|
|
62
|
+
* the predefined flow and states.
|
|
63
|
+
*/
|
|
54
64
|
class Engine {
|
|
55
65
|
constructor(options) {
|
|
56
66
|
this.options = options;
|
|
57
67
|
this.context = {
|
|
58
|
-
status: types_1.STEP_STATUS.
|
|
68
|
+
status: types_1.STEP_STATUS.PENDING,
|
|
59
69
|
completed: false,
|
|
60
70
|
error: [],
|
|
61
71
|
};
|
|
62
|
-
this.record = { status: types_1.STEP_STATUS.
|
|
72
|
+
this.record = { status: types_1.STEP_STATUS.PENDING, editStatusAble: true };
|
|
63
73
|
this.spec = {};
|
|
64
74
|
debug('engine start');
|
|
65
75
|
// 初始化参数
|
|
66
76
|
this.options.args = (0, lodash_1.get)(this.options, 'args', process.argv.slice(2));
|
|
67
77
|
this.options.cwd = (0, lodash_1.get)(this.options, 'cwd', process.cwd());
|
|
68
|
-
this.options.template =
|
|
78
|
+
this.options.template = (0, utils_2.getAbsolutePath)((0, lodash_1.get)(this.options, 'template'), this.options.cwd);
|
|
69
79
|
debug(`engine options: ${(0, utils_1.stringify)(options)}`);
|
|
70
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Initialization steps before starting the engine.
|
|
83
|
+
*/
|
|
71
84
|
beforeStart() {
|
|
72
85
|
return __awaiter(this, void 0, void 0, function* () {
|
|
86
|
+
// 初始化 logger
|
|
87
|
+
this.glog = this.getLogger();
|
|
88
|
+
this.logger = this.glog.__generate('engine');
|
|
73
89
|
// 初始化 spec
|
|
74
|
-
this.parseSpecInstance = new parse_spec_1.default((0, lodash_1.get)(this.options, 'template'),
|
|
75
|
-
|
|
90
|
+
this.parseSpecInstance = new parse_spec_1.default((0, lodash_1.get)(this.options, 'template'), {
|
|
91
|
+
argv: this.options.args,
|
|
92
|
+
logger: this.logger,
|
|
93
|
+
});
|
|
94
|
+
this.spec = yield this.parseSpecInstance.start();
|
|
76
95
|
// 初始化行参环境变量 > .env (parse-spec require .env)
|
|
77
96
|
(0, lodash_1.each)(this.options.env, (value, key) => {
|
|
78
97
|
process.env[key] = value;
|
|
@@ -80,16 +99,22 @@ class Engine {
|
|
|
80
99
|
const { steps: _steps } = this.spec;
|
|
81
100
|
// 参数校验
|
|
82
101
|
this.validate();
|
|
83
|
-
// 初始化 logger
|
|
84
|
-
this.glog = this.getLogger();
|
|
85
|
-
this.logger = this.glog.__generate('engine');
|
|
86
102
|
this.context.steps = yield this.download(_steps);
|
|
87
103
|
});
|
|
88
104
|
}
|
|
89
|
-
|
|
105
|
+
/**
|
|
106
|
+
* Start the engine.
|
|
107
|
+
*
|
|
108
|
+
* This is the primary execution function for the engine. It is responsible for starting
|
|
109
|
+
* the entire engine and handling each step.
|
|
110
|
+
*
|
|
111
|
+
* @note engine应收敛所有的异常,不应该抛出异常
|
|
112
|
+
*/
|
|
90
113
|
start() {
|
|
91
114
|
return __awaiter(this, void 0, void 0, function* () {
|
|
92
115
|
this.context.status = types_1.STEP_STATUS.RUNNING;
|
|
116
|
+
// Haoran: should set this.record.status to RUNNING?
|
|
117
|
+
this.record.status = types_1.STEP_STATUS.RUNNING;
|
|
93
118
|
try {
|
|
94
119
|
yield this.beforeStart();
|
|
95
120
|
}
|
|
@@ -99,7 +124,8 @@ class Engine {
|
|
|
99
124
|
this.context.error.push(error);
|
|
100
125
|
return this.context;
|
|
101
126
|
}
|
|
102
|
-
const { steps: _steps, yaml, access = yaml.access } = this.spec;
|
|
127
|
+
const { steps: _steps, yaml, command, access = yaml.access } = this.spec;
|
|
128
|
+
this.logger.write(`${(0, utils_2.emoji)('⌛')} Steps for [${command}] of [${(0, lodash_1.get)(this.spec, 'yaml.appName')}]\n${chalk_1.default.gray('====================')}`);
|
|
103
129
|
// 初始化全局的 action
|
|
104
130
|
this.globalActionInstance = new actions_1.default(yaml.actions, {
|
|
105
131
|
hookLevel: parse_spec_1.IActionLevel.GLOBAL,
|
|
@@ -107,9 +133,11 @@ class Engine {
|
|
|
107
133
|
skipActions: this.spec.skipActions,
|
|
108
134
|
});
|
|
109
135
|
const credential = yield (0, utils_1.getCredential)(access, this.logger);
|
|
136
|
+
this.context.credential = credential;
|
|
110
137
|
// 处理 global-pre
|
|
111
138
|
try {
|
|
112
139
|
this.globalActionInstance.setValue('magic', this.getFilterContext());
|
|
140
|
+
this.globalActionInstance.setValue('command', command);
|
|
113
141
|
yield this.globalActionInstance.start(parse_spec_1.IHookType.PRE, { access, credential });
|
|
114
142
|
}
|
|
115
143
|
catch (error) {
|
|
@@ -118,14 +146,17 @@ class Engine {
|
|
|
118
146
|
yield this.doCompleted();
|
|
119
147
|
return this.context;
|
|
120
148
|
}
|
|
121
|
-
|
|
122
|
-
|
|
149
|
+
// Assign the id, pending status and etc for all steps.
|
|
150
|
+
this.context.steps = (0, lodash_1.map)(this.context.steps, item => {
|
|
151
|
+
return Object.assign(Object.assign({}, item), { stepCount: (0, lodash_1.uniqueId)(), status: types_1.STEP_STATUS.PENDING, done: false });
|
|
123
152
|
});
|
|
124
153
|
const res = yield new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
|
154
|
+
// Every states object has two fixed states, "init" and "final".
|
|
125
155
|
const states = {
|
|
126
156
|
init: {
|
|
127
157
|
on: {
|
|
128
|
-
|
|
158
|
+
// Haoran: May this.context.steps be empty?
|
|
159
|
+
INIT: this.context.steps.length === 0 ? 'final' : (0, lodash_1.get)(this.context.steps, '[0].stepCount'),
|
|
129
160
|
},
|
|
130
161
|
},
|
|
131
162
|
final: {
|
|
@@ -133,12 +164,10 @@ class Engine {
|
|
|
133
164
|
invoke: {
|
|
134
165
|
src: () => __awaiter(this, void 0, void 0, function* () {
|
|
135
166
|
// 执行终态是 error-with-continue 的时候,改为 success
|
|
136
|
-
const status = this.record.status === types_1.STEP_STATUS.ERROR_WITH_CONTINUE
|
|
137
|
-
? types_1.STEP_STATUS.SUCCESS
|
|
138
|
-
: this.record.status;
|
|
167
|
+
const status = this.record.status === types_1.STEP_STATUS.ERROR_WITH_CONTINUE ? types_1.STEP_STATUS.SUCCESS : this.record.status;
|
|
139
168
|
this.context.status = status;
|
|
140
169
|
yield this.doCompleted();
|
|
141
|
-
this.context.steps = (0, lodash_1.map)(this.context.steps,
|
|
170
|
+
this.context.steps = (0, lodash_1.map)(this.context.steps, item => (0, lodash_1.omit)(item, ['instance']));
|
|
142
171
|
this.context.output = this.getOutput();
|
|
143
172
|
debug(`context: ${(0, utils_1.stringify)(this.context)}`);
|
|
144
173
|
debug('engine end');
|
|
@@ -147,13 +176,10 @@ class Engine {
|
|
|
147
176
|
},
|
|
148
177
|
},
|
|
149
178
|
};
|
|
179
|
+
// Every states object has dynamic state, that based on the step.StepCount.
|
|
150
180
|
(0, lodash_1.each)(this.context.steps, (item, index) => {
|
|
151
|
-
const target = this.context.steps[index + 1]
|
|
152
|
-
|
|
153
|
-
: 'final';
|
|
154
|
-
const flowProject = yaml.useFlow
|
|
155
|
-
? (0, lodash_1.filter)(this.context.steps, (o) => o.flowId === item.flowId)
|
|
156
|
-
: [item];
|
|
181
|
+
const target = this.context.steps[index + 1] ? (0, lodash_1.get)(this.context.steps, `[${index + 1}].stepCount`) : 'final';
|
|
182
|
+
const flowProject = yaml.useFlow ? (0, lodash_1.filter)(this.context.steps, o => o.flowId === item.flowId) : [item];
|
|
157
183
|
states[item.stepCount] = {
|
|
158
184
|
invoke: {
|
|
159
185
|
id: item.stepCount,
|
|
@@ -166,9 +192,9 @@ class Engine {
|
|
|
166
192
|
this.recordContext(item, { status: types_1.STEP_STATUS.RUNNING });
|
|
167
193
|
// 检查全局的执行状态,如果是failure,则不执行该步骤, 并记录状态为 skipped
|
|
168
194
|
if (this.record.status === types_1.STEP_STATUS.FAILURE) {
|
|
169
|
-
return yield Promise.all((0, lodash_1.map)(flowProject,
|
|
195
|
+
return yield Promise.all((0, lodash_1.map)(flowProject, o => this.doSkip(o)));
|
|
170
196
|
}
|
|
171
|
-
return yield Promise.all((0, lodash_1.map)(flowProject,
|
|
197
|
+
return yield Promise.all((0, lodash_1.map)(flowProject, o => this.handleSrc(o)));
|
|
172
198
|
}),
|
|
173
199
|
onDone: {
|
|
174
200
|
target,
|
|
@@ -184,27 +210,41 @@ class Engine {
|
|
|
184
210
|
states,
|
|
185
211
|
});
|
|
186
212
|
const stepService = (0, xstate_1.interpret)(fetchMachine)
|
|
187
|
-
.onTransition(
|
|
213
|
+
.onTransition(state => state.value)
|
|
188
214
|
.start();
|
|
189
215
|
stepService.send('INIT');
|
|
190
216
|
}));
|
|
217
|
+
this.glog.__clear();
|
|
191
218
|
return res;
|
|
192
219
|
});
|
|
193
220
|
}
|
|
221
|
+
/**
|
|
222
|
+
* Extracts and returns an object containing the output of each step.
|
|
223
|
+
* The object's key is the project name and the value is the output of that project.
|
|
224
|
+
*/
|
|
194
225
|
getOutput() {
|
|
195
226
|
const output = {};
|
|
196
|
-
(0, lodash_1.each)(this.context.steps,
|
|
197
|
-
if (!(0, lodash_1.
|
|
227
|
+
(0, lodash_1.each)(this.context.steps, item => {
|
|
228
|
+
if (!(0, lodash_1.isNil)(item.output)) {
|
|
198
229
|
(0, lodash_1.set)(output, item.projectName, item.output);
|
|
199
230
|
}
|
|
200
231
|
});
|
|
201
232
|
return output;
|
|
202
233
|
}
|
|
234
|
+
/**
|
|
235
|
+
* Validates the 'steps' and 'command' present in 'this.spec'.
|
|
236
|
+
* Throws an error if either 'steps' or 'command' are missing.
|
|
237
|
+
*/
|
|
203
238
|
validate() {
|
|
204
|
-
const { steps,
|
|
239
|
+
const { steps, command } = this.spec;
|
|
205
240
|
(0, assert_1.default)(!(0, lodash_1.isEmpty)(steps), 'steps is required');
|
|
206
|
-
(0, assert_1.default)(
|
|
241
|
+
(0, assert_1.default)(command, 'command is required');
|
|
207
242
|
}
|
|
243
|
+
/**
|
|
244
|
+
* Asynchronously downloads and initializes the given steps.
|
|
245
|
+
* For each step, it loads the specified component and associates a logger with it.
|
|
246
|
+
* Returns an array containing the initialized steps.
|
|
247
|
+
*/
|
|
208
248
|
download(steps) {
|
|
209
249
|
return __awaiter(this, void 0, void 0, function* () {
|
|
210
250
|
const newSteps = [];
|
|
@@ -223,17 +263,23 @@ class Engine {
|
|
|
223
263
|
const customLogger = (0, lodash_1.get)(this.options, 'logConfig.customLogger');
|
|
224
264
|
if (customLogger) {
|
|
225
265
|
debug('use custom logger');
|
|
226
|
-
if (customLogger
|
|
266
|
+
if ((customLogger === null || customLogger === void 0 ? void 0 : customLogger.CODE) === logger_1.default.CODE) {
|
|
227
267
|
return customLogger;
|
|
228
268
|
}
|
|
229
269
|
throw new Error('customLogger must be instance of Logger');
|
|
230
270
|
}
|
|
231
|
-
return new logger_1.default(Object.assign(Object.assign({ traceId: (0,
|
|
271
|
+
return new logger_1.default(Object.assign(Object.assign({ traceId: (0, utils_2.traceid)(), logDir: path_1.default.join((0, utils_2.getRootHome)(), 'logs') }, this.options.logConfig), { level: (0, lodash_1.get)(this.options, 'logConfig.level', this.spec.debug ? 'DEBUG' : undefined) }));
|
|
232
272
|
}
|
|
273
|
+
/**
|
|
274
|
+
* Updates the context for the given step based on the provided options.
|
|
275
|
+
*
|
|
276
|
+
* @param item - The current step being processed.
|
|
277
|
+
* @param options - An object containing details like status, error, output, etc. to update the step's context.
|
|
278
|
+
*/
|
|
233
279
|
recordContext(item, options = {}) {
|
|
234
280
|
const { status, error, output, process_time, props, done } = options;
|
|
235
281
|
this.context.stepCount = item.stepCount;
|
|
236
|
-
this.context.steps = (0, lodash_1.map)(this.context.steps,
|
|
282
|
+
this.context.steps = (0, lodash_1.map)(this.context.steps, obj => {
|
|
237
283
|
if (obj.stepCount === item.stepCount) {
|
|
238
284
|
if (status) {
|
|
239
285
|
obj.status = status;
|
|
@@ -258,26 +304,40 @@ class Engine {
|
|
|
258
304
|
return obj;
|
|
259
305
|
});
|
|
260
306
|
}
|
|
307
|
+
/**
|
|
308
|
+
* Generates a context data for the given step containing details like cwd, vars, and other steps' outputs and props.
|
|
309
|
+
* @param item - The current step being processed.
|
|
310
|
+
* @returns - The generated context data.
|
|
311
|
+
*/
|
|
261
312
|
getFilterContext(item) {
|
|
262
313
|
const data = {
|
|
263
314
|
cwd: path_1.default.dirname(this.spec.yaml.path),
|
|
264
315
|
vars: this.spec.yaml.vars,
|
|
316
|
+
__runtime: this.options.verify ? 'enigne' : 'parse',
|
|
317
|
+
resources: {},
|
|
265
318
|
};
|
|
266
319
|
for (const obj of this.context.steps) {
|
|
267
|
-
data[obj.projectName] = { output: obj.output || {}, props: obj.props || {} };
|
|
320
|
+
data.resources[obj.projectName] = { output: obj.output || {}, props: obj.props || {} };
|
|
268
321
|
}
|
|
269
322
|
if (item) {
|
|
270
|
-
data.
|
|
323
|
+
data.credential = item.credential;
|
|
271
324
|
data.that = {
|
|
272
325
|
name: item.projectName,
|
|
273
326
|
access: item.access,
|
|
274
327
|
component: item.component,
|
|
275
|
-
props: data[item.projectName].props,
|
|
276
|
-
output: data[item.projectName].output,
|
|
328
|
+
props: data.resources[item.projectName].props,
|
|
329
|
+
output: data.resources[item.projectName].output,
|
|
277
330
|
};
|
|
278
331
|
}
|
|
279
332
|
return data;
|
|
280
333
|
}
|
|
334
|
+
/**
|
|
335
|
+
* Handles the subsequent operations after a step has been completed.
|
|
336
|
+
* 1. Marks the step as completed.
|
|
337
|
+
* 2. If the step status is FAILURE, attempts to trigger the global FAIL hook.
|
|
338
|
+
* 3. If the step status is SUCCESS, attempts to trigger the global SUCCESS hook.
|
|
339
|
+
* 4. Regardless of the step's status, tries to trigger the global COMPLETE hook to denote completion.
|
|
340
|
+
*/
|
|
281
341
|
doCompleted() {
|
|
282
342
|
return __awaiter(this, void 0, void 0, function* () {
|
|
283
343
|
this.context.completed = true;
|
|
@@ -308,18 +368,23 @@ class Engine {
|
|
|
308
368
|
}
|
|
309
369
|
});
|
|
310
370
|
}
|
|
371
|
+
/**
|
|
372
|
+
* Handles the execution process for a project step.
|
|
373
|
+
* @param item - The project step to handle.
|
|
374
|
+
*/
|
|
311
375
|
handleSrc(item) {
|
|
376
|
+
var _a, _b, _c;
|
|
312
377
|
return __awaiter(this, void 0, void 0, function* () {
|
|
313
|
-
|
|
378
|
+
const { command } = this.spec;
|
|
379
|
+
// Attempt to execute pre-hook and component logic for the project step.
|
|
314
380
|
try {
|
|
315
381
|
// project pre hook and project component
|
|
316
382
|
yield this.handleAfterSrc(item);
|
|
317
383
|
}
|
|
318
384
|
catch (error) {
|
|
319
|
-
// project fail hook
|
|
385
|
+
// On error, attempt to trigger the project's fail hook and update the recorded context.
|
|
320
386
|
try {
|
|
321
|
-
const
|
|
322
|
-
const res = yield this.actionInstance.start(parse_spec_1.IHookType.FAIL, newInputs);
|
|
387
|
+
const res = yield ((_a = this.actionInstance) === null || _a === void 0 ? void 0 : _a.start(parse_spec_1.IHookType.FAIL, this.record.componentProps));
|
|
323
388
|
this.recordContext(item, (0, lodash_1.get)(res, 'pluginOutput', {}));
|
|
324
389
|
}
|
|
325
390
|
catch (error) {
|
|
@@ -328,13 +393,13 @@ class Engine {
|
|
|
328
393
|
}
|
|
329
394
|
}
|
|
330
395
|
// 若记录的全局状态为true,则进行输出成功的日志
|
|
396
|
+
// If the global record status is SUCCESS, attempt to trigger the project's success hook.
|
|
331
397
|
if (this.record.status === types_1.STEP_STATUS.SUCCESS) {
|
|
332
398
|
// project success hook
|
|
333
399
|
try {
|
|
334
400
|
// 项目的output, 再次获取魔法变量
|
|
335
401
|
this.actionInstance.setValue('magic', this.getFilterContext(item));
|
|
336
|
-
const
|
|
337
|
-
const res = yield this.actionInstance.start(parse_spec_1.IHookType.SUCCESS, Object.assign(Object.assign({}, newInputs), { output: (0, lodash_1.get)(item, 'output', {}) }));
|
|
402
|
+
const res = yield ((_b = this.actionInstance) === null || _b === void 0 ? void 0 : _b.start(parse_spec_1.IHookType.SUCCESS, Object.assign(Object.assign({}, this.record.componentProps), { output: (0, lodash_1.get)(item, 'output', {}) })));
|
|
338
403
|
this.recordContext(item, (0, lodash_1.get)(res, 'pluginOutput', {}));
|
|
339
404
|
}
|
|
340
405
|
catch (error) {
|
|
@@ -342,29 +407,47 @@ class Engine {
|
|
|
342
407
|
this.recordContext(item, { error });
|
|
343
408
|
}
|
|
344
409
|
}
|
|
345
|
-
// project complete hook
|
|
410
|
+
// Attempt to trigger the project's complete hook regardless of status.
|
|
346
411
|
try {
|
|
347
|
-
const
|
|
348
|
-
const res = yield this.actionInstance.start(parse_spec_1.IHookType.COMPLETE, Object.assign(Object.assign({}, newInputs), { output: (0, lodash_1.get)(item, 'output', {}) }));
|
|
412
|
+
const res = yield ((_c = this.actionInstance) === null || _c === void 0 ? void 0 : _c.start(parse_spec_1.IHookType.COMPLETE, Object.assign(Object.assign({}, this.record.componentProps), { output: (0, lodash_1.get)(item, 'output', {}) })));
|
|
349
413
|
this.recordContext(item, (0, lodash_1.get)(res, 'pluginOutput', {}));
|
|
350
414
|
}
|
|
351
415
|
catch (error) {
|
|
352
416
|
this.record.status = types_1.STEP_STATUS.FAILURE;
|
|
353
|
-
this.recordContext(item, { error
|
|
417
|
+
this.recordContext(item, { error });
|
|
354
418
|
}
|
|
419
|
+
// 记录项目已经执行完成
|
|
420
|
+
const process_time = (0, utils_1.getProcessTime)(this.record.startTime);
|
|
421
|
+
this.recordContext(item, { done: true, process_time });
|
|
422
|
+
// Log output based on the record status.
|
|
355
423
|
if (this.record.status === types_1.STEP_STATUS.SUCCESS) {
|
|
356
|
-
this.logger.
|
|
424
|
+
this.logger.write(`${chalk_1.default.green('✔')} ${chalk_1.default.gray(`[${item.projectName}] completed (${process_time}s)`)}`);
|
|
425
|
+
}
|
|
426
|
+
if (this.record.status === types_1.STEP_STATUS.FAILURE) {
|
|
427
|
+
this.logger.write(`${chalk_1.default.red('✖')} ${chalk_1.default.gray(`[${item.projectName}] failed to [${command}] (${process_time}s)`)}`);
|
|
357
428
|
}
|
|
429
|
+
// step执行完成后,释放logger
|
|
430
|
+
this.glog.__unset(item.projectName);
|
|
358
431
|
});
|
|
359
432
|
}
|
|
433
|
+
/**
|
|
434
|
+
* Handles the logic after a project step's execution.
|
|
435
|
+
* @param item - The project step to handle.
|
|
436
|
+
*/
|
|
360
437
|
handleAfterSrc(item) {
|
|
438
|
+
var _a;
|
|
361
439
|
return __awaiter(this, void 0, void 0, function* () {
|
|
362
440
|
try {
|
|
441
|
+
// Print detailed information of the project step for debugging purposes.
|
|
363
442
|
debug(`project item: ${(0, utils_1.stringify)(item)}`);
|
|
443
|
+
// Extract the command from the specification.
|
|
444
|
+
const { command } = this.spec;
|
|
445
|
+
// Retrieve the credentials for the project step.
|
|
364
446
|
item.credential = yield (0, utils_1.getCredential)(item.access, this.logger);
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
447
|
+
// Set a secret for each credential.
|
|
448
|
+
const { AccessKeyID, AccessKeySecret } = item.credential;
|
|
449
|
+
this.glog.__setSecret([AccessKeyID, AccessKeySecret]);
|
|
450
|
+
// Parse actions for the project step and initialize a new action instance.
|
|
368
451
|
const newAction = this.parseSpecInstance.parseActions(item.actions, parse_spec_1.IActionLevel.PROJECT);
|
|
369
452
|
debug(`project actions: ${JSON.stringify(newAction)}`);
|
|
370
453
|
this.actionInstance = new actions_1.default(newAction, {
|
|
@@ -373,26 +456,33 @@ class Engine {
|
|
|
373
456
|
logger: item.logger,
|
|
374
457
|
skipActions: this.spec.skipActions,
|
|
375
458
|
});
|
|
459
|
+
// Set values for the action instance.
|
|
376
460
|
this.actionInstance.setValue('magic', this.getFilterContext(item));
|
|
461
|
+
this.actionInstance.setValue('step', item);
|
|
462
|
+
this.actionInstance.setValue('command', command);
|
|
463
|
+
// Retrieve properties for the project step.
|
|
377
464
|
const newInputs = yield this.getProps(item);
|
|
378
|
-
|
|
465
|
+
this.actionInstance.setValue('componentProps', newInputs);
|
|
466
|
+
// Start the pre-hook and execute the logic for the project step.
|
|
467
|
+
const pluginResult = yield ((_a = this.actionInstance) === null || _a === void 0 ? void 0 : _a.start(parse_spec_1.IHookType.PRE, newInputs));
|
|
379
468
|
const response = yield this.doSrc(item, pluginResult);
|
|
380
469
|
// 记录全局的执行状态
|
|
381
470
|
if (this.record.editStatusAble) {
|
|
382
471
|
this.record.status = types_1.STEP_STATUS.SUCCESS;
|
|
383
472
|
}
|
|
384
|
-
//
|
|
473
|
+
// If the project step has an ID, update the corresponding record status and output.
|
|
385
474
|
if (item.id) {
|
|
386
475
|
this.record.steps = Object.assign(Object.assign({}, this.record.steps), { [item.id]: {
|
|
387
476
|
status: types_1.STEP_STATUS.SUCCESS,
|
|
388
477
|
output: response,
|
|
389
478
|
} });
|
|
390
479
|
}
|
|
391
|
-
|
|
392
|
-
this.recordContext(item, { status: types_1.STEP_STATUS.SUCCESS, output: response
|
|
480
|
+
// Update the project step's context to SUCCESS.
|
|
481
|
+
this.recordContext(item, { status: types_1.STEP_STATUS.SUCCESS, output: response });
|
|
393
482
|
}
|
|
394
483
|
catch (e) {
|
|
395
484
|
const error = e;
|
|
485
|
+
// Determine the status based on the project step's "continue-on-error" attribute.
|
|
396
486
|
const status = item['continue-on-error'] === true ? types_1.STEP_STATUS.ERROR_WITH_CONTINUE : types_1.STEP_STATUS.FAILURE;
|
|
397
487
|
// 记录全局的执行状态
|
|
398
488
|
if (this.record.editStatusAble) {
|
|
@@ -402,35 +492,42 @@ class Engine {
|
|
|
402
492
|
// 全局的执行状态一旦失败,便不可修改
|
|
403
493
|
this.record.editStatusAble = false;
|
|
404
494
|
}
|
|
495
|
+
// If the project step has an ID, update the corresponding record status.
|
|
405
496
|
if (item.id) {
|
|
406
497
|
this.record.steps = Object.assign(Object.assign({}, this.record.steps), { [item.id]: {
|
|
407
498
|
status,
|
|
408
499
|
} });
|
|
409
500
|
}
|
|
410
|
-
|
|
501
|
+
// Handle the error based on the project step's "continue-on-error" attribute.
|
|
411
502
|
if (item['continue-on-error']) {
|
|
412
|
-
this.recordContext(item, { status
|
|
503
|
+
this.recordContext(item, { status });
|
|
413
504
|
}
|
|
414
505
|
else {
|
|
415
|
-
this.recordContext(item, { status, error
|
|
506
|
+
this.recordContext(item, { status, error });
|
|
416
507
|
throw error;
|
|
417
508
|
}
|
|
418
509
|
}
|
|
419
510
|
});
|
|
420
511
|
}
|
|
512
|
+
/**
|
|
513
|
+
* Retrieve properties for a specific project step.
|
|
514
|
+
* @param item - The project step for which properties are to be retrieved.
|
|
515
|
+
* @returns An object containing properties related to the project step.
|
|
516
|
+
*/
|
|
421
517
|
getProps(item) {
|
|
422
518
|
return __awaiter(this, void 0, void 0, function* () {
|
|
423
519
|
const magic = this.getFilterContext(item);
|
|
424
520
|
debug(`magic context: ${JSON.stringify(magic)}`);
|
|
425
521
|
const newInputs = (0, parse_spec_1.getInputs)(item.props, magic);
|
|
426
|
-
const { projectName,
|
|
522
|
+
const { projectName, command } = this.spec;
|
|
427
523
|
const result = {
|
|
428
524
|
cwd: this.options.cwd,
|
|
525
|
+
name: (0, lodash_1.get)(this.spec, 'yaml.appName'),
|
|
429
526
|
props: newInputs,
|
|
430
|
-
command
|
|
431
|
-
args: (0, lodash_1.filter)(this.options.args,
|
|
527
|
+
command,
|
|
528
|
+
args: (0, lodash_1.filter)(this.options.args, o => !(0, lodash_1.includes)([projectName, command], o)),
|
|
432
529
|
yaml: {
|
|
433
|
-
path: this.spec
|
|
530
|
+
path: (0, lodash_1.get)(this.spec, 'yaml.path'),
|
|
434
531
|
},
|
|
435
532
|
resource: {
|
|
436
533
|
name: item.projectName,
|
|
@@ -448,78 +545,98 @@ class Engine {
|
|
|
448
545
|
return result;
|
|
449
546
|
});
|
|
450
547
|
}
|
|
548
|
+
/**
|
|
549
|
+
* Executes the appropriate action based on the provided project step.
|
|
550
|
+
* @param item - The project step to be executed.
|
|
551
|
+
* @param data - Additional data which may contain plugin output.
|
|
552
|
+
* @returns Result of the executed action, if applicable.
|
|
553
|
+
*/
|
|
451
554
|
doSrc(item, data = {}) {
|
|
452
555
|
return __awaiter(this, void 0, void 0, function* () {
|
|
453
|
-
|
|
556
|
+
// Extract command and projectName from the specification.
|
|
557
|
+
const { command = '', projectName } = this.spec;
|
|
558
|
+
// Retrieve properties for the given project step.
|
|
454
559
|
const newInputs = yield this.getProps(item);
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
this.
|
|
560
|
+
// Set component properties based on the provided data or the newly retrieved properties.
|
|
561
|
+
this.record.componentProps = (0, lodash_1.isEmpty)(data.pluginOutput) ? newInputs : data.pluginOutput;
|
|
562
|
+
debug(`component props: ${(0, utils_1.stringify)(this.record.componentProps)}`);
|
|
563
|
+
this.actionInstance.setValue('componentProps', this.record.componentProps);
|
|
458
564
|
// 服务级操作
|
|
459
565
|
if (projectName) {
|
|
460
|
-
if ((0, lodash_1.isFunction)(item.instance[
|
|
566
|
+
if ((0, lodash_1.isFunction)(item.instance[command])) {
|
|
461
567
|
// 方法存在,执行报错,退出码101
|
|
462
568
|
try {
|
|
463
|
-
return yield item.instance[
|
|
569
|
+
return yield item.instance[command](this.record.componentProps);
|
|
464
570
|
}
|
|
465
571
|
catch (e) {
|
|
466
572
|
const useAllowFailure = (0, utils_1.getAllowFailure)(item.allow_failure, {
|
|
467
573
|
exitCode: constants_1.EXIT_CODE.COMPONENT,
|
|
468
|
-
command
|
|
574
|
+
command,
|
|
469
575
|
});
|
|
470
576
|
if (useAllowFailure)
|
|
471
577
|
return;
|
|
472
578
|
const error = e;
|
|
473
|
-
throw new utils_2.
|
|
579
|
+
throw new utils_2.DevsError(error.message, {
|
|
580
|
+
data: (0, lodash_1.get)(e, 'data'),
|
|
581
|
+
stack: error.stack,
|
|
474
582
|
exitCode: constants_1.EXIT_CODE.COMPONENT,
|
|
475
|
-
prefix: `
|
|
583
|
+
prefix: `[${item.projectName}] failed to [${command}]:`,
|
|
476
584
|
});
|
|
477
585
|
}
|
|
478
586
|
}
|
|
479
587
|
const useAllowFailure = (0, utils_1.getAllowFailure)(item.allow_failure, {
|
|
480
588
|
exitCode: constants_1.EXIT_CODE.DEVS,
|
|
481
|
-
command
|
|
589
|
+
command,
|
|
482
590
|
});
|
|
483
591
|
if (useAllowFailure)
|
|
484
592
|
return;
|
|
485
593
|
// 方法不存在,此时系统将会认为是未找到组件方法,系统的exit code为100;
|
|
486
|
-
throw new utils_2.
|
|
594
|
+
throw new utils_2.DevsError(`The [${command}] command was not found.`, {
|
|
487
595
|
exitCode: constants_1.EXIT_CODE.DEVS,
|
|
488
|
-
tips: `Please check the component ${item.component} has the ${
|
|
596
|
+
tips: `Please check the component ${item.component} has the ${command} command. Serverless Devs documents:${chalk_1.default.underline('https://github.com/Serverless-Devs/Serverless-Devs/blob/master/docs/zh/command')}`,
|
|
597
|
+
prefix: `[${item.projectName}] failed to [${command}]:`,
|
|
489
598
|
});
|
|
490
599
|
}
|
|
491
600
|
// 应用级操作
|
|
492
|
-
if ((0, lodash_1.isFunction)(item.instance[
|
|
601
|
+
if ((0, lodash_1.isFunction)(item.instance[command])) {
|
|
493
602
|
// 方法存在,执行报错,退出码101
|
|
494
603
|
try {
|
|
495
|
-
return yield item.instance[
|
|
604
|
+
return yield item.instance[command](this.record.componentProps);
|
|
496
605
|
}
|
|
497
606
|
catch (e) {
|
|
498
607
|
const useAllowFailure = (0, utils_1.getAllowFailure)(item.allow_failure, {
|
|
499
608
|
exitCode: constants_1.EXIT_CODE.COMPONENT,
|
|
500
|
-
command
|
|
609
|
+
command,
|
|
501
610
|
});
|
|
502
611
|
if (useAllowFailure)
|
|
503
612
|
return;
|
|
504
613
|
const error = e;
|
|
505
|
-
throw new utils_2.
|
|
614
|
+
throw new utils_2.DevsError(error.message, {
|
|
615
|
+
data: (0, lodash_1.get)(e, 'data'),
|
|
616
|
+
stack: error.stack,
|
|
506
617
|
exitCode: constants_1.EXIT_CODE.COMPONENT,
|
|
507
|
-
prefix: `
|
|
618
|
+
prefix: `[${item.projectName}] failed to [${command}]:`,
|
|
508
619
|
});
|
|
509
620
|
}
|
|
510
621
|
}
|
|
511
622
|
// 方法不存在,进行警告,但是并不会报错,最终的exit code为0;
|
|
512
|
-
this.logger.tips(`The [${
|
|
623
|
+
this.logger.tips(`The [${command}] command was not found.`, `Please check the component ${item.component} has the ${command} command. Serverless Devs documents:https://github.com/Serverless-Devs/Serverless-Devs/blob/master/docs/zh/command`);
|
|
513
624
|
});
|
|
514
625
|
}
|
|
626
|
+
/**
|
|
627
|
+
* Handles the project step that is marked to be skipped.
|
|
628
|
+
* @param item - The project step to be skipped.
|
|
629
|
+
* @returns A resolved Promise.
|
|
630
|
+
*/
|
|
515
631
|
doSkip(item) {
|
|
516
632
|
return __awaiter(this, void 0, void 0, function* () {
|
|
517
|
-
// id
|
|
633
|
+
// If the step has an 'id', set its status to 'SKIP' in the record.
|
|
518
634
|
if (item.id) {
|
|
519
635
|
this.record.steps = Object.assign(Object.assign({}, this.record.steps), { [item.id]: {
|
|
520
636
|
status: types_1.STEP_STATUS.SKIP,
|
|
521
637
|
} });
|
|
522
638
|
}
|
|
639
|
+
// Mark the step's status as 'SKIP' and set its processing time to 0.
|
|
523
640
|
this.recordContext(item, { status: types_1.STEP_STATUS.SKIP, process_time: 0 });
|
|
524
641
|
return Promise.resolve();
|
|
525
642
|
});
|