Skip to content

Commit b498aef

Browse files
committed
feat: Refactoring
1 parent 0a64735 commit b498aef

File tree

33 files changed

+383
-42
lines changed

33 files changed

+383
-42
lines changed

src/apitypes/rest/rest.changes.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ import {
8282
getOperationTags,
8383
OperationsMap,
8484
} from '../../components'
85-
import { checkApiKind, calculateApiKind } from '../../components/compare/bwc.validation'
85+
import { checkApiKind, getApiKindFormLabels } from '../../components/compare/bwc.validation'
8686

8787
export const compareDocuments: DocumentsCompare = async (
8888
operationsMap: OperationsMap,
@@ -136,8 +136,8 @@ export const compareDocuments: DocumentsCompare = async (
136136
afterValueNormalizedProperty: AFTER_VALUE_NORMALIZED_PROPERTY,
137137
beforeValueNormalizedProperty: BEFORE_VALUE_NORMALIZED_PROPERTY,
138138
apiCompatibilityScopeFunction: checkApiKind(
139-
prevDoc?.apiKind ?? calculateApiKind(prevDocData?.info, prevDoc?.labels, previousVersionLabels),
140-
currDoc?.apiKind ?? calculateApiKind(currDocData?.info, currDoc?.labels, currentVersionLabels),
139+
prevDoc?.apiKind ?? getApiKindFormLabels(prevDocData?.info, prevDoc?.labels, previousVersionLabels),
140+
currDoc?.apiKind ?? getApiKindFormLabels(currDocData?.info, currDoc?.labels, currentVersionLabels),
141141
),
142142
},
143143
) as { merged: OpenAPIV3.Document; diffs: Diff[] }

src/components/compare/bwc.validation.ts

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,49 @@ import {
2222
ApiCompatibilityScope,
2323
ApiCompatibilityScopeFunction,
2424
} from '@netcracker/qubership-apihub-api-diff'
25-
import { ApiKind, Labels } from '../../types'
25+
import { Labels } from '../../types'
2626
import { findApiKindLabel, getApiKind } from '../document'
2727
import { OpenAPIV3 } from 'openapi-types'
2828

29-
const hasNoBWC = (obj: unknown): boolean => {
30-
return getApiKind(obj) === API_KIND.NO_BWC
29+
export const getApiCompatibilityKind = (beforeJson: unknown, afterJson: unknown): ApiCompatibilityKind | undefined => {
30+
const beforeApiKind = getApiKind(beforeJson)?.toLowerCase() ?? ''
31+
const afterApiKind = getApiKind(afterJson)?.toLowerCase() ?? ''
32+
33+
if (beforeApiKind === API_KIND.NO_BWC || afterApiKind === API_KIND.NO_BWC) {
34+
return ApiCompatibilityKind.NOT_BACKWARD_COMPATIBLE
35+
}
36+
37+
if (beforeApiKind === API_KIND.BWC || afterApiKind === API_KIND.BWC) {
38+
return ApiCompatibilityKind.BACKWARD_COMPATIBLE
39+
}
40+
41+
return undefined
42+
}
43+
44+
export const getMethodsApiCompatibilityKind = (obj: unknown): ApiCompatibilityKind | undefined => {
45+
if (checkAllMethodsHaveSameApiKind(obj, API_KIND.NO_BWC)) {
46+
return ApiCompatibilityKind.NOT_BACKWARD_COMPATIBLE
47+
}
48+
49+
if (checkAllMethodsHaveSameApiKind(obj, API_KIND.BWC)) {
50+
return ApiCompatibilityKind.BACKWARD_COMPATIBLE
51+
}
52+
53+
return undefined
54+
}
55+
56+
const hasApiKind = (obj: unknown, apiKind: string): boolean => {
57+
return getApiKind(obj) === apiKind
3158
}
3259

3360
// If a path object is removed/added, we must ensure every HTTP method under it
3461
// is explicitly marked NO_BWC before treating the change as risky.
35-
const checkAllMethodsHaveNoBWC = (obj: unknown): boolean => {
62+
const checkAllMethodsHaveSameApiKind = (obj: unknown, apiKind: string): boolean => {
3663
if (!isObject(obj)) {
3764
return false
3865
}
3966

40-
if (hasNoBWC(obj)) {
67+
if (hasApiKind(obj, apiKind)) {
4168
return true
4269
}
4370
const entries = Object.entries(obj)
@@ -46,7 +73,7 @@ const checkAllMethodsHaveNoBWC = (obj: unknown): boolean => {
4673
entries.every(([key, value]) =>
4774
isValidHttpMethod(key) &&
4875
isObject(value) &&
49-
hasNoBWC(value),
76+
hasApiKind(value, apiKind),
5077
)
5178
}
5279

@@ -95,40 +122,36 @@ export const checkApiKind = (
95122
}
96123

97124
if (beforeExists && afterExists) {
98-
return hasNoBWC(beforeJson) || hasNoBWC(afterJson)
99-
? ApiCompatibilityKind.NOT_BACKWARD_COMPATIBLE
100-
: undefined
125+
return getApiCompatibilityKind(beforeJson, afterJson)
101126
}
102127

103128
// case remove: when a node disappears, api-diff emits REMOVE diffs for each
104129
// operation. We only mark the deletion as NO_BWC if all removed methods were
105130
// explicitly flagged NO_BWC, keeping deletions consistent with declared scope.
106131
if (beforeExists && !afterExists) {
107-
return checkAllMethodsHaveNoBWC(beforeJson)
108-
? ApiCompatibilityKind.NOT_BACKWARD_COMPATIBLE
109-
: undefined
132+
return getMethodsApiCompatibilityKind(beforeJson)
110133
}
111134

112135
// case add: additions are checked the same way. A new path or operation is
113136
// considered NO_BWC only when every contained method declares NO_BWC.
114137
if (afterExists && !beforeExists) {
115-
return checkAllMethodsHaveNoBWC(afterJson)
116-
? ApiCompatibilityKind.NOT_BACKWARD_COMPATIBLE
117-
: undefined
138+
return getMethodsApiCompatibilityKind(afterJson)
118139
}
119140

120141
return undefined
121142
}
122143
}
123144

124-
export const calculateApiKind = (info?: OpenAPIV3.InfoObject, fileLabels?: Labels, versionLabels?: Labels): ApiKind => {
145+
export const getApiKindFormLabels = (
146+
info?: OpenAPIV3.InfoObject,
147+
fileLabels?: Labels,
148+
versionLabels?: Labels,
149+
): string | undefined => {
125150
const infoApiKind = getApiKind(info)
126-
if (infoApiKind && infoApiKind?.toLowerCase() === API_KIND.NO_BWC) {
127-
return API_KIND.NO_BWC
151+
if (infoApiKind) {
152+
return infoApiKind.toLowerCase()
128153
}
129-
const apiKind = findApiKindLabel(fileLabels, versionLabels)
130154

131-
return apiKind?.toLowerCase() === API_KIND.NO_BWC
132-
? API_KIND.NO_BWC
133-
: API_KIND.BWC
155+
const apiKind = findApiKindLabel(fileLabels, versionLabels)
156+
return apiKind?.toLowerCase()
134157
}

test/apiKinds.test.ts

Lines changed: 81 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -201,59 +201,123 @@ describe('Check Api Compatibility Function tests', () => {
201201
})
202202
})
203203

204-
describe('Publish ApiKind version Labels and file Labels priority tests', () => {
205-
test('should prioritize version label no-BWC over file label BWC in previous version', async () => {
204+
describe('ApiKind info section tests', () => {
205+
test('should apply api-kind label in previous document info section', async () => {
206+
const result = await runApiKindTest('api-kinds/no-bwc-api-kind-info-label-in-prev-document')
207+
expect(result).toEqual(changesSummaryMatcher({ [RISKY_CHANGE_TYPE]: 1 }))
208+
})
209+
210+
test('should apply api-kind label in current document info section', async () => {
211+
const result = await runApiKindTest('api-kinds/no-bwc-api-kind-info-label-in-curr-document')
212+
expect(result).toEqual(changesSummaryMatcher({ [RISKY_CHANGE_TYPE]: 1 }))
213+
})
214+
})
215+
216+
describe('ApiKind operations section tests', () => {
217+
test('should apply api-kind label in current document operation', async () => {
218+
const result = await runApiKindTest('api-kinds/no-bwc-api-kind-operation-label-curr-document')
219+
expect(result).toEqual(changesSummaryMatcher({
220+
[RISKY_CHANGE_TYPE]: 1,
221+
[UNCLASSIFIED_CHANGE_TYPE]: 1, // x-api-kind field in the operation also gives a diff
222+
}))
223+
})
224+
225+
test('should apply api-kind label in previous document operation', async () => {
226+
const result = await runApiKindTest('api-kinds/no-bwc-api-kind-operation-label-prev-document')
227+
expect(result).toEqual(changesSummaryMatcher({
228+
[RISKY_CHANGE_TYPE]: 1,
229+
[UNCLASSIFIED_CHANGE_TYPE]: 1, // x-api-kind field in the operation also gives a diff
230+
}))
231+
})
232+
})
233+
234+
describe('Publish ApiKind Priority tests', () => {
235+
test('should prioritize version label no-BWC api kind over file label BWC in previous version', async () => {
206236
const result = await runApiKindTest(
207237
'api-kinds/no-api-kind-in-documents', [API_KIND_BWC_LABEL], [], [API_KIND_NO_BWC_LABEL],
208238
)
209239
expect(result).toEqual(changesSummaryMatcher({ [BREAKING_CHANGE_TYPE]: 1 }))
210240
})
211241

212-
test('should prioritize version label no-BWC over file label BWC in current version', async () => {
242+
test('should prioritize version label no-BWC api kind over file label BWC in current version', async () => {
213243
const result = await runApiKindTest(
214244
'api-kinds/no-api-kind-in-documents', [], [API_KIND_BWC_LABEL], [], [API_KIND_NO_BWC_LABEL],
215245
)
216246
expect(result).toEqual(changesSummaryMatcher({ [BREAKING_CHANGE_TYPE]: 1 }))
217247
})
218248

219-
test('should prioritize file label no-BWC over version label BWC in previous version', async () => {
249+
test('should prioritize file label no-BWC api kind over version label BWC in previous version', async () => {
220250
const result = await runApiKindTest(
221251
'api-kinds/no-api-kind-in-documents', [API_KIND_NO_BWC_LABEL], [], [API_KIND_BWC_LABEL],
222252
)
223253
expect(result).toEqual(changesSummaryMatcher({ [RISKY_CHANGE_TYPE]: 1 }))
224254
})
225255

226-
test('should prioritize file label no-BWC over version label BWC in current version', async () => {
256+
test('should prioritize file label no-BWC api kind over version label BWC in current version', async () => {
227257
const result = await runApiKindTest(
228258
'api-kinds/no-api-kind-in-documents', [], [API_KIND_NO_BWC_LABEL], [], [API_KIND_BWC_LABEL],
229259
)
230260
expect(result).toEqual(changesSummaryMatcher({ [RISKY_CHANGE_TYPE]: 1 }))
231261
})
232-
})
233262

234-
describe('ApiKind info section tests', () => {
235-
test('should apply api-kind label in previous document info section', async () => {
236-
const result = await runApiKindTest('api-kinds/api-kind-info-label-in-prev-document')
263+
test('should prioritize info label no-BWC api kind over version label BWC in previous version', async () => {
264+
const result = await runApiKindTest(
265+
'api-kinds/no-bwc-api-kind-info-label-in-prev-document', [API_KIND_BWC_LABEL], [], [API_KIND_BWC_LABEL],
266+
)
237267
expect(result).toEqual(changesSummaryMatcher({ [RISKY_CHANGE_TYPE]: 1 }))
238268
})
239269

240-
test('should apply api-kind label in current document info section', async () => {
241-
const result = await runApiKindTest('api-kinds/api-kind-info-label-in-curr-document')
270+
test('should prioritize info label no-BWC api kind over version label BWC in current version', async () => {
271+
const result = await runApiKindTest(
272+
'api-kinds/no-bwc-api-kind-info-label-in-curr-document', [], [API_KIND_BWC_LABEL], [], [API_KIND_BWC_LABEL],
273+
)
242274
expect(result).toEqual(changesSummaryMatcher({ [RISKY_CHANGE_TYPE]: 1 }))
243275
})
244-
})
245276

246-
describe('ApiKind operations section tests', () => {
247-
test('should apply api-kind label in current document operation', async () => {
248-
const result = await runApiKindTest('api-kinds/api-kind-operation-label-curr-document')
277+
test('should prioritize previous info label as BWC when info api-kind overrides no-BWC publish labels', async () => {
278+
const result = await runApiKindTest(
279+
'api-kinds/bwc-api-kind-info-label-in-prev-document', [API_KIND_NO_BWC_LABEL], [], [API_KIND_NO_BWC_LABEL],
280+
)
281+
expect(result).toEqual(changesSummaryMatcher({ [BREAKING_CHANGE_TYPE]: 1 }))
282+
})
283+
284+
test('should prioritize current info label as BWC when info api kind overrides no-BWC publish labels', async () => {
285+
const result = await runApiKindTest(
286+
'api-kinds/bwc-api-kind-info-label-in-curr-document', [], [API_KIND_NO_BWC_LABEL], [], [API_KIND_NO_BWC_LABEL],
287+
)
288+
expect(result).toEqual(changesSummaryMatcher({ [BREAKING_CHANGE_TYPE]: 1 }))
289+
})
290+
291+
test('should prioritize previous operation-level BWC api kind over current no-BWC publish labels', async () => {
292+
const result = await runApiKindTest(
293+
'api-kinds/bwc-api-kind-operation-label-prev-document', [], [API_KIND_NO_BWC_LABEL], [], [API_KIND_NO_BWC_LABEL],
294+
)
295+
expect(result).toEqual(changesSummaryMatcher({
296+
[BREAKING_CHANGE_TYPE]: 1,
297+
[UNCLASSIFIED_CHANGE_TYPE]: 1, // x-api-kind field in the operation also gives a diff
298+
}))
299+
})
300+
301+
test('should prioritize current operation-level BWC api kind over current no-BWC publish labels', async () => {
302+
const result = await runApiKindTest(
303+
'api-kinds/bwc-api-kind-operation-label-curr-document', [], [API_KIND_NO_BWC_LABEL], [], [API_KIND_NO_BWC_LABEL],
304+
)
305+
expect(result).toEqual(changesSummaryMatcher({
306+
[BREAKING_CHANGE_TYPE]: 1,
307+
[UNCLASSIFIED_CHANGE_TYPE]: 1, // x-api-kind field in the operation also gives a diff
308+
}))
309+
})
310+
311+
test('should prioritize current operation-level no-BWC api kind over current BWC info label', async () => {
312+
const result = await runApiKindTest('api-kinds/double-api-kind-info-label-in-curr-document')
249313
expect(result).toEqual(changesSummaryMatcher({
250314
[RISKY_CHANGE_TYPE]: 1,
251315
[UNCLASSIFIED_CHANGE_TYPE]: 1, // x-api-kind field in the operation also gives a diff
252316
}))
253317
})
254318

255-
test('should apply api-kind label in previous document operation', async () => {
256-
const result = await runApiKindTest('api-kinds/api-kind-operation-label-prev-document')
319+
test('should prioritize current operation-level no-BWC api kind over previous BWC info label', async () => {
320+
const result = await runApiKindTest('api-kinds/double-api-kind-info-label-in-prev-document')
257321
expect(result).toEqual(changesSummaryMatcher({
258322
[RISKY_CHANGE_TYPE]: 1,
259323
[UNCLASSIFIED_CHANGE_TYPE]: 1, // x-api-kind field in the operation also gives a diff

test/projects/api-kinds/api-kind-info-label-in-curr-document/1.yaml renamed to test/projects/api-kinds/bwc-api-kind-info-label-in-curr-document/1.yaml

File renamed without changes.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
openapi: 3.1.0
2+
info:
3+
title: test
4+
version: 0.1.0
5+
x-api-kind: BWC
6+
paths:
7+
/path1:
8+
post:
9+
responses:
10+
'200':
11+
description: OK
12+
content:
13+
application/json:
14+
schema:
15+
type: string

test/projects/api-kinds/api-kind-info-label-in-curr-document/config.json renamed to test/projects/api-kinds/bwc-api-kind-info-label-in-curr-document/config.json

File renamed without changes.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
openapi: 3.1.0
2+
info:
3+
title: test
4+
version: 0.1.0
5+
x-api-kind: BWC
6+
paths:
7+
/path1:
8+
post:
9+
responses:
10+
'200':
11+
description: OK
12+
content:
13+
application/json:
14+
schema:
15+
type: number

test/projects/api-kinds/api-kind-info-label-in-prev-document/2.yaml renamed to test/projects/api-kinds/bwc-api-kind-info-label-in-prev-document/2.yaml

File renamed without changes.

test/projects/api-kinds/api-kind-info-label-in-prev-document/config.json renamed to test/projects/api-kinds/bwc-api-kind-info-label-in-prev-document/config.json

File renamed without changes.

test/projects/api-kinds/api-kind-operation-label-curr-document/1.yaml renamed to test/projects/api-kinds/bwc-api-kind-operation-label-curr-document/1.yaml

File renamed without changes.

0 commit comments

Comments
 (0)