Skip to content

Commit

Permalink
Begin creating BullMQ jobs from workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
FyreByrd committed Oct 2, 2024
1 parent ca20797 commit f18f70a
Show file tree
Hide file tree
Showing 10 changed files with 275 additions and 49 deletions.
37 changes: 36 additions & 1 deletion source/SIL.AppBuilder.Portal/common/BullJobTypes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { Channels } from './build-engine-api/types.js';

export enum ScriptoriaJobType {
Test = 'Test',
ReassignUserTasks = 'ReassignUserTasks'
ReassignUserTasks = 'ReassignUserTasks',
CreateProduct = 'CreateProduct',
BuildProduct = 'BuildProduct',
EmailReviewers = 'EmailReviewers',
PublishProduct = 'PublishProduct'
}

export interface TestJob {
Expand All @@ -13,10 +19,39 @@ export interface SyncUserTasksJob {
projectId: number;
}

export interface CreateProductJob {
type: ScriptoriaJobType.CreateProduct;
productId: string;
}

export interface BuildProductJob {
type: ScriptoriaJobType.BuildProduct;
productId: string;
targets?: string;
environment: { [key: string]: string };
}

export interface EmailReviewersJob {
type: ScriptoriaJobType.EmailReviewers;
productId: string;
}

export interface PublishProductJob {
type: ScriptoriaJobType.PublishProduct;
productId: string;
channel: Channels;
targets: string;
environment: { [key: string]: any };
}

export type ScriptoriaJob = JobTypeMap[keyof JobTypeMap];

export type JobTypeMap = {
[ScriptoriaJobType.Test]: TestJob;
[ScriptoriaJobType.ReassignUserTasks]: SyncUserTasksJob;
[ScriptoriaJobType.CreateProduct]: CreateProductJob;
[ScriptoriaJobType.BuildProduct]: BuildProductJob;
[ScriptoriaJobType.EmailReviewers]: EmailReviewersJob;
[ScriptoriaJobType.PublishProduct]: PublishProductJob;
// Add more mappings here as needed
};
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,10 @@ export type BuildResponse = SuccessResponse &
artifacts: { [key: string]: string };
};

export type Channels = 'production' | 'beta' | 'alpha'

type ReleaseCommon = {
channel: 'production' | 'beta' | 'alpha';
channel: Channels;
targets: string;
};
export type ReleaseConfig = ReleaseCommon & {
Expand Down
27 changes: 13 additions & 14 deletions source/SIL.AppBuilder.Portal/common/public/workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,25 +84,23 @@ export type WorkflowContext = {
includeArtifacts: 'apk' | 'aab' | boolean;
start?: StateName;
adminLevel: RequiredAdminLevel;
environment: BuildEnv;
// Not sure how this is used, but will figure out when integrating into backend
environment: { [key: string]: any };
productType: ProductType;
productId: string;
};

// These are all specific to the Google Play workflows
// Not sure how these are used, but will figure out when integrating into backend
export type BuildEnv = {
googlePlayDraft?: boolean;
googlePlayExisting?: boolean;
googlePlayUploaded?: boolean;
};

export type WorkflowInput = {
export type WorkflowConfig = {
adminLevel: RequiredAdminLevel;
productType: ProductType;
};

export type WorkflowInput = WorkflowConfig & {
productId: string;
};

// TODO: Just put this info directly in the database
export function workflowInputFromDBProductType(workflowDefinitionId: number): WorkflowInput {
export function workflowInputFromDBProductType(workflowDefinitionId: number): WorkflowConfig {
switch (workflowDefinitionId) {
case 1: // sil_android_google_play
return {
Expand All @@ -113,7 +111,7 @@ export function workflowInputFromDBProductType(workflowDefinitionId: number): Wo
return {
adminLevel: RequiredAdminLevel.High,
productType: ProductType.Android_S3
};
};
case 6: // la_android_google_play
return {
adminLevel: RequiredAdminLevel.Low,
Expand Down Expand Up @@ -141,7 +139,9 @@ export function workflowInputFromDBProductType(workflowDefinitionId: number): Wo
productType: ProductType.AssetPackage
};
default: // would be some other workflow type presumably
console.log(`Unrecognized workflow definition: ${workflowDefinitionId}! Returning configuration for sil_android_google_play.`);
console.log(
`Unrecognized workflow definition: ${workflowDefinitionId}! Returning configuration for sil_android_google_play.`
);
return {
adminLevel: RequiredAdminLevel.High,
productType: ProductType.Android_GooglePlay
Expand Down Expand Up @@ -182,5 +182,4 @@ export type StateNode = {
export type Snapshot = {
value: string;
context: WorkflowContext;
input: WorkflowInput;
};
43 changes: 30 additions & 13 deletions source/SIL.AppBuilder.Portal/common/workflow/default-workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
WorkflowEvent
} from '../public/workflow.js';
import { RoleId } from '../public/prisma.js';
import { scriptoriaQueue } from '../index.js';
import { ScriptoriaJobType } from '../BullJobTypes.js';

/**
* IMPORTANT: READ THIS BEFORE EDITING A STATE MACHINE!
Expand Down Expand Up @@ -69,7 +71,8 @@ export const DefaultWorkflow = setup({
includeArtifacts: false,
environment: {},
productType: input.productType,
adminLevel: input.adminLevel
adminLevel: input.adminLevel,
productId: input.productId
}),
states: {
Start: {
Expand Down Expand Up @@ -303,9 +306,11 @@ export const DefaultWorkflow = setup({
'Product Creation': {
entry: [
assign({ instructions: 'waiting' }),
() => {
// TODO: hook into build engine
console.log('Creating Product');
({ context }) => {
scriptoriaQueue.add(`Create Product (${context.productId})`, {
type: ScriptoriaJobType.CreateProduct,
productId: context.productId
});
}
],
on: {
Expand Down Expand Up @@ -458,9 +463,13 @@ export const DefaultWorkflow = setup({
assign({
instructions: 'waiting'
}),
() => {
// TODO: hook into build engine
console.log('Building Product');
({ context }) => {
scriptoriaQueue.add(`Build Product (${context.productId})`, {
type: ScriptoriaJobType.BuildProduct,
productId: context.productId,
// TODO: assign targets
environment: context.environment
});
}
],
on: {
Expand Down Expand Up @@ -664,19 +673,27 @@ export const DefaultWorkflow = setup({
user: RoleId.AppBuilder
},
guard: { type: 'hasReviewers' },
actions: () => {
// TODO: connect to backend to email reviewers
console.log('Emailing Reviewers');
actions: ({ context }) => {
scriptoriaQueue.add(`Email Reviewers (Product: ${context.productId})`, {
type: ScriptoriaJobType.EmailReviewers,
productId: context.productId
});
}
}
}
},
'Product Publish': {
entry: [
assign({ instructions: 'waiting' }),
() => {
// TODO: hook into build engine
console.log('Publishing Product');
({ context }) => {
scriptoriaQueue.add(`Publish Product (${context.productId})`, {
type: ScriptoriaJobType.PublishProduct,
productId: context.productId,
// TODO: How should these values be determined?
channel: 'alpha',
targets: 'google-play',
environment: context.environment
});
}
],
on: {
Expand Down
21 changes: 9 additions & 12 deletions source/SIL.AppBuilder.Portal/common/workflow/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import DatabaseWrites from '../databaseProxy/index.js';
import {
WorkflowContext,
WorkflowInput,
WorkflowConfig,
RequiredAdminLevel,
ProductType,
ActionType,
Expand All @@ -33,15 +34,15 @@ export class Workflow {
private adminLevel: RequiredAdminLevel;
private productType: ProductType;

private constructor(productId: string, input: WorkflowInput) {
this.productId = productId;
private constructor(input: WorkflowInput) {
this.productId = input.productId;
this.adminLevel = input.adminLevel;
this.productType = input.productType;
}

/* PUBLIC METHODS */
/** Create a new workflow instance and populate the database tables. */
public static async create(productId: string, input: WorkflowInput): Promise<Workflow> {
public static async create(productId: string, input: WorkflowConfig): Promise<Workflow> {
DatabaseWrites.workflowInstances.upsert({
where: {
ProductId: productId
Expand All @@ -53,13 +54,13 @@ export class Workflow {
}
});

const flow = new Workflow(productId, input);
const flow = new Workflow({productId, ...input});

flow.flow = createActor(DefaultWorkflow, {
inspect: (e) => {
if (e.type === '@xstate.snapshot') flow.inspect(e);
},
input: input
input: {productId, ...input}
});

flow.flow.start();
Expand All @@ -69,13 +70,13 @@ export class Workflow {
/** Restore from a snapshot in the database. */
public static async restore(productId: string): Promise<Workflow> {
const snap = await Workflow.getSnapshot(productId);
const flow = new Workflow(productId, snap.input);
const flow = new Workflow(snap.context);
flow.flow = createActor(DefaultWorkflow, {
snapshot: snap ? DefaultWorkflow.resolveState(snap) : undefined,
inspect: (e) => {
if (e.type === '@xstate.snapshot') flow.inspect(e);
},
input: snap.input
input: snap.context
});

flow.flow.start();
Expand Down Expand Up @@ -209,11 +210,7 @@ export class Workflow {
data: {
Snapshot: JSON.stringify({
value: this.stateName(this.currentState),
context: context,
input: {
adminLevel: this.adminLevel,
productType: this.productType
}
context: context
} as Snapshot)
}
});
Expand Down
16 changes: 16 additions & 0 deletions source/SIL.AppBuilder.Portal/node-server/BullWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,22 @@ export class ScriptoriaWorker extends BullWorker<BullMQ.ScriptoriaJob, number> {
return new Executor.ReassignUserTasks().execute(
job as Job<BullMQ.SyncUserTasksJob, number, string>
);
case BullMQ.ScriptoriaJobType.CreateProduct:
return new Executor.CreateProduct().execute(
job as Job<BullMQ.CreateProductJob, number, string>
);
case BullMQ.ScriptoriaJobType.BuildProduct:
return new Executor.BuildProduct().execute(
job as Job<BullMQ.BuildProductJob, number, string>
);
case BullMQ.ScriptoriaJobType.PublishProduct:
return new Executor.PublishProduct().execute(
job as Job<BullMQ.PublishProductJob, number, string>
);
case BullMQ.ScriptoriaJobType.EmailReviewers:
return new Executor.EmailReviewers().execute(
job as Job<BullMQ.EmailReviewersJob, number, string>
);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export { Test } from './test.js';
export { ReassignUserTasks } from './reassignUserTasks.js';
export { ReassignUserTasks } from './reassignUserTasks.js';
export { EmailReviewers } from './reviewers.js';
export { CreateProduct, BuildProduct, PublishProduct } from './product.js';
Loading

0 comments on commit f18f70a

Please sign in to comment.