diff --git a/.github/workflows/dispatch-integration-test.yml b/.github/workflows/dispatch-integration-test.yml new file mode 100644 index 000000000..6fe4904d7 --- /dev/null +++ b/.github/workflows/dispatch-integration-test.yml @@ -0,0 +1,23 @@ +name: Run if-check on requested branch + +on: + workflow_dispatch: + +jobs: + run: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 18 + cache: 'npm' + + - name: Install dependencies + run: npm install + + - name: Run integration tests + run: npm run if-check -- -d manifests/outputs diff --git a/manifests/examples/builtins/time-sync/success.yml b/manifests/examples/builtins/time-sync/success.yml index 6d1841e97..90b80580f 100644 --- a/manifests/examples/builtins/time-sync/success.yml +++ b/manifests/examples/builtins/time-sync/success.yml @@ -1,23 +1,16 @@ name: time-sync description: successful path tags: +'time-sync': + start-time: '2023-12-12T00:00:00.000Z' + end-time: '2023-12-12T00:01:00.000Z' + interval: 5 + allow-padding: true initialize: - output: - - yaml - plugins: - 'time-sync': - method: TimeSync - path: "builtin" - global-config: - start-time: '2023-12-12T00:00:00.000Z' - end-time: '2023-12-12T00:01:00.000Z' - interval: 5 - allow-padding: true + plugins: {} tree: children: child: - pipeline: - - time-sync config: inputs: - timestamp: '2023-12-12T00:00:00.000Z' diff --git a/src/__tests__/if-run/lib/compute.test.ts b/src/__tests__/if-run/lib/compute.test.ts index b019d4c67..1549f22f8 100644 --- a/src/__tests__/if-run/lib/compute.test.ts +++ b/src/__tests__/if-run/lib/compute.test.ts @@ -19,6 +19,59 @@ describe('lib/compute: ', () => { kind: 'execute', }, }); + const mockObservePlugin = () => ({ + execute: () => [ + {timestamp: '2024-09-02', duration: 40, 'cpu/utilization': 30}, + {timestamp: '2024-09-03', duration: 60, 'cpu/utilization': 40}, + ], + metadata: { + kind: 'execute', + }, + }); + const mockObservePluginTimeSync = () => ({ + execute: () => [ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 60, + 'cpu/utilization': 30, + }, + { + timestamp: '2023-12-12T00:01:00.000Z', + duration: 60, + 'cpu/utilization': 40, + }, + ], + metadata: { + kind: 'execute', + }, + }); + const mockTimeSync = () => ({ + execute: () => [ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 30, + 'cpu/utilization': 30, + }, + { + timestamp: '2023-12-12T00:00:30.000Z', + duration: 30, + 'cpu/utilization': 30, + }, + { + timestamp: '2023-12-12T00:01:00.000Z', + duration: 30, + 'cpu/utilization': 40, + }, + { + timestamp: '2023-12-12T00:01:30.000Z', + duration: 30, + 'cpu/utilization': 40, + }, + ], + metadata: { + kind: 'execute', + }, + }); /** * Compute params. */ @@ -35,7 +88,11 @@ describe('lib/compute: ', () => { }, }, }, - pluginStorage: pluginStorage().set('mock', mockExecutePlugin()), + pluginStorage: pluginStorage() + .set('mock', mockExecutePlugin()) + .set('mock-observe', mockObservePlugin()) + .set('mock-observe-time-sync', mockObservePluginTimeSync()) + .set('time-sync', mockTimeSync()), }; describe('compute(): ', () => { @@ -221,4 +278,77 @@ describe('lib/compute: ', () => { expect(response.children.mockChild.outputs).toEqual(expectedResult); }); }); + + it('computes simple tree with observe plugin.', async () => { + const tree = { + children: { + mockChild: { + pipeline: {observe: ['mock-observe']}, + }, + }, + }; + + const response = await compute(tree, paramsExecute); + const expectedResult = [ + {timestamp: '2024-09-02', duration: 40, 'cpu/utilization': 30}, + {timestamp: '2024-09-03', duration: 60, 'cpu/utilization': 40}, + ]; + + expect(response.children.mockChild.inputs).toEqual(expectedResult); + }); + + it('computes simple tree with time sync plugin.', async () => { + const tree = { + children: { + mockChild: { + pipeline: {observe: ['mock-observe-time-sync']}, + }, + }, + }; + const timeSync = { + 'start-time': '2023-12-12T00:00:00.000Z', + 'end-time': '2023-12-12T00:02:00.000Z', + interval: 5, + 'allow-padding': true, + }; + + const response = await compute(tree, {...paramsExecute, timeSync}); + const expectedInputs = [ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 60, + 'cpu/utilization': 30, + }, + { + timestamp: '2023-12-12T00:01:00.000Z', + duration: 60, + 'cpu/utilization': 40, + }, + ]; + const expectedOutput = [ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 30, + 'cpu/utilization': 30, + }, + { + timestamp: '2023-12-12T00:00:30.000Z', + duration: 30, + 'cpu/utilization': 30, + }, + { + timestamp: '2023-12-12T00:01:00.000Z', + duration: 30, + 'cpu/utilization': 40, + }, + { + timestamp: '2023-12-12T00:01:30.000Z', + duration: 30, + 'cpu/utilization': 40, + }, + ]; + + expect(response.children.mockChild.inputs).toEqual(expectedInputs); + expect(response.children.mockChild.outputs).toEqual(expectedOutput); + }); }); diff --git a/src/__tests__/if-run/lib/initialize.test.ts b/src/__tests__/if-run/lib/initialize.test.ts index f00142260..0eccda08b 100644 --- a/src/__tests__/if-run/lib/initialize.test.ts +++ b/src/__tests__/if-run/lib/initialize.test.ts @@ -18,7 +18,6 @@ import {ERRORS} from '@grnsft/if-core/utils'; import {initialize} from '../../../if-run/lib/initialize'; import {STRINGS} from '../../../if-run/config'; -import {GlobalPlugins} from '../../../common/types/manifest'; const { MissingPluginPathError, @@ -30,8 +29,9 @@ const {MISSING_METHOD, MISSING_PATH, INVALID_MODULE_PATH} = STRINGS; describe('lib/initalize: ', () => { describe('initalize(): ', () => { it('creates instance with get and set methods.', async () => { - const plugins = {}; - const response = await initialize(plugins); + const context = {initialize: {plugins: {}}}; + // @ts-ignore + const response = await initialize(context); expect(response).toHaveProperty('get'); expect(response).toHaveProperty('set'); @@ -40,15 +40,20 @@ describe('lib/initalize: ', () => { }); it('checks if plugin is initalized, warning is logged and plugin has execute and metadata props.', async () => { - const plugins: GlobalPlugins = { - mockavizta: { - path: 'mockavizta', - method: 'Mockavizta', + const context = { + initialize: { + plugins: { + mockavizta: { + path: 'mockavizta', + method: 'Mockavizta', + }, + }, }, }; - const storage = await initialize(plugins); + // @ts-ignore + const storage = await initialize(context); - const pluginName = Object.keys(plugins)[0]; + const pluginName = Object.keys(context.initialize.plugins)[0]; const module = storage.get(pluginName); expect(module).toHaveProperty('execute'); expect(module).toHaveProperty('metadata'); @@ -56,36 +61,45 @@ describe('lib/initalize: ', () => { }); it('checks if plugin is initalized with global config and has execute and metadata.', async () => { - const plugins: GlobalPlugins = { - mockavizta: { - path: 'mockavizta', - method: 'Mockavizta', - 'global-config': { - verbose: true, + const context = { + initialize: { + plugins: { + mockavizta: { + path: 'mockavizta', + method: 'Mockavizta', + 'global-config': { + verbose: true, + }, + }, }, }, }; - const storage = await initialize(plugins); + // @ts-ignore + const storage = await initialize(context); - const pluginName = Object.keys(plugins)[0]; + const pluginName = Object.keys(context.initialize.plugins)[0]; const module = storage.get(pluginName); expect(module).toHaveProperty('execute'); expect(module).toHaveProperty('metadata'); }); it('throws error if plugin does not have path property.', async () => { - const plugins: GlobalPlugins = { - // @ts-ignore - mockavizta: { - method: 'Mockavizta', - 'global-config': { - verbose: true, + const context = { + initialize: { + plugins: { + mockavizta: { + method: 'Mockavizta', + 'global-config': { + verbose: true, + }, + }, }, }, }; try { - await initialize(plugins); + // @ts-ignore + await initialize(context); } catch (error) { expect(error).toBeInstanceOf(MissingPluginPathError); @@ -96,18 +110,22 @@ describe('lib/initalize: ', () => { }); it('throws error if plugin does not have path property.', async () => { - const plugins: GlobalPlugins = { - // @ts-ignore - mockavizta: { - path: 'mockavizta', - 'global-config': { - verbose: true, + const context = { + initialize: { + plugins: { + mockavizta: { + path: 'mockavizta', + 'global-config': { + verbose: true, + }, + }, }, }, }; try { - await initialize(plugins); + // @ts-ignore + await initialize(context); } catch (error) { expect(error).toBeInstanceOf(MissingPluginMethodError); @@ -118,59 +136,115 @@ describe('lib/initalize: ', () => { }); it('checks if builtin plugin is initalized.', async () => { - const plugins: GlobalPlugins = { - mockavizta: { - path: 'builtin', - method: 'Mockavizta', - 'global-config': { - verbose: true, + const context = { + initialize: { + plugins: { + mockavizta: { + path: 'builtin', + method: 'Mockavizta', + 'global-config': { + verbose: true, + }, + }, }, }, }; - const storage = await initialize(plugins); + // @ts-ignore + const storage = await initialize(context); - const pluginName = Object.keys(plugins)[0]; + const pluginName = Object.keys(context.initialize.plugins)[0]; const module = storage.get(pluginName); expect(module).toHaveProperty('execute'); expect(module).toHaveProperty('metadata'); }); + it('checks if time sync plugin is initalized.', async () => { + const context = { + initialize: { + plugins: { + 'time-sync': { + path: 'lib/time-sync', + method: 'TimeSync', + 'global-config': {}, + }, + }, + }, + }; + // @ts-ignore + const storage = await initialize(context); + + const pluginName = Object.keys(context.initialize.plugins)[0]; + const module = storage.get(pluginName); + expect(module).toHaveProperty('execute'); + expect(module).toHaveProperty('metadata'); + }); + + it('initalizes time sync based on context.', async () => { + const context = { + initialize: { + plugins: {}, + }, + 'time-sync': { + 'start-time': '2024-09-04', + 'end-time': '2024-09-05', + 'allow-padding': true, + interval: 5, + }, + }; + // @ts-ignore + const storage = await initialize(context); + const module = storage.get('time-sync'); + + expect(module).toHaveProperty('execute'); + expect(module).toHaveProperty('metadata'); + }); + it('checks if github plugin is initalized.', async () => { - const plugins: GlobalPlugins = { - mockavizta: { - path: 'https://github.com/mockavizta', - method: 'Mockavizta', - 'global-config': { - verbose: true, + const context = { + initialize: { + plugins: { + mockavizta: { + path: 'https://github.com/mockavizta', + method: 'Mockavizta', + 'global-config': { + verbose: true, + }, + }, }, }, }; - const storage = await initialize(plugins); + // @ts-ignore + const storage = await initialize(context); - const pluginName = Object.keys(plugins)[0]; + const pluginName = Object.keys(context.initialize.plugins)[0]; const module = storage.get(pluginName); expect(module).toHaveProperty('execute'); expect(module).toHaveProperty('metadata'); }); it('throws error if plugin path is invalid.', async () => { - const plugins: GlobalPlugins = { - mockavizta: { - path: 'failing-mock', - method: 'Mockavizta', - 'global-config': { - verbose: true, + const context = { + initialize: { + plugins: { + mockavizta: { + path: 'failing-mock', + method: 'Mockavizta', + 'global-config': { + verbose: true, + }, + }, }, }, }; try { - await initialize(plugins); + // @ts-ignore + await initialize(context); } catch (error: any) { expect(error).toBeInstanceOf(PluginInitializationError); expect(error.message).toEqual( INVALID_MODULE_PATH( - plugins.mockavizta.path, + context.initialize.plugins.mockavizta.path, new Error( "Cannot find module 'failing-mock' from 'src/if-run/lib/initialize.ts'" ) diff --git a/src/__tests__/if-run/builtins/time-sync.test.ts b/src/__tests__/if-run/lib/time-sync.test.ts similarity index 99% rename from src/__tests__/if-run/builtins/time-sync.test.ts rename to src/__tests__/if-run/lib/time-sync.test.ts index 314ed06d4..2d5a9c983 100644 --- a/src/__tests__/if-run/builtins/time-sync.test.ts +++ b/src/__tests__/if-run/lib/time-sync.test.ts @@ -4,7 +4,7 @@ import {Settings, DateTime} from 'luxon'; import {AggregationParams} from '../../../common/types/manifest'; import {storeAggregationMetrics} from '../../../if-run/lib/aggregate'; -import {TimeSync} from '../../../if-run/builtins/time-sync'; +import {TimeSync} from '../../../if-run/lib/time-sync'; import {STRINGS} from '../../../if-run/config'; diff --git a/src/common/util/validations.ts b/src/common/util/validations.ts index 9f2d4c495..1907ed82f 100644 --- a/src/common/util/validations.ts +++ b/src/common/util/validations.ts @@ -51,40 +51,51 @@ export const manifestSchema = z.object({ }) .optional() .nullable(), + 'time-sync': z + .object({ + 'start-time': z.string(), + 'end-time': z.string(), + interval: z.number().gt(0), + 'allow-padding': z.boolean(), + }) + .optional() + .nullable(), initialize: z.object({ plugins: z.record( z.string(), - z.object({ - path: z.string(), - method: z.string(), - 'global-config': z.record(z.string(), z.any()).optional(), - 'parameter-metadata': z - .object({ - inputs: z - .record( - z.string(), - z.object({ - unit: z.string(), - description: z.string(), - 'aggregation-method': z.string(), - }) - ) - .optional() - .nullable(), - outputs: z - .record( - z.string(), - z.object({ - unit: z.string(), - description: z.string(), - 'aggregation-method': z.string(), - }) - ) - .optional() - .nullable(), - }) - .optional(), - }) + z + .object({ + path: z.string(), + method: z.string(), + 'global-config': z.record(z.string(), z.any()).optional(), + 'parameter-metadata': z + .object({ + inputs: z + .record( + z.string(), + z.object({ + unit: z.string(), + description: z.string(), + 'aggregation-method': z.string(), + }) + ) + .optional() + .nullable(), + outputs: z + .record( + z.string(), + z.object({ + unit: z.string(), + description: z.string(), + 'aggregation-method': z.string(), + }) + ) + .optional() + .nullable(), + }) + .optional(), + }) + .optional() ), }), execution: z diff --git a/src/if-run/builtins/index.ts b/src/if-run/builtins/index.ts index a8ccc76fd..49b30c882 100644 --- a/src/if-run/builtins/index.ts +++ b/src/if-run/builtins/index.ts @@ -1,4 +1,3 @@ -export {TimeSync} from './time-sync'; export {Interpolation} from './interpolation'; export {MockObservations} from './mock-observations'; export {Divide} from './divide'; diff --git a/src/if-run/config/strings.ts b/src/if-run/config/strings.ts index 24835f8ed..59354912b 100644 --- a/src/if-run/config/strings.ts +++ b/src/if-run/config/strings.ts @@ -47,6 +47,7 @@ Note that for the '--output' option you also need to define the output type in y CHECKING_AGGREGATION_METHOD: (unitName: string) => `Checking aggregation method for ${unitName}`, INITIALIZING_PLUGINS: 'Initializing plugins', + INITIALIZING_TIME_SYNC: 'Initializing time synchronization', INITIALIZING_PLUGIN: (pluginName: string) => `Initializing ${pluginName}`, LOADING_PLUGIN_FROM_PATH: (pluginName: string, path: string) => `Loading ${pluginName} from ${path}`, diff --git a/src/if-run/index.ts b/src/if-run/index.ts index 732cc9fec..293fef905 100644 --- a/src/if-run/index.ts +++ b/src/if-run/index.ts @@ -41,15 +41,20 @@ const impactEngine = async () => { try { const {tree, ...context} = validateManifest(envManifest); - const pluginStorage = await initialize(context.initialize.plugins); + const pluginStorage = await initialize(context); const computedTree = await compute(tree, { context, pluginStorage, observe, regroup, compute: computeFlag, + timeSync: context['time-sync'], }); + if (context['time-sync']) { + delete context.initialize.plugins['time-sync']; + } + if (context.aggregation) { storeAggregationMetrics({metrics: context.aggregation?.metrics}); } diff --git a/src/if-run/lib/compute.ts b/src/if-run/lib/compute.ts index dfd742ef4..7840a80bd 100644 --- a/src/if-run/lib/compute.ts +++ b/src/if-run/lib/compute.ts @@ -75,7 +75,7 @@ const computeNode = async (node: Node, params: ComputeParams): Promise => { let inputStorage = structuredClone(node.inputs) as PluginParams[]; inputStorage = mergeDefaults(inputStorage, defaults); - const pipelineCopy = structuredClone(pipeline); + const pipelineCopy = structuredClone(pipeline) || {}; /** * If iteration is on observe pipeline, then executes observe plugins and sets the inputs value. @@ -88,17 +88,16 @@ const computeNode = async (node: Node, params: ComputeParams): Promise => { if (isExecute(plugin)) { inputStorage = await plugin.execute(inputStorage, nodeConfig); + node.inputs = inputStorage; if (params.context.explainer) { addExplainData({ pluginName, metadata: plugin.metadata, - pluginData: params.context.initialize.plugins[pluginName], + pluginData: params.context.initialize!.plugins[pluginName], }); } - debugLogger.setExecutingPluginName(); - node.outputs = inputStorage; } } @@ -107,8 +106,8 @@ const computeNode = async (node: Node, params: ComputeParams): Promise => { /** * If regroup is requested, execute regroup strategy, delete child's inputs, outputs and empty regroup array. */ - if ((noFlags || params.regroup) && pipeline.regroup) { - node.children = Regroup(inputStorage, pipeline.regroup); + if ((noFlags || params.regroup) && pipelineCopy.regroup) { + node.children = Regroup(inputStorage, pipelineCopy.regroup); delete node.inputs; delete node.outputs; @@ -123,6 +122,16 @@ const computeNode = async (node: Node, params: ComputeParams): Promise => { }); } + /** + * Adds `time-sync` as the first plugin of compute phase if requested. + */ + if (params.timeSync) { + pipelineCopy.compute = [ + 'time-sync', + ...((pipelineCopy && pipelineCopy.compute) || []), + ]; + } + /** * If iteration is on compute plugin, then executes compute plugins and sets the outputs value. */ diff --git a/src/if-run/lib/explain.ts b/src/if-run/lib/explain.ts index add1a02b6..dce49b75a 100644 --- a/src/if-run/lib/explain.ts +++ b/src/if-run/lib/explain.ts @@ -30,8 +30,8 @@ export const addExplainData = (params: ExplainParams) => { const {pluginName, pluginData, metadata} = params; const plugin = { [pluginName]: { - method: pluginData.method, - path: pluginData.path, + method: pluginData!.method, + path: pluginData!.path, inputs: metadata?.inputs || 'undefined', outputs: metadata?.outputs || 'undefined', }, diff --git a/src/if-run/lib/initialize.ts b/src/if-run/lib/initialize.ts index 5adcc2b18..afa93a2da 100644 --- a/src/if-run/lib/initialize.ts +++ b/src/if-run/lib/initialize.ts @@ -9,7 +9,7 @@ import {pluginStorage} from '../util/plugin-storage'; import {CONFIG, STRINGS} from '../config'; import {PluginInterface} from '../types/interface'; -import {GlobalPlugins, PluginOptions} from '../../common/types/manifest'; +import {Context, PluginOptions} from '../../common/types/manifest'; import {PluginStorageInterface} from '../types/plugin-storage'; const { @@ -27,6 +27,7 @@ const { LOADING_PLUGIN_FROM_PATH, INITIALIZING_PLUGIN, INITIALIZING_PLUGINS, + INITIALIZING_TIME_SYNC, } = STRINGS; /** @@ -59,6 +60,8 @@ const handModule = (method: string, pluginPath: string) => { if (pluginPath === 'builtin') { pluginPath = path.normalize(`${__dirname}/../builtins`); + } else if (pluginPath === 'lib/time-sync') { + pluginPath = path.normalize(`${__dirname}/../${pluginPath}`); } else { if (pluginPath?.startsWith(GITHUB_PATH)) { const parts = pluginPath.split('/'); @@ -84,7 +87,7 @@ const initPlugin = async ( path, 'global-config': globalConfig, 'parameter-metadata': parameterMetadata, - } = initPluginParams; + } = initPluginParams!; console.debug(INITIALIZING_PLUGIN(method)); @@ -105,12 +108,24 @@ const initPlugin = async ( * Registers all plugins from `manifest`.`initialize` property. */ export const initialize = async ( - plugins: GlobalPlugins + context: Context ): Promise => { console.debug(INITIALIZING_PLUGINS); - + const {plugins} = context.initialize; const storage = pluginStorage(); + /** + * If `time-sync` is requested, then add it to plugins. + */ + if (context['time-sync']) { + console.debug(INITIALIZING_TIME_SYNC); + plugins['time-sync'] = { + path: 'lib/time-sync', + method: 'TimeSync', + 'global-config': context['time-sync'], + }; + } + for await (const pluginName of Object.keys(plugins)) { const plugin = await initPlugin(plugins[pluginName]); storage.set(pluginName, plugin); diff --git a/src/if-run/builtins/time-sync.ts b/src/if-run/lib/time-sync.ts similarity index 94% rename from src/if-run/builtins/time-sync.ts rename to src/if-run/lib/time-sync.ts index 9d589c491..e9f4ee1bc 100644 --- a/src/if-run/builtins/time-sync.ts +++ b/src/if-run/lib/time-sync.ts @@ -36,6 +36,21 @@ const { INVALID_DATETIME, } = STRINGS; +/** + * Time synchronization plugin converted into framework integrated tool. + * It can't be requested in `initialize.plugins` section anymore. Instead describe configuration in context. + * @example + * ```yaml + * name: time-sync + * description: sample in time sync lib + * tags: sample, time, sync + * time-sync: + * start-time: '2023-12-12T00:00:00.000Z' + * end-time: '2023-12-12T00:01:00.000Z' + * interval: 5 + * allow-padding: true + * ``` + */ export const TimeSync = ( globalConfig: TimeNormalizerConfig, parametersMetadata: PluginParametersMetadata @@ -131,14 +146,16 @@ export const TimeSync = ( return resampleInputs(sortedInputs, timeParams) as PluginParams[]; }; + /** + * Dates are passed to `time-sync` both in ISO 8601 format + * and as a Date object (from the deserialization of a YAML file). + * If the YAML parser fails to identify as a date, it passes as a string. + */ const parseDate = (date: Date | string) => { if (!date) { return DateTime.invalid('Invalid date'); } - // dates are passed to time-sync.ts both in ISO 8601 format - // and as a Date object (from the deserialization of a YAML file) - // if the YAML parser fails to identify as a date, it passes as a string if (isDate(date)) { return DateTime.fromJSDate(date); } diff --git a/src/if-run/types/compute.ts b/src/if-run/types/compute.ts index 6777bf553..da31b2635 100644 --- a/src/if-run/types/compute.ts +++ b/src/if-run/types/compute.ts @@ -13,6 +13,13 @@ export type PhasedPipeline = { compute?: string[]; }; +type TimeSyncConfig = { + 'start-time': string; + 'end-time': string; + interval: number; + 'allow-padding': boolean; +}; + export type ComputeParams = { pluginStorage: PluginStorageInterface; context: Context; @@ -22,6 +29,7 @@ export type ComputeParams = { observe?: Boolean; regroup?: Boolean; compute?: Boolean; + timeSync?: TimeSyncConfig | undefined | null; }; export type Node = { diff --git a/src/if-run/types/explain.ts b/src/if-run/types/explain.ts index b1b684882..c7f1a6d38 100644 --- a/src/if-run/types/explain.ts +++ b/src/if-run/types/explain.ts @@ -1,7 +1,9 @@ import {ParameterMetadata} from '@grnsft/if-core/types'; +import {PluginOptions} from '../../common/types/manifest'; + export type ExplainParams = { pluginName: string; - pluginData: {method: string; path: string}; + pluginData: PluginOptions; metadata: {inputs?: ParameterMetadata; outputs?: ParameterMetadata}; }; diff --git a/src/if-run/types/interface.ts b/src/if-run/types/interface.ts index 6834a3ebb..7b6c19b33 100644 --- a/src/if-run/types/interface.ts +++ b/src/if-run/types/interface.ts @@ -4,6 +4,3 @@ export type PluginInterface = ExecutePlugin | GroupByPlugin; export const isExecute = (plugin: PluginInterface): plugin is ExecutePlugin => (plugin as ExecutePlugin).metadata.kind === 'execute'; - -export const isGroupBy = (plugin: PluginInterface): plugin is GroupByPlugin => - (plugin as GroupByPlugin).metadata.kind === 'groupby';