Add support for output templating
Co-authored-by: Fredrik Adelöw <freben@gmail.com> Co-authored-by: blam<ben@blam.sh> Co-authored-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -50,6 +50,7 @@
|
||||
"fs-extra": "^9.0.0",
|
||||
"git-url-parse": "^11.4.4",
|
||||
"globby": "^11.0.0",
|
||||
"handlebars": "^4.7.6",
|
||||
"helmet": "^4.0.0",
|
||||
"isomorphic-git": "^1.8.0",
|
||||
"jsonschema": "^1.2.6",
|
||||
@@ -66,9 +67,9 @@
|
||||
"@types/mock-fs": "^4.13.0",
|
||||
"@types/supertest": "^2.0.8",
|
||||
"mock-fs": "^4.13.0",
|
||||
"msw": "^0.21.2",
|
||||
"supertest": "^4.0.2",
|
||||
"yaml": "^1.10.0",
|
||||
"msw": "^0.21.2"
|
||||
"yaml": "^1.10.0"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -63,11 +63,17 @@ export class TaskAgent implements Task {
|
||||
});
|
||||
}
|
||||
|
||||
async complete(result: CompletedTaskState): Promise<void> {
|
||||
async complete(
|
||||
result: CompletedTaskState,
|
||||
metadata?: JsonObject,
|
||||
): Promise<void> {
|
||||
await this.storage.completeTask({
|
||||
taskId: this.state.taskId,
|
||||
status: result === 'failed' ? 'failed' : 'completed',
|
||||
eventBody: { message: `Run completed with status: ${result}` },
|
||||
eventBody: {
|
||||
message: `Run completed with status: ${result}`,
|
||||
...metadata,
|
||||
},
|
||||
});
|
||||
this.isDone = true;
|
||||
if (this.heartbeatTimeoutId) {
|
||||
|
||||
@@ -22,6 +22,7 @@ import { TaskBroker, Task } from './types';
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import { TemplateActionRegistry } from './TemplateConverter';
|
||||
import * as handlebars from 'handlebars';
|
||||
|
||||
type Options = {
|
||||
logger: Logger;
|
||||
@@ -55,7 +56,11 @@ export class TaskWorker {
|
||||
`Starting up work with ${task.spec.steps.length} steps`,
|
||||
);
|
||||
|
||||
const outputs: { [name: string]: JsonValue } = {};
|
||||
const templateCtx: {
|
||||
steps: {
|
||||
[stepName: string]: { output: { [outputName: string]: JsonValue } };
|
||||
};
|
||||
} = { steps: {} };
|
||||
|
||||
for (const step of task.spec.steps) {
|
||||
const metadata = { stepId: step.id };
|
||||
@@ -87,8 +92,24 @@ export class TaskWorker {
|
||||
throw new Error(`Action '${step.action}' does not exist`);
|
||||
}
|
||||
|
||||
// TODO: substitute any placeholders with output from previous steps
|
||||
const parameters = step.parameters!;
|
||||
const parameters: { [name: string]: JsonValue } = {};
|
||||
for (const [name, maybeTemplateStr] of Object.entries(
|
||||
step.parameters ?? {},
|
||||
)) {
|
||||
if (typeof maybeTemplateStr === 'string') {
|
||||
const value = handlebars.compile(maybeTemplateStr, {
|
||||
noEscape: true,
|
||||
strict: true,
|
||||
data: false,
|
||||
preventIndent: true,
|
||||
})(templateCtx);
|
||||
parameters[name] = value;
|
||||
} else {
|
||||
parameters[name] = maybeTemplateStr;
|
||||
}
|
||||
}
|
||||
|
||||
const stepOutputs: { [name: string]: JsonValue } = {};
|
||||
|
||||
await action.handler({
|
||||
logger,
|
||||
@@ -96,10 +117,12 @@ export class TaskWorker {
|
||||
parameters,
|
||||
workspacePath,
|
||||
output(name: string, value: JsonValue) {
|
||||
outputs[name] = value;
|
||||
stepOutputs[name] = value;
|
||||
},
|
||||
});
|
||||
|
||||
templateCtx.steps[step.id] = { output: stepOutputs };
|
||||
|
||||
await task.emitLog(`Finished step ${step.name}`, {
|
||||
...metadata,
|
||||
status: 'completed',
|
||||
@@ -112,9 +135,24 @@ export class TaskWorker {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
await task.complete('completed');
|
||||
|
||||
const output = Object.fromEntries(
|
||||
Object.entries(task.spec.output).map(([name, templateStr]) => {
|
||||
const value = handlebars.compile(templateStr, {
|
||||
noEscape: true,
|
||||
strict: true,
|
||||
data: false,
|
||||
preventIndent: true,
|
||||
})(templateCtx);
|
||||
return [name, value];
|
||||
}),
|
||||
);
|
||||
|
||||
await task.complete('completed', { output });
|
||||
} catch (error) {
|
||||
await task.complete('failed');
|
||||
await task.complete('failed', {
|
||||
error: { name: error.name, message: error.message },
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,13 @@ export function templateEntityToSpec(
|
||||
},
|
||||
});
|
||||
|
||||
return { steps };
|
||||
return {
|
||||
steps,
|
||||
output: {
|
||||
remoteUrl: '{{ steps.publish.output.remoteUrl }}',
|
||||
catalogInfoUrl: '{{ steps.publish.output.catalogInfoUrl }}',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
type ActionContext = {
|
||||
|
||||
@@ -49,6 +49,7 @@ export type TaskSpec = {
|
||||
action: string;
|
||||
parameters?: { [name: string]: JsonValue };
|
||||
}>;
|
||||
output: { [name: string]: string };
|
||||
};
|
||||
|
||||
export type DispatchResult = {
|
||||
@@ -59,7 +60,7 @@ export interface Task {
|
||||
spec: TaskSpec;
|
||||
done: boolean;
|
||||
emitLog(message: string, metadata?: JsonValue): Promise<void>;
|
||||
complete(result: CompletedTaskState): Promise<void>;
|
||||
complete(result: CompletedTaskState, metadata?: JsonValue): Promise<void>;
|
||||
getWorkspaceName(): Promise<string>;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user