Skip to content

Commit 30eed17

Browse files
authored
Merge pull request #8 from OpenPathfinder/feat/workflows
2 parents 7518567 + 1aa8fe1 commit 30eed17

File tree

6 files changed

+166
-7
lines changed

6 files changed

+166
-7
lines changed

src/__tests__/cli-commands.test.ts

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/* eslint-env jest */
22

3-
import { getVersion, runDoctor, addProjectWithGithubOrgs, printChecklists, printChecks } from '../cli-commands.js'
3+
import { getVersion, runDoctor, addProjectWithGithubOrgs, printChecklists, printChecks, printWorkflows } from '../cli-commands.js'
44
import { getPackageJson } from '../utils.js'
5-
import { APIHealthResponse, APIProjectDetails, APIGithubOrgDetails, APIErrorResponse, APIChecklistItem, APICheckItem } from '../types.js'
6-
import { mockApiHealthResponse, mockAPIProjectResponse, mockAPIGithubOrgResponse, mockAPIChecklistResponse, mockAPICheckResponse } from './fixtures.js'
5+
import { APIHealthResponse, APIProjectDetails, APIGithubOrgDetails, APIErrorResponse, APIChecklistItem, APICheckItem, APIWorkflowItem } from '../types.js'
6+
import { mockApiHealthResponse, mockAPIProjectResponse, mockAPIGithubOrgResponse, mockAPIChecklistResponse, mockAPICheckResponse, mockAPIWorkflowResponse } from './fixtures.js'
77
import nock from 'nock'
88

99
const pkg = getPackageJson()
@@ -380,4 +380,102 @@ describe('CLI Commands', () => {
380380
expect(result.messages[0]).toBe('No compliance checks found')
381381
})
382382
})
383+
384+
describe('printWorkflows', () => {
385+
let mockWorkflows: APIWorkflowItem[]
386+
387+
beforeEach(() => {
388+
nock.cleanAll()
389+
mockWorkflows = [...mockAPIWorkflowResponse]
390+
})
391+
392+
it('should retrieve and format workflow items successfully', async () => {
393+
// Mock API call
394+
nock('http://localhost:3000')
395+
.get('/api/v1/workflow')
396+
.reply(200, mockWorkflows)
397+
398+
// Execute the function
399+
const result = await printWorkflows()
400+
401+
// Verify the result
402+
expect(result.success).toBe(true)
403+
expect(result.messages[0]).toBe('Compliance workflows available:')
404+
expect(result.messages[1]).toContain(mockWorkflows[0].id)
405+
expect(result.messages[1]).toContain(mockWorkflows[0].description)
406+
expect(result.messages).toHaveLength(2) // Header + 1 workflow item
407+
expect(nock.isDone()).toBe(true) // Verify all mocked endpoints were called
408+
})
409+
410+
it('should handle multiple workflow items', async () => {
411+
// Add a second workflow item
412+
const secondWorkflow = {
413+
...mockWorkflows[0],
414+
id: 'create-stuff',
415+
description: 'Another workflow description'
416+
}
417+
mockWorkflows.push(secondWorkflow)
418+
419+
// Mock API call
420+
nock('http://localhost:3000')
421+
.get('/api/v1/workflow')
422+
.reply(200, mockWorkflows)
423+
424+
// Execute the function
425+
const result = await printWorkflows()
426+
427+
// Verify the result
428+
expect(result.success).toBe(true)
429+
expect(result.messages[0]).toBe('Compliance workflows available:')
430+
expect(result.messages[1]).toContain(mockWorkflows[0].id)
431+
expect(result.messages[2]).toContain(mockWorkflows[1].id)
432+
expect(result.messages).toHaveLength(3) // Header + 2 workflow items
433+
})
434+
435+
it('should handle API errors gracefully', async () => {
436+
// Mock API error
437+
nock('http://localhost:3000')
438+
.get('/api/v1/workflow')
439+
.reply(500, { errors: [{ message: 'Internal server error' }] } as APIErrorResponse)
440+
441+
// Execute the function
442+
const result = await printWorkflows()
443+
444+
// Verify the result
445+
expect(result.success).toBe(false)
446+
expect(result.messages[0]).toContain('❌ Failed to retrieve compliance workflow items')
447+
expect(result.messages).toHaveLength(1)
448+
})
449+
450+
it('should handle network errors gracefully', async () => {
451+
// Mock network error
452+
nock('http://localhost:3000')
453+
.get('/api/v1/workflow')
454+
.replyWithError('Network error')
455+
456+
// Execute the function
457+
const result = await printWorkflows()
458+
459+
// Verify the result
460+
expect(result.success).toBe(false)
461+
expect(result.messages[0]).toContain('❌ Failed to retrieve compliance workflow items')
462+
expect(result.messages[0]).toContain('Network error')
463+
expect(result.messages).toHaveLength(1)
464+
})
465+
466+
it('should handle empty workflow response', async () => {
467+
// Mock empty response
468+
nock('http://localhost:3000')
469+
.get('/api/v1/workflow')
470+
.reply(200, [])
471+
472+
// Execute the function
473+
const result = await printWorkflows()
474+
475+
// Verify the result
476+
expect(result.success).toBe(true)
477+
expect(result.messages).toHaveLength(1) // Only the header message
478+
expect(result.messages[0]).toBe('No compliance workflows found')
479+
})
480+
})
383481
})

src/__tests__/fixtures.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { APIHealthResponse, APIProjectDetails, APIGithubOrgDetails, APIChecklistItem, APICheckItem } from '../types.js'
1+
import { APIHealthResponse, APIProjectDetails, APIGithubOrgDetails, APIChecklistItem, APICheckItem, APIWorkflowItem } from '../types.js'
22

33
export const mockApiHealthResponse: APIHealthResponse = {
44
status: 'ok',
@@ -121,3 +121,8 @@ export const mockAPICheckResponse: APICheckItem[] = [{
121121
created_at: '2025-02-21T18:53:00.485Z',
122122
updated_at: '2025-02-21T18:53:00.485Z'
123123
}]
124+
125+
export const mockAPIWorkflowResponse: APIWorkflowItem[] = [{
126+
id: 'update-stuff',
127+
description: 'Test workflow description'
128+
}]

src/api-client.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { getConfig } from './utils.js'
22
import { got } from 'got'
3-
import { APIHealthResponse, APIProjectDetails, APIGithubOrgDetails, APIChecklistItem, APICheckItem } from './types.js'
3+
import { APIHealthResponse, APIProjectDetails, APIGithubOrgDetails, APIChecklistItem, APICheckItem, APIWorkflowItem } from './types.js'
44

55
export const apiClient = () => {
66
const config = getConfig()
@@ -70,3 +70,12 @@ export const getAllChecks = async (): Promise<APICheckItem[]> => {
7070
}
7171
return response.body as APICheckItem[]
7272
}
73+
74+
export const getAllWorkflows = async (): Promise<APIWorkflowItem[]> => {
75+
const client = apiClient()
76+
const response = await client.get('workflow', { responseType: 'json' })
77+
if (response.statusCode !== 200) {
78+
throw new Error(`Failed to get the data from the API: ${response.statusCode} ${response.body}`)
79+
}
80+
return response.body as APIWorkflowItem[]
81+
}

src/cli-commands.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { CommandResult } from './types.js'
22
import { isApiAvailable, isApiCompatible, getPackageJson } from './utils.js'
3-
import { getAPIDetails, createProject, addGithubOrgToProject, getAllChecklistItems, getAllChecks } from './api-client.js'
3+
import { getAPIDetails, createProject, addGithubOrgToProject, getAllChecklistItems, getAllChecks, getAllWorkflows } from './api-client.js'
44

55
const pkg = getPackageJson()
66

@@ -110,3 +110,30 @@ export const printChecks = async (): Promise<CommandResult> => {
110110
success
111111
}
112112
}
113+
114+
export const printWorkflows = async (): Promise<CommandResult> => {
115+
const messages: string[] = []
116+
let success = true
117+
try {
118+
const workflows = await getAllWorkflows()
119+
if (workflows.length === 0) {
120+
messages.push('No compliance workflows found')
121+
return {
122+
messages,
123+
success
124+
}
125+
}
126+
messages.push('Compliance workflows available:')
127+
workflows.forEach((workflow) => {
128+
messages.push(`- ${workflow.id}: ${workflow.description}`)
129+
})
130+
} catch (error) {
131+
messages.push(`❌ Failed to retrieve compliance workflow items: ${error instanceof Error ? error.message : 'Unknown error'}`)
132+
success = false
133+
}
134+
135+
return {
136+
messages,
137+
success
138+
}
139+
}

src/index.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Command } from 'commander'
44
// @ts-ignore
55
import { stringToArray } from '@ulisesgascon/string-to-array'
66
import { handleCommandResult } from './utils.js'
7-
import { getVersion, runDoctor, addProjectWithGithubOrgs, printChecklists, printChecks } from './cli-commands.js'
7+
import { getVersion, runDoctor, addProjectWithGithubOrgs, printChecklists, printChecks, printWorkflows } from './cli-commands.js'
88

99
const program = new Command()
1010

@@ -23,6 +23,18 @@ program
2323
handleCommandResult(result)
2424
})
2525

26+
const workflow = program
27+
.command('workflow')
28+
.description('Compliance workflow management')
29+
30+
workflow
31+
.command('list')
32+
.description('Print all available compliance workflows')
33+
.action(async () => {
34+
const result = await printWorkflows()
35+
handleCommandResult(result)
36+
})
37+
2638
const checklist = program
2739
.command('compliance-checklist')
2840
.description('Compliance checklist management')

src/types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,14 @@ export type APICheckItem = {
141141
updated_at: string;
142142
};
143143

144+
/**
145+
* Workflow Schema
146+
*/
147+
export interface APIWorkflowItem {
148+
id: string;
149+
description: string;
150+
}
151+
144152
/**
145153
* Error object as defined in the OpenAPI schema
146154
*/

0 commit comments

Comments
 (0)