lugger
Version:
Lugger is an automation framework running on customizable Typescript DSL
354 lines • 13.6 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.runWorkflow__ = exports.parallel__ = exports.task__ = exports.step__ = exports.stage__ = exports.StageReflect__ = exports.PipelineCodes = exports.runWorkflow = exports.parallel = exports.task = exports.step = exports.stage = void 0;
const ts_basis_1 = require("ts-basis");
const ts_dsl_1 = require("ts-dsl");
const pipeline_model_1 = require("./pipeline.model");
const uuid_1 = require("uuid");
const __1 = require("../../..");
function stage(...args) { return (0, exports.stage__)(...args); }
exports.stage = stage;
function step(stepName) { return (0, ts_dsl_1.dslIfaceGuard)('step', __filename); }
exports.step = step;
function task(taskName) { return (0, ts_dsl_1.dslIfaceGuard)('task', __filename); }
exports.task = task;
function parallelModel(...args) { }
class ParallelModel {
}
ParallelModel.failFast = parallelModel;
exports.parallel = parallelModel;
function runWorkflow(workflowClass) {
return (0, ts_dsl_1.dslIfaceGuard)('runWorkflow', __filename);
}
exports.runWorkflow = runWorkflow;
var PipelineCodesEnum;
(function (PipelineCodesEnum) {
PipelineCodesEnum[PipelineCodesEnum["PARALLEL_EXEC_FAILURE"] = 0] = "PARALLEL_EXEC_FAILURE";
})(PipelineCodesEnum || (PipelineCodesEnum = {}));
exports.PipelineCodes = (0, ts_basis_1.ReturnCodeFamily)('PipelineCodes', PipelineCodesEnum);
function getAnonContextname(cce, name) {
return `(anonymous_${name}_${cce.blockContext.sourceFile.file.ts.split('/').pop()}:${cce.blockContext.lastRunSource})`;
}
class StageReflect__ {
stage(...args) { }
stage_0(stageName, stageClosure) { return null; }
;
stage_2(stageOptions) { return null; }
stage_3(...args) { return null; }
}
exports.StageReflect__ = StageReflect__;
let _stage_reflect;
const stage__ = (...args) => {
if (!(0, __1.fromDSL)(args)) {
if ((0, ts_dsl_1.isDecorationCall)(args)) {
return (0, ts_dsl_1.decoratorHandler)(args, {
member: (target, deco) => {
deco.addInitializer(function () {
const instance = this;
addFlowContext(instance, 'stage', deco.name);
});
return target;
}
});
}
else if (typeof args[0] === 'string' || args[0].constructor === Object) {
const stageOptions = typeof args[0] === 'string' ? { name: args[0] } : args[0];
return (0, ts_dsl_1.decoratorHandler)({
member: (target, deco) => {
deco.addInitializer(function () {
const instance = this;
addFlowContext(instance, 'stage', deco.name);
const anyFcb = (0, ts_dsl_1.getRuntime)().functionContextCallbacks.any;
const funcPath = `${instance.constructor.name}.${deco.name}`;
if (!anyFcb[funcPath]) {
anyFcb[funcPath] = [];
}
anyFcb[funcPath].push(fnCtx => {
if (stageOptions) {
if (stageOptions.name) {
stageOptions.stageName = stageOptions.name;
}
Object.assign(fnCtx.scopeContext.data, stageOptions);
}
});
});
return target;
}
});
}
}
const cce = args[0];
const a = (0, ts_dsl_1.backfillArgs)(args.slice(1), 'stageOptions', 'stageClosure');
if (typeof a.stageOptions === 'string') {
a.stageOptions = {
name: a.stageOptions
};
}
return (0, ts_dsl_1.getRuntime)().scopedExec(cce, 'lugger:pipeline:stage', {}, async (resolve, reject, scopeContext) => {
const parentScope = scopeContext.parent;
let opts = (parentScope === null || parentScope === void 0 ? void 0 : parentScope.data.stageOptions) ? parentScope === null || parentScope === void 0 ? void 0 : parentScope.data.stageOptions : a.stageOptions;
if (!opts) {
opts = {};
}
if (!opts.name) {
opts.name = getAnonContextname(cce, 'stage');
}
scopeContext.data.stageName = opts.name;
try {
if (opts.when) {
await (0, ts_dsl_1.punchGrab)(opts.when(parentScope.data.workflowInst));
}
let res;
if (a.stageClosure) {
res = await (0, ts_dsl_1.errorCheck)(a.stageClosure(scopeContext));
}
if (!res) {
res = {};
}
resolve((0, ts_basis_1.ok)(res));
}
catch (e) {
reject(e);
}
});
};
exports.stage__ = stage__;
exports.stage__.inCollationHandler = ((ica) => {
var _a, _b;
const a = (0, ts_dsl_1.backfillArgs)(ica.args.slice(1), 'stageOptions', 'stageClosure');
if (typeof a.stageOptions === 'string') {
a.stageOptions = { name: a.stageOptions };
}
const stageName = ((_a = a.stageOptions) === null || _a === void 0 ? void 0 : _a.name) ? (_b = a.stageOptions) === null || _b === void 0 ? void 0 : _b.name : getAnonContextname(ica.cce, 'stage');
return { collationName: stageName };
});
function step__(cce, ...stepArgs) {
const a = (0, ts_dsl_1.backfillArgs)(stepArgs, 'stepName', 'stepClosure');
if (!a.stepName) {
a.stepName = getAnonContextname(cce, 'step');
}
return (0, ts_dsl_1.getRuntime)().scopedExec(cce, 'lugger:pipeline:step', { data: { stepName: a.stepName }, requireParent: ['lugger:pipeline:stage', 'lugger:pipeline:parallel'] }, async (resolve, reject, scopeContext) => {
try {
let res;
if (a.stepClosure) {
res = await (0, ts_dsl_1.errorCheck)(a.stepClosure(scopeContext));
}
if (!res) {
res = {};
}
resolve((0, ts_basis_1.ok)(res));
}
catch (e) {
reject(e);
}
});
}
exports.step__ = step__;
step__.inCollationHandler = ((ica) => {
const a = (0, ts_dsl_1.backfillArgs)(ica.args.slice(1), 'stepName', 'stepClosure');
if (!a.stepName) {
a.stepName = getAnonContextname(ica.cce, 'step');
}
return { collationName: a.stepName };
});
function task__(cce, ...taskArgs) {
const a = (0, ts_dsl_1.backfillArgs)(taskArgs, 'taskName', 'taskClosure');
if (!a.taskName) {
a.taskName = getAnonContextname(cce, 'task');
}
return (0, ts_dsl_1.getRuntime)().scopedExec(cce, 'lugger:pipeline:task', { data: { taskName: a.taskName }, requireParent: ['lugger:pipeline:stage', 'lugger:pipeline:parallel'] }, async (resolve, reject, scopeContext) => {
try {
let res;
if (a.taskClosure) {
res = await a.taskClosure(scopeContext);
}
if (!res) {
res = {};
}
resolve((0, ts_basis_1.ok)(res));
}
catch (e) {
reject(e);
}
});
}
exports.task__ = task__;
task__.inCollationHandler = ((ica) => {
const a = (0, ts_dsl_1.backfillArgs)(ica.args.slice(1), 'taskName', 'taskClosure');
if (!a.taskName) {
a.taskName = getAnonContextname(ica.cce, 'step');
}
return { collationName: a.taskName };
});
let failFastContext = false;
function parallelModel__(cce, ...args) {
const collator = new ts_dsl_1.__RuntimeCollator();
const a = (0, ts_dsl_1.backfillArgs)(args, 'parallelOptions', 'collationClosure');
let closureIsCollation = false;
if (a.collationClosure && typeof a.collationClosure !== 'function') {
closureIsCollation = true;
}
let options = a.parallelOptions ? a.parallelOptions : { failFast: false };
if (typeof options === 'string') {
const optionStr = options;
options = { failFast: false };
if (optionStr === 'failFast') {
options.failFast = true;
}
}
if (options.failFast === null || options.failFast === undefined) {
options.failFast = false;
}
if (failFastContext) {
options.failFast = true;
failFastContext = false;
}
return (0, ts_dsl_1.getRuntime)().scopedExec(cce, 'lugger:pipeline:parallel', { data: { collator } }, async (resolve, reject, scopeContext) => {
try {
let immediateBlock;
scopeContext.onImmediateBlockContextAssign.push((scopeCtx, blockCtx) => {
immediateBlock = blockCtx;
blockCtx.collator = collator;
});
if (closureIsCollation) {
collator.collation = a.collationClosure;
}
else {
if (a.collationClosure) {
await (0, ts_dsl_1.errorCheck)(a.collationClosure(scopeContext));
}
}
const proms = [];
const collationKeys = Object.keys(collator.collation);
for (const key of collationKeys) {
proms.push((0, ts_basis_1.promise)(async (resolve, reject) => {
try {
return resolve(await (0, ts_dsl_1.errorCheck)(collator.collation[key](scopeContext)));
}
catch (e) {
if (options.failFast) {
(0, ts_dsl_1.getRuntime)().setScopeError(scopeContext, null, e);
}
return reject(e);
}
}));
}
let res = proms.length ? await ts_basis_1.PromUtil.allSettled(proms) : [];
const threadErrors = [];
let i = 0;
const failedCollationKeys = [];
res.forEach(a => {
if (a instanceof Error) {
const collationKey = collationKeys[i];
threadErrors.push({ key: collationKey, error: a });
failedCollationKeys.push(collationKey);
}
++i;
});
if (threadErrors.length > 0) {
const e = new pipeline_model_1.ParallelExecError(`Parallel exec failed at threads: [${failedCollationKeys.join(', ')}]`);
console.log(threadErrors);
e.threadErrors = threadErrors;
return reject(exports.PipelineCodes.error('PARALLEL_EXEC_FAILURE', e).error);
}
return resolve(true);
}
catch (e) {
reject(e);
}
});
}
class ParallelModel__ {
static failFast(cce, ...args) { return parallelModel__(cce, ...args); }
}
parallelModel__.failFast = ParallelModel__.failFast;
exports.parallel__ = parallelModel__;
function runWorkflow__(cce, workflowClass) {
return (0, ts_basis_1.promise)(async (resolve, reject) => {
const workflowId = (0, uuid_1.v4)();
const wfInst = new workflowClass();
const flowContexts = wfInst.flowContexts;
wfInst.__workflowId = workflowId;
wfInst.__ctx = cce.scopeContext;
const e = {
workflow: wfInst,
workflowId,
workflowName: workflowClass.name,
stageName: '',
stageType: '',
result: null,
error: null,
rethrow: true,
startTime: Date.now(),
duration: null,
endTime: null,
metadata: {},
};
let error;
try {
if (wfInst['setup']) {
await (0, ts_dsl_1.errorCheck)(wfInst['setup'](cce.scopeContext));
}
}
catch (e) {
error = e;
}
for (const section of flowContexts) {
if (error) {
break;
}
try {
await (0, ts_dsl_1.errorCheck)(wfInst[section.property](cce.scopeContext));
}
catch (e) {
error = e;
break;
}
}
let postErrors = [];
if (!error) {
try {
if (wfInst['success']) {
await (0, ts_dsl_1.errorCheck)(wfInst['success'](cce.scopeContext));
}
}
catch (e) {
postErrors.push(e);
}
}
else {
try {
if (wfInst['failure']) {
await (0, ts_dsl_1.errorCheck)(wfInst['failure'](cce.scopeContext));
}
}
catch (e) {
postErrors.push(e);
}
}
try {
if (wfInst['cleanup']) {
await (0, ts_dsl_1.errorCheck)(wfInst['cleanup'](cce.scopeContext));
}
}
catch (e) {
postErrors.push(e);
}
if (error) {
return reject(error);
}
let pipelineReturn;
if (wfInst.finalReturn) {
pipelineReturn = await (0, ts_dsl_1.punchGrab)(wfInst.finalReturn());
}
resolve(pipelineReturn);
});
}
exports.runWorkflow__ = runWorkflow__;
function addFlowContext(workflowInstance, type, property, stageOptions) {
if (!workflowInstance.flowContexts) {
workflowInstance.flowContexts = [];
}
workflowInstance.flowContexts.push({ type, class: workflowInstance.constructor, property, stageOptions });
}
//# sourceMappingURL=pipeline.js.map
;