Skip to content

Commit

Permalink
feat: ✨ plugins can return warning to not interupt hook
Browse files Browse the repository at this point in the history
  • Loading branch information
ArnaudTA committed Sep 27, 2024
1 parent 29c6a8a commit 3e132c3
Show file tree
Hide file tree
Showing 11 changed files with 102 additions and 21 deletions.
4 changes: 2 additions & 2 deletions apps/client/src/views/admin/ListLogs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const hideLogs = ref(false)
const hideLogDetails = ref(true)
const logs = computed(() => adminLogStore.logs)
const logsLength = computed(() => adminLogStore.count)
const logsLength = computed(() => adminLogStore.count ?? 0)
async function showLogs(index: number) {
page.value = index
Expand Down Expand Up @@ -113,7 +113,7 @@ onMounted(async () => {
<div
v-for="log in logs"
:key="log.id"
:class="`my-5 border-solid ${log.data?.failed ? 'border-red-100' : 'border-zinc-100'}`"
:class="`my-5 border-solid ${log.data?.warning?.length ? 'border-amber-200' : log.data?.failed ? 'border-red-100' : 'border-zinc-100'}`"
>
<div
class="flex flex-wrap justify-between"
Expand Down
2 changes: 1 addition & 1 deletion packages/hooks/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@cpn-console/hooks",
"type": "module",
"version": "2.3.2",
"version": "2.4.0",
"private": false,
"description": "",
"main": "dist/index.js",
Expand Down
61 changes: 58 additions & 3 deletions packages/hooks/src/hooks/hook.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,30 @@ import { createHook, executeStep } from './hook.ts'

const okStatus = { status: { result: 'OK' } } as const
const koStatus = { status: { result: 'KO', message: 'Failed' } } as const
const warningStatus = { status: { result: 'WARNING', message: 'Failed' } } as const

async function simpleOkHookCall() {
return okStatus
}
async function simpleFailedHookCall() {
return koStatus
}
async function simpleWarningHookCall() {
return warningStatus
}

describe('test executeStep mechanism', () => {
it('test payload results, everything ok', async () => {
const results = await executeStep({
plugin1: simpleOkHookCall,
plugin2: simpleOkHookCall,
}, { apis: {}, args: {}, config: {}, failed: false, results: {} }, 'main')
}, { apis: {}, args: {}, config: {}, failed: false, results: {}, warning: [] }, 'main')

expect(results.apis).toEqual({})
expect(results.args).toEqual({})
expect(results.config).toEqual({})
expect(results.failed).toBe(false)
expect(results.warning).toEqual([])
expect(results.results).toEqual({
plugin1: { ...okStatus, executionTime: { main: expect.any(Number) } },
plugin2: { ...okStatus, executionTime: { main: expect.any(Number) } },
Expand All @@ -33,11 +38,12 @@ describe('test executeStep mechanism', () => {
const results = await executeStep({
plugin1: simpleFailedHookCall,
plugin2: simpleFailedHookCall,
}, { apis: {}, args: {}, config: {}, failed: false, results: {} }, 'main')
}, { apis: {}, args: {}, config: {}, failed: false, results: {}, warning: [] }, 'main')

expect(results.apis).toEqual({})
expect(results.args).toEqual({})
expect(results.config).toEqual({})
expect(results.warning).toEqual([])
expect(results.failed).contain('plugin1')
expect(results.failed).contain('plugin2')
expect(results.results).toEqual({
Expand All @@ -50,18 +56,36 @@ describe('test executeStep mechanism', () => {
const results = await executeStep({
plugin1: simpleOkHookCall,
plugin2: simpleFailedHookCall,
}, { apis: {}, args: {}, config: {}, failed: false, results: {} }, 'main')
}, { apis: {}, args: {}, config: {}, failed: false, results: {}, warning: [] }, 'main')

expect(results.apis).toEqual({})
expect(results.args).toEqual({})
expect(results.config).toEqual({})
expect(results.warning).toEqual([])
expect(results.failed).not.contain('plugin1')
expect(results.failed).contain('plugin2')
expect(results.results).toEqual({
plugin1: { ...okStatus, executionTime: { main: expect.any(Number) } },
plugin2: { ...koStatus, executionTime: { main: expect.any(Number) } },
})
})

it('test payload results, partial warning', async () => {
const results = await executeStep({
plugin1: simpleOkHookCall,
plugin2: simpleWarningHookCall,
}, { apis: {}, args: {}, config: {}, failed: false, results: {}, warning: [] }, 'main')

expect(results.apis).toEqual({})
expect(results.args).toEqual({})
expect(results.config).toEqual({})
expect(results.warning).toEqual(['plugin2'])
expect(results.failed).toEqual(false)
expect(results.results).toEqual({
plugin1: { ...okStatus, executionTime: { main: expect.any(Number) } },
plugin2: { ...warningStatus, executionTime: { main: expect.any(Number) } },
})
})
})

describe('createHook', () => {
Expand Down Expand Up @@ -112,13 +136,44 @@ describe('createHook', () => {
expect(hookResult.config).toEqual({})
expect(hookResult.totalExecutionTime).toEqual(expect.any(Number))
expect(hookResult.failed).toEqual(false)
expect(hookResult.warning).toEqual([])
expect(hookResult.results).toEqual({ plugin1: { ...okStatus, executionTime: {
pre: expect.any(Number),
main: expect.any(Number),
post: expect.any(Number),
} } })
})

it('test payload results, multistep with warning', async () => {
const hook = createHook(false)
hook.steps.pre.plugin1 = simpleWarningHookCall
hook.steps.main.plugin2 = simpleOkHookCall
hook.steps.post.plugin2 = simpleOkHookCall

const hookResult = await hook.execute({}, {})

expect(hookResult.args).toEqual({})
expect(hookResult.config).toEqual({})
expect(hookResult.totalExecutionTime).toEqual(expect.any(Number))
expect(hookResult.failed).toEqual(false)
expect(hookResult.warning).toEqual(['plugin1'])
expect(hookResult.results).toEqual({
plugin1: {
...warningStatus,
executionTime: {
pre: expect.any(Number),
},
},
plugin2: {
...okStatus,
executionTime: {
main: expect.any(Number),
post: expect.any(Number),
},
},
})
})

it('test payload results, main fails', async () => {
const hook = createHook(false)
hook.apis.plugin1 = () => new PluginApi() // à tester ailleurs
Expand Down
9 changes: 8 additions & 1 deletion packages/hooks/src/hooks/hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type * as hooks from './index.js'

export type DefaultArgs = Record<any, any>
export interface PluginResult {
status: { result: 'OK', message?: string } | { result: 'KO', message: string }
status: { result: 'OK', message?: string } | { result: 'KO' | 'WARNING', message: string }
store?: Record<string, string | number>
[key: string]: any
}
Expand All @@ -25,6 +25,7 @@ export interface Config {
export interface HookPayload<Args extends DefaultArgs> {
args: Args
failed: boolean | string[]
warning: string[]
results: HookPayloadResults
apis: HookPayloadApis<Args>
config: Config
Expand Down Expand Up @@ -65,6 +66,8 @@ export async function executeStep<Args extends DefaultArgs>(step: HookStep, payl
payload.failed = Array.isArray(payload.failed)
? [...payload.failed, name]
: [name]
} else if (results[index].status.result === 'WARNING' && !payload.warning.includes(name)) {
payload.warning.push(name)
}
payload.results[name] = { ...results[index], executionTime: payload.results[name].executionTime }
})
Expand Down Expand Up @@ -93,6 +96,7 @@ export function createHook<E extends DefaultArgs, V extends DefaultArgs>(unique
results: {},
apis: payloadApis,
config,
warning: [],
}

const executeSteps = ['pre', 'main', 'post'] as const
Expand All @@ -107,6 +111,7 @@ export function createHook<E extends DefaultArgs, V extends DefaultArgs>(unique
args: payload.args,
results: payload.results,
failed: payload.failed,
warning: payload.warning,
totalExecutionTime: Date.now() - startTime,
config,
}
Expand All @@ -124,6 +129,7 @@ export function createHook<E extends DefaultArgs, V extends DefaultArgs>(unique
results: {},
apis: payloadApis,
config,
warning: [],
}

const result = await executeStep(steps.check, payload, 'validate')
Expand All @@ -133,6 +139,7 @@ export function createHook<E extends DefaultArgs, V extends DefaultArgs>(unique
failed: result.failed,
totalExecutionTime: Date.now() - startTime,
config,
warning: payload.warning,
}
}
const hook: Hook<E, V> = {
Expand Down
1 change: 0 additions & 1 deletion packages/hooks/src/utils/utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ const object = { test1: 1, test2: 2, 3: 'test3' }

it('should return object keys', () => {
const keys = objectKeys(object)
console.log(typeof keys[2])

// cannot gaurantee order in keys
expect(keys[0]).contain('3')
Expand Down
2 changes: 1 addition & 1 deletion packages/shared/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@cpn-console/shared",
"type": "module",
"version": "1.1.5",
"version": "1.1.6",
"private": false,
"description": "",
"main": "dist/index.js",
Expand Down
4 changes: 4 additions & 0 deletions packages/shared/src/contracts/log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,12 @@ export const logContract = contractInstance.router({
data: z.object({
args: z.any(),
failed: z.boolean().or(z.array(z.string())).optional(),
warning: z.string().array().optional(),
results: z.any(),
totalExecutionTime: z.number().optional(),
}).passthrough().transform((data) => {
delete data.config
return data
}),
action: z.string(),
userId: z.string().nullable(),
Expand Down
4 changes: 1 addition & 3 deletions packages/shared/src/utils/const.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { apiPrefix } from '../index.js'

export const adminGroupPath = '/admin'

export const projectIsLockedInfo = 'Le projet est verrouillé, pas d\'action possible'
Expand All @@ -9,7 +7,7 @@ export const invalidInternalRepoName = 'Le nom du dépôt ne doit contenir ni ma

export const fakeToken = 'fakeToken'
export const tokenHeaderName = 'x-dso-token'
export const swaggerUiPath = `${apiPrefix}/swagger-ui`
export const swaggerUiPath = '/api/v1/swagger-ui'

export const levels = [
'r',
Expand Down
2 changes: 1 addition & 1 deletion plugins/sonarqube/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@cpn-console/sonarqube-plugin",
"type": "module",
"version": "2.0.2",
"version": "2.0.3",
"private": false,
"description": "",
"main": "dist/index.js",
Expand Down
28 changes: 22 additions & 6 deletions plugins/sonarqube/src/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,13 @@ export const upsertProject: StepCall<Project> = async (payload) => {
result: 'OK',
},
}
} catch (_error) {
} catch (error) {
return {
status: {
result: 'KO',
result: 'WARNING',
message: 'Failed to reconcile',
},
error: parseError(error),
}
}
}
Expand Down Expand Up @@ -203,14 +204,29 @@ export const setVariables: StepCall<Project> = async (payload) => {
}),
])

return { status: { result: 'OK' } }
if (payload.results.sonarqube.status.result === 'WARNING') {
return {
status: {
result: 'WARNING',
message: `main message: ${payload.results.sonarqube.status.message}, post message: OK`,
},
}
}
return {
status: {
result: 'OK',
},
}
} catch (error) {
return {
error: parseError(error),
status: {
result: 'KO',
message: 'Failed to reconcile',
result: 'WARNING',
message: `main message: ${payload.results.sonarqube.status.message}, post message: Failed to reconcile`,
},
...payload.results.sonarqube.error && { errors: {
main: payload.results.sonarqube.error,
post: parseError(error),
} },
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions plugins/sonarqube/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import infos from './infos.js'
import monitor from './monitor.js'

function start(_options: unknown) {
initSonar()
getStatus()
try {
initSonar()
getStatus()
} catch (_error) {}
}

export const plugin: Plugin = {
Expand Down

0 comments on commit 3e132c3

Please sign in to comment.