Skip to content

Commit a1602a4

Browse files
committed
feat: add createApplicationRun method to SDK and CLI
- Add createApplicationRun method to PlatformSDKHttp - Add create-run CLI command with items parameter - Fix build configs and add comprehensive tests - All 140 tests passing
1 parent 252baf5 commit a1602a4

6 files changed

Lines changed: 241 additions & 3 deletions

File tree

packages/cli/src/cli-functions.spec.ts

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
getRun,
99
cancelApplicationRun,
1010
listRunResults,
11+
createApplicationRun,
1112
} from './cli-functions.js';
1213
import { PlatformSDK, PlatformSDKHttp } from '@aignostics/platform-typescript-sdk';
1314
import { AuthService } from './utils/auth.js';
@@ -32,6 +33,7 @@ const platformSDKMock = {
3233
getRun: vi.fn(),
3334
cancelApplicationRun: vi.fn(),
3435
listRunResults: vi.fn(),
36+
createApplicationRun: vi.fn(),
3537
getConfig: vi.fn(),
3638
getVersion: vi.fn(),
3739
} satisfies PlatformSDK;
@@ -60,6 +62,9 @@ describe('CLI Functions Unit Tests', () => {
6062
};
6163

6264
beforeEach(() => {
65+
// Clear all mocks
66+
vi.clearAllMocks();
67+
6368
// Mock console methods to avoid noise in tests
6469
consoleSpy = {
6570
log: vi.spyOn(console, 'log').mockImplementation(() => {}),
@@ -342,4 +347,112 @@ describe('CLI Functions Unit Tests', () => {
342347
expect(mockExit).toHaveBeenCalledWith(1);
343348
});
344349
});
350+
351+
describe('createApplicationRun', () => {
352+
it('should create application run successfully with empty items', async () => {
353+
const runResponse = {
354+
application_run_id: 'run-123',
355+
};
356+
platformSDKMock.createApplicationRun.mockResolvedValue(runResponse);
357+
358+
await createApplicationRun(
359+
'https://api.example.com',
360+
mockAuthService,
361+
'test-app:v1.0.0',
362+
'[]'
363+
);
364+
365+
expect(platformSDKMock.createApplicationRun).toHaveBeenCalledWith({
366+
application_version_id: 'test-app:v1.0.0',
367+
items: [],
368+
});
369+
expect(consoleSpy.log).toHaveBeenCalledWith(
370+
'✅ Application run created successfully:',
371+
JSON.stringify(runResponse, null, 2)
372+
);
373+
});
374+
375+
it('should create application run successfully with items', async () => {
376+
const runResponse = {
377+
application_run_id: 'run-456',
378+
};
379+
const items = [
380+
{
381+
reference: 'slide_1',
382+
input_artifacts: [
383+
{
384+
name: 'input_slide',
385+
download_url: 'https://example.com/slide1.tiff',
386+
metadata: { mime_type: 'image/tiff' },
387+
},
388+
],
389+
},
390+
];
391+
platformSDKMock.createApplicationRun.mockResolvedValue(runResponse);
392+
393+
await createApplicationRun(
394+
'https://api.example.com',
395+
mockAuthService,
396+
'test-app:v1.0.0',
397+
JSON.stringify(items)
398+
);
399+
400+
expect(platformSDKMock.createApplicationRun).toHaveBeenCalledWith({
401+
application_version_id: 'test-app:v1.0.0',
402+
items: items,
403+
});
404+
expect(consoleSpy.log).toHaveBeenCalledWith(
405+
'✅ Application run created successfully:',
406+
JSON.stringify(runResponse, null, 2)
407+
);
408+
});
409+
410+
it('should handle invalid JSON in items parameter', async () => {
411+
await createApplicationRun(
412+
'https://api.example.com',
413+
mockAuthService,
414+
'test-app:v1.0.0',
415+
'invalid-json'
416+
);
417+
418+
expect(consoleSpy.error).toHaveBeenCalledWith('❌ Invalid items JSON:', expect.any(Error));
419+
expect(mockExit).toHaveBeenCalledWith(1);
420+
expect(platformSDKMock.createApplicationRun).not.toHaveBeenCalled();
421+
});
422+
423+
it('should handle non-array items parameter', async () => {
424+
await createApplicationRun(
425+
'https://api.example.com',
426+
mockAuthService,
427+
'test-app:v1.0.0',
428+
'{"not": "an array"}'
429+
);
430+
431+
expect(consoleSpy.error).toHaveBeenCalledWith(
432+
'❌ Invalid items JSON:',
433+
expect.objectContaining({
434+
message: 'Items must be an array',
435+
})
436+
);
437+
expect(mockExit).toHaveBeenCalledWith(1);
438+
expect(platformSDKMock.createApplicationRun).not.toHaveBeenCalled();
439+
});
440+
441+
it('should handle API error during run creation', async () => {
442+
platformSDKMock.createApplicationRun.mockRejectedValue(new Error('API error'));
443+
444+
await createApplicationRun(
445+
'https://api.example.com',
446+
mockAuthService,
447+
'test-app:v1.0.0',
448+
'[]'
449+
);
450+
451+
expect(consoleSpy.error).toHaveBeenCalledWith(
452+
'❌ Failed to create application run:',
453+
expect.any(Error)
454+
);
455+
expect(mockExit).toHaveBeenCalledWith(1);
456+
});
457+
});
345458
});

packages/cli/src/cli-functions.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { PlatformSDKHttp } from '@aignostics/platform-typescript-sdk';
1+
import { PlatformSDKHttp, type ItemCreationRequest } from '@aignostics/platform-typescript-sdk';
22
import { AuthService } from './utils/auth.js';
33
import { readFileSync } from 'fs';
44
import { join } from 'path';
@@ -128,3 +128,40 @@ export async function listRunResults(
128128
process.exit(1);
129129
}
130130
}
131+
132+
export async function createApplicationRun(
133+
endpoint: string,
134+
authService: AuthService,
135+
applicationVersionId: string,
136+
itemsJson: string
137+
): Promise<void> {
138+
const sdk = new PlatformSDKHttp({
139+
baseURL: endpoint,
140+
tokenProvider: () => authService.getValidAccessToken(),
141+
});
142+
try {
143+
// Parse the items JSON
144+
let items: ItemCreationRequest[];
145+
try {
146+
const parsed = JSON.parse(itemsJson) as unknown;
147+
if (!Array.isArray(parsed)) {
148+
throw new Error('Items must be an array');
149+
}
150+
items = parsed as ItemCreationRequest[];
151+
} catch (parseError) {
152+
console.error('❌ Invalid items JSON:', parseError);
153+
process.exit(1);
154+
return; // Ensure we don't continue execution in tests
155+
}
156+
157+
const response = await sdk.createApplicationRun({
158+
application_version_id: applicationVersionId,
159+
items: items,
160+
});
161+
console.log('✅ Application run created successfully:', JSON.stringify(response, null, 2));
162+
} catch (error) {
163+
console.error('❌ Failed to create application run:', error);
164+
process.exit(1);
165+
return; // Ensure we don't continue execution in tests
166+
}
167+
}

packages/cli/src/cli.test.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,13 @@ vi.mock('./cli-functions', () => ({
100100
)
101101
);
102102
}),
103+
// eslint-disable-next-line @typescript-eslint/require-await
104+
createApplicationRun: vi.fn(async () => {
105+
console.log(
106+
'✅ Application run created successfully:',
107+
JSON.stringify({ application_run_id: 'run-123' }, null, 2)
108+
);
109+
}),
103110
}));
104111

105112
// Mock process.exit to prevent test runner from exiting
@@ -399,6 +406,63 @@ describe('CLI Integration Tests', () => {
399406
});
400407
});
401408

409+
describe('create-run command', () => {
410+
it('should create application run successfully with empty items', async () => {
411+
// Mock process.argv for yargs
412+
process.argv = [
413+
'node',
414+
'cli.js',
415+
'create-run',
416+
'test-app:v1.0.0',
417+
'--endpoint',
418+
'https://api.example.com',
419+
'--items',
420+
'[]',
421+
];
422+
423+
await main();
424+
425+
expect(consoleSpy.log).toHaveBeenCalledWith(
426+
'✅ Application run created successfully:',
427+
expect.stringContaining('run-123')
428+
);
429+
});
430+
431+
it('should create application run successfully with default empty items', async () => {
432+
// Mock process.argv for yargs - without explicit --items parameter
433+
process.argv = [
434+
'node',
435+
'cli.js',
436+
'create-run',
437+
'test-app:v1.0.0',
438+
'--endpoint',
439+
'https://api.example.com',
440+
];
441+
442+
await main();
443+
444+
expect(consoleSpy.log).toHaveBeenCalledWith(
445+
'✅ Application run created successfully:',
446+
expect.stringContaining('run-123')
447+
);
448+
});
449+
450+
it('should require applicationVersionId parameter', async () => {
451+
// Mock process.argv for yargs - missing applicationVersionId
452+
process.argv = ['node', 'cli.js', 'create-run'];
453+
454+
try {
455+
await main();
456+
expect.fail('Expected main() to throw an error when applicationVersionId is missing');
457+
} catch (error) {
458+
expect(error.message).toMatch(/process\.exit.*1/);
459+
expect(consoleSpy.error).toHaveBeenCalledWith(
460+
expect.stringContaining('Not enough non-option arguments')
461+
);
462+
}
463+
});
464+
});
465+
402466
describe('CLI argument parsing', () => {
403467
it('should handle version flag', async () => {
404468
// Mock process.argv for yargs

packages/cli/src/cli.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
getRun,
1414
cancelApplicationRun,
1515
listRunResults,
16+
createApplicationRun,
1617
} from './cli-functions.js';
1718
import crypto from 'crypto';
1819

@@ -149,6 +150,29 @@ export async function main() {
149150
}),
150151
argv => listRunResults(argv.endpoint, authService, argv.applicationRunId)
151152
)
153+
.command(
154+
'create-run <applicationVersionId>',
155+
'Create a new application run',
156+
yargs =>
157+
yargs
158+
.positional('applicationVersionId', {
159+
describe: 'Application version ID to run',
160+
type: 'string',
161+
demandOption: true,
162+
})
163+
.option('endpoint', {
164+
describe: 'API endpoint to use',
165+
type: 'string',
166+
default: 'https://platform.aignostics.com',
167+
})
168+
.option('items', {
169+
describe: 'JSON string of items to process (array of objects)',
170+
type: 'string',
171+
default: '[]',
172+
}),
173+
argv =>
174+
createApplicationRun(argv.endpoint, authService, argv.applicationVersionId, argv.items)
175+
)
152176
.command(
153177
'login',
154178
'Login to the Aignostics Platform',

packages/cli/tsup.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export default defineConfig({
44
entry: ['src/index.ts'],
55
format: ['esm', 'cjs'],
66
target: 'node18',
7-
dts: false,
7+
dts: true,
88
sourcemap: true,
99
clean: true,
1010
splitting: false,

packages/sdk/src/platform-sdk.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ export class PlatformSDKHttp implements PlatformSDK {
161161
const response = await client.createApplicationRunV1RunsPost({
162162
runCreationRequest: request,
163163
});
164-
if (response.status !== 200) {
164+
if (response.status < 200 || response.status >= 300) {
165165
throw new Error(`Failed to create application run: ${response.statusText}`);
166166
}
167167
return response.data;

0 commit comments

Comments
 (0)