add createTestAutomation

This commit is contained in:
Charles Driesler
2024-05-28 13:20:10 +01:00
parent 960c646bee
commit 16dfefd0bd
7 changed files with 170 additions and 9 deletions
@@ -194,6 +194,12 @@ input ProjectAutomationCreateInput {
enabled: Boolean!
}
input ProjectTestAutomationCreateInput {
name: String!
modelId: String!
functionId: String!
}
input AutomateFunctionsFilter {
search: String
"""
@@ -287,8 +293,8 @@ type ProjectAutomationMutations {
just refer to the last version of the model.
"""
trigger(automationId: ID!): Boolean!
createTestAutomation(input: ProjectAutomationCreateInput!): Automation!
createTestAutomationRun(automationId: ID!): string!
createTestAutomation(input: ProjectTestAutomationCreateInput!): Automation!
# createTestAutomationRun(automationId: ID!): String!
}
extend type ProjectMutations {
@@ -27,6 +27,7 @@ import {
import {
createAutomation,
createAutomationRevision,
createTestAutomation,
getAutomationsStatus,
updateAutomation
} from '@/modules/automate/services/automationManagement'
@@ -472,6 +473,20 @@ export = {
})
return true
},
async createTestAutomation(parent, { input }, ctx) {
const create = createTestAutomation({
getFunction,
storeAutomation,
storeAutomationRevision
})
return await create({
input,
projectId: parent.projectId,
userId: ctx.userId!,
userResourceAccessRules: ctx.resourceAccessRules
})
}
},
Query: {
@@ -13,6 +13,7 @@ import { getServerOrigin } from '@/modules/shared/helpers/envHelper'
import cryptoRandomString from 'crypto-random-string'
import {
createAutomation as clientCreateAutomation,
getFunction,
getFunctionRelease,
getFunctionReleases
} from '@/modules/automate/clients/executionEngine'
@@ -22,7 +23,8 @@ import { createStoredAuthCode } from '@/modules/automate/services/executionEngin
import {
ProjectAutomationCreateInput,
ProjectAutomationRevisionCreateInput,
ProjectAutomationUpdateInput
ProjectAutomationUpdateInput,
ProjectTestAutomationCreateInput
} from '@/modules/core/graph/generated/graphql'
import { ContextResourceAccessRules } from '@/modules/core/helpers/token'
import {
@@ -47,6 +49,7 @@ import {
import { LibsodiumEncryptionError } from '@/modules/shared/errors/encryption'
import { validateInputAgainstFunctionSchema } from '@/modules/automate/utils/inputSchemaValidator'
import { AutomationsEmitter } from '@/modules/automate/events/automations'
import { validateAutomationName } from '@/modules/automate/utils/automationConfigurationValidator'
export type CreateAutomationDeps = {
createAuthCode: ReturnType<typeof createStoredAuthCode>
@@ -76,12 +79,7 @@ export const createAutomation =
storeAutomationToken
} = deps
const nameLength = name?.length || 0
if (nameLength < 1 || nameLength > 255) {
throw new AutomationCreationError(
'Automation name should be a string between the length of 1 and 255 characters.'
)
}
validateAutomationName(name)
await validateStreamAccess(
userId,
@@ -125,6 +123,99 @@ export const createAutomation =
return { automation: automationRecord, token: automationTokenRecord }
}
export type CreateTestAutomationDeps = {
getFunction: typeof getFunction
storeAutomation: typeof storeAutomation
storeAutomationRevision: typeof storeAutomationRevision
}
/** Create a test automation and its first revision in one request. */
export const createTestAutomation =
(deps: CreateTestAutomationDeps) =>
async (params: {
input: ProjectTestAutomationCreateInput
projectId: string
userId: string
userResourceAccessRules?: ContextResourceAccessRules
}) => {
const {
input: { name, functionId, modelId },
projectId,
userId,
userResourceAccessRules
} = params
const { getFunction, storeAutomation, storeAutomationRevision } = deps
validateAutomationName(name)
await validateStreamAccess(
userId,
projectId,
Roles.Stream.Owner,
userResourceAccessRules
)
// Get latest release for specified function
const { functionVersions: functionReleases } = await getFunction({ functionId })
if (!functionReleases || functionReleases.length === 0) {
// TODO: This should probably be okay for test automations
throw new AutomationCreationError(
'The specified function does not have any releases'
)
}
const latestFunctionRelease = functionReleases[0]
// Create and store the automation record
const automationId = cryptoRandomString({ length: 10 })
const automationRecord = await storeAutomation({
id: automationId,
name,
userId,
createdAt: new Date(),
updatedAt: new Date(),
enabled: true,
projectId,
executionEngineAutomationId: null,
isTestAutomation: true
})
await AutomationsEmitter.emit(AutomationsEmitter.events.Created, {
automation: automationRecord
})
// Create and store the automation revision
const automationRevisionRecord = await storeAutomationRevision({
functions: [
{
functionId,
functionReleaseId: latestFunctionRelease.functionVersionId,
functionInputs: null
}
],
triggers: [
{
triggerType: VersionCreationTriggerType,
triggeringId: modelId
}
],
automationId,
userId,
active: true,
// TODO: Should this be formally nullable?
publicKey: ''
})
await AutomationsEmitter.emit(AutomationsEmitter.events.CreatedRevision, {
automation: automationRecord,
revision: automationRevisionRecord
})
return automationRecord
}
export type UpdateAutomationDeps = {
getAutomation: typeof getAutomation
updateAutomation: typeof updateDbAutomation
@@ -0,0 +1,10 @@
import { AutomationCreationError } from '@/modules/automate/errors/management'
export const validateAutomationName = (automationName: string): void => {
const nameLength = automationName?.length || 0
if (nameLength < 1 || nameLength > 255) {
throw new AutomationCreationError(
'Automation name should be a string between the length of 1 and 255 characters.'
)
}
}
@@ -1795,6 +1795,7 @@ export type ProjectAutomationMutations = {
__typename?: 'ProjectAutomationMutations';
create: Automation;
createRevision: AutomationRevision;
createTestAutomation: Automation;
/**
* Trigger an automation with a fake "version created" trigger. The "version created" will
* just refer to the last version of the model.
@@ -1814,6 +1815,11 @@ export type ProjectAutomationMutationsCreateRevisionArgs = {
};
export type ProjectAutomationMutationsCreateTestAutomationArgs = {
input: ProjectTestAutomationCreateInput;
};
export type ProjectAutomationMutationsTriggerArgs = {
automationId: Scalars['ID'];
};
@@ -2100,6 +2106,12 @@ export enum ProjectPendingVersionsUpdatedMessageType {
Updated = 'UPDATED'
}
export type ProjectTestAutomationCreateInput = {
functionId: Scalars['String'];
modelId: Scalars['String'];
name: Scalars['String'];
};
export type ProjectTriggeredAutomationsStatusUpdatedMessage = {
__typename?: 'ProjectTriggeredAutomationsStatusUpdatedMessage';
model: Model;
@@ -3604,6 +3616,7 @@ export type ResolversTypes = {
ProjectPendingModelsUpdatedMessageType: ProjectPendingModelsUpdatedMessageType;
ProjectPendingVersionsUpdatedMessage: ResolverTypeWrapper<Omit<ProjectPendingVersionsUpdatedMessage, 'version'> & { version: ResolversTypes['FileUpload'] }>;
ProjectPendingVersionsUpdatedMessageType: ProjectPendingVersionsUpdatedMessageType;
ProjectTestAutomationCreateInput: ProjectTestAutomationCreateInput;
ProjectTriggeredAutomationsStatusUpdatedMessage: ResolverTypeWrapper<ProjectTriggeredAutomationsStatusUpdatedMessageGraphQLReturn>;
ProjectTriggeredAutomationsStatusUpdatedMessageType: ProjectTriggeredAutomationsStatusUpdatedMessageType;
ProjectUpdateInput: ProjectUpdateInput;
@@ -3811,6 +3824,7 @@ export type ResolversParentTypes = {
ProjectMutations: MutationsObjectGraphQLReturn;
ProjectPendingModelsUpdatedMessage: Omit<ProjectPendingModelsUpdatedMessage, 'model'> & { model: ResolversParentTypes['FileUpload'] };
ProjectPendingVersionsUpdatedMessage: Omit<ProjectPendingVersionsUpdatedMessage, 'version'> & { version: ResolversParentTypes['FileUpload'] };
ProjectTestAutomationCreateInput: ProjectTestAutomationCreateInput;
ProjectTriggeredAutomationsStatusUpdatedMessage: ProjectTriggeredAutomationsStatusUpdatedMessageGraphQLReturn;
ProjectUpdateInput: ProjectUpdateInput;
ProjectUpdateRoleInput: ProjectUpdateRoleInput;
@@ -4579,6 +4593,7 @@ export type ProjectResolvers<ContextType = GraphQLContext, ParentType extends Re
export type ProjectAutomationMutationsResolvers<ContextType = GraphQLContext, ParentType extends ResolversParentTypes['ProjectAutomationMutations'] = ResolversParentTypes['ProjectAutomationMutations']> = {
create?: Resolver<ResolversTypes['Automation'], ParentType, ContextType, RequireFields<ProjectAutomationMutationsCreateArgs, 'input'>>;
createRevision?: Resolver<ResolversTypes['AutomationRevision'], ParentType, ContextType, RequireFields<ProjectAutomationMutationsCreateRevisionArgs, 'input'>>;
createTestAutomation?: Resolver<ResolversTypes['Automation'], ParentType, ContextType, RequireFields<ProjectAutomationMutationsCreateTestAutomationArgs, 'input'>>;
trigger?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType, RequireFields<ProjectAutomationMutationsTriggerArgs, 'automationId'>>;
update?: Resolver<ResolversTypes['Automation'], ParentType, ContextType, RequireFields<ProjectAutomationMutationsUpdateArgs, 'input'>>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
@@ -1784,6 +1784,7 @@ export type ProjectAutomationMutations = {
__typename?: 'ProjectAutomationMutations';
create: Automation;
createRevision: AutomationRevision;
createTestAutomation: Automation;
/**
* Trigger an automation with a fake "version created" trigger. The "version created" will
* just refer to the last version of the model.
@@ -1803,6 +1804,11 @@ export type ProjectAutomationMutationsCreateRevisionArgs = {
};
export type ProjectAutomationMutationsCreateTestAutomationArgs = {
input: ProjectTestAutomationCreateInput;
};
export type ProjectAutomationMutationsTriggerArgs = {
automationId: Scalars['ID'];
};
@@ -2089,6 +2095,12 @@ export enum ProjectPendingVersionsUpdatedMessageType {
Updated = 'UPDATED'
}
export type ProjectTestAutomationCreateInput = {
functionId: Scalars['String'];
modelId: Scalars['String'];
name: Scalars['String'];
};
export type ProjectTriggeredAutomationsStatusUpdatedMessage = {
__typename?: 'ProjectTriggeredAutomationsStatusUpdatedMessage';
model: Model;
@@ -1785,6 +1785,7 @@ export type ProjectAutomationMutations = {
__typename?: 'ProjectAutomationMutations';
create: Automation;
createRevision: AutomationRevision;
createTestAutomation: Automation;
/**
* Trigger an automation with a fake "version created" trigger. The "version created" will
* just refer to the last version of the model.
@@ -1804,6 +1805,11 @@ export type ProjectAutomationMutationsCreateRevisionArgs = {
};
export type ProjectAutomationMutationsCreateTestAutomationArgs = {
input: ProjectTestAutomationCreateInput;
};
export type ProjectAutomationMutationsTriggerArgs = {
automationId: Scalars['ID'];
};
@@ -2090,6 +2096,12 @@ export enum ProjectPendingVersionsUpdatedMessageType {
Updated = 'UPDATED'
}
export type ProjectTestAutomationCreateInput = {
functionId: Scalars['String'];
modelId: Scalars['String'];
name: Scalars['String'];
};
export type ProjectTriggeredAutomationsStatusUpdatedMessage = {
__typename?: 'ProjectTriggeredAutomationsStatusUpdatedMessage';
model: Model;