Skip to content

Commit 58bd1d6

Browse files
committed
feat: add command compliance-checklist list
1 parent f8a77e5 commit 58bd1d6

File tree

3 files changed

+147
-6
lines changed

3 files changed

+147
-6
lines changed

src/__tests__/cli-commands.test.ts

Lines changed: 106 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 } from '../cli-commands.js'
3+
import { getVersion, runDoctor, addProjectWithGithubOrgs, printChecklists } from '../cli-commands.js'
44
import { getPackageJson } from '../utils.js'
5-
import { APIHealthResponse, APIProjectDetails, APIGithubOrgDetails, APIErrorResponse } from '../types.js'
6-
import { mockApiHealthResponse, mockAPIProjectResponse, mockAPIGithubOrgResponse } from './fixtures.js'
5+
import { APIHealthResponse, APIProjectDetails, APIGithubOrgDetails, APIErrorResponse, APIChecklistItem } from '../types.js'
6+
import { mockApiHealthResponse, mockAPIProjectResponse, mockAPIGithubOrgResponse, mockAPIChecklistResponse } from './fixtures.js'
77
import nock from 'nock'
88

99
const pkg = getPackageJson()
@@ -175,4 +175,107 @@ describe('CLI Commands', () => {
175175
expect(result.messages).toHaveLength(1)
176176
})
177177
})
178+
179+
describe('printChecklists', () => {
180+
let mockChecklists: APIChecklistItem[]
181+
182+
beforeEach(() => {
183+
nock.cleanAll()
184+
mockChecklists = [...mockAPIChecklistResponse]
185+
})
186+
187+
it('should retrieve and format checklist items successfully', async () => {
188+
// Mock API call
189+
nock('http://localhost:3000')
190+
.get('/api/v1/compliance-checklist')
191+
.reply(200, mockChecklists)
192+
193+
// Execute the function
194+
const result = await printChecklists()
195+
196+
// Verify the result
197+
expect(result.success).toBe(true)
198+
expect(result.messages[0]).toBe('Compliance checklists:')
199+
expect(result.messages[1]).toContain(mockChecklists[0].title)
200+
expect(result.messages[1]).toContain(mockChecklists[0].code_name)
201+
expect(result.messages[1]).toContain(mockChecklists[0].description)
202+
expect(result.messages[1]).toContain(mockChecklists[0].url)
203+
expect(result.messages).toHaveLength(2) // Header + 1 checklist item
204+
expect(nock.isDone()).toBe(true) // Verify all mocked endpoints were called
205+
})
206+
207+
it('should handle multiple checklist items', async () => {
208+
// Add a second checklist item
209+
const secondChecklist = {
210+
...mockChecklists[0],
211+
id: 456,
212+
title: 'Second Checklist',
213+
code_name: 'second-checklist',
214+
description: 'Another checklist description',
215+
url: 'https://api.visionboard.example.com/checklist/456'
216+
}
217+
mockChecklists.push(secondChecklist)
218+
219+
// Mock API call
220+
nock('http://localhost:3000')
221+
.get('/api/v1/compliance-checklist')
222+
.reply(200, mockChecklists)
223+
224+
// Execute the function
225+
const result = await printChecklists()
226+
227+
// Verify the result
228+
expect(result.success).toBe(true)
229+
expect(result.messages[0]).toBe('Compliance checklists:')
230+
expect(result.messages[1]).toContain(mockChecklists[0].title)
231+
expect(result.messages[2]).toContain(mockChecklists[1].title)
232+
expect(result.messages).toHaveLength(3) // Header + 2 checklist items
233+
})
234+
235+
it('should handle API errors gracefully', async () => {
236+
// Mock API error
237+
nock('http://localhost:3000')
238+
.get('/api/v1/compliance-checklist')
239+
.reply(500, { errors: [{ message: 'Internal server error' }] } as APIErrorResponse)
240+
241+
// Execute the function
242+
const result = await printChecklists()
243+
244+
// Verify the result
245+
expect(result.success).toBe(false)
246+
expect(result.messages[0]).toContain('❌ Failed to retrieve compliance checklist items')
247+
expect(result.messages).toHaveLength(1)
248+
})
249+
250+
it('should handle network errors gracefully', async () => {
251+
// Mock network error
252+
nock('http://localhost:3000')
253+
.get('/api/v1/compliance-checklist')
254+
.replyWithError('Network error')
255+
256+
// Execute the function
257+
const result = await printChecklists()
258+
259+
// Verify the result
260+
expect(result.success).toBe(false)
261+
expect(result.messages[0]).toContain('❌ Failed to retrieve compliance checklist items')
262+
expect(result.messages[0]).toContain('Network error')
263+
expect(result.messages).toHaveLength(1)
264+
})
265+
266+
it('should handle empty checklist response', async () => {
267+
// Mock empty response
268+
nock('http://localhost:3000')
269+
.get('/api/v1/compliance-checklist')
270+
.reply(200, [])
271+
272+
// Execute the function
273+
const result = await printChecklists()
274+
275+
// Verify the result
276+
expect(result.success).toBe(true)
277+
expect(result.messages).toHaveLength(1) // Only the header message
278+
expect(result.messages[0]).toBe('No compliance checklists found')
279+
})
280+
})
178281
})

src/cli-commands.ts

Lines changed: 28 additions & 2 deletions
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 } from './api-client.js'
3+
import { getAPIDetails, createProject, addGithubOrgToProject, getAllChecklistItems } from './api-client.js'
44

55
const pkg = getPackageJson()
66

@@ -42,7 +42,6 @@ export const addProjectWithGithubOrgs = async (name: string, githubOrgUrls: stri
4242
let success = true
4343
try {
4444
const project = await createProject(name)
45-
// Add GitHub organizations sequentially to avoid race conditions
4645
for (const githubOrgUrl of githubOrgUrls) {
4746
await addGithubOrgToProject(project.id, githubOrgUrl)
4847
}
@@ -57,3 +56,30 @@ export const addProjectWithGithubOrgs = async (name: string, githubOrgUrls: stri
5756
success
5857
}
5958
}
59+
60+
export const printChecklists = async (): Promise<CommandResult> => {
61+
const messages: string[] = []
62+
let success = true
63+
try {
64+
const checklists = await getAllChecklistItems()
65+
if (checklists.length === 0) {
66+
messages.push('No compliance checklists found')
67+
return {
68+
messages,
69+
success
70+
}
71+
}
72+
messages.push('Compliance checklists:')
73+
checklists.forEach((checklist) => {
74+
messages.push(`- ${checklist.title} (${checklist.code_name}): ${checklist.description}. Docs: ${checklist.url}`)
75+
})
76+
} catch (error) {
77+
messages.push(`❌ Failed to retrieve compliance checklist items: ${error instanceof Error ? error.message : 'Unknown error'}`)
78+
success = false
79+
}
80+
81+
return {
82+
messages,
83+
success
84+
}
85+
}

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 } from './cli-commands.js'
7+
import { getVersion, runDoctor, addProjectWithGithubOrgs, printChecklists } from './cli-commands.js'
88

99
const program = new Command()
1010

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

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

0 commit comments

Comments
 (0)