@elisra-devops/docgen-data-provider 1.79.0 → 1.81.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/models/mewp-reporting.d.ts +7 -6
- package/bin/modules/ResultDataProvider.d.ts +2 -0
- package/bin/modules/ResultDataProvider.js +201 -36
- package/bin/modules/ResultDataProvider.js.map +1 -1
- package/bin/tests/modules/ResultDataProvider.test.js +34 -14
- package/bin/tests/modules/ResultDataProvider.test.js.map +1 -1
- package/bin/utils/mewpExternalIngestionUtils.d.ts +2 -2
- package/bin/utils/mewpExternalIngestionUtils.js +96 -41
- package/bin/utils/mewpExternalIngestionUtils.js.map +1 -1
- package/package.json +1 -1
- package/src/models/mewp-reporting.ts +8 -6
- package/src/modules/ResultDataProvider.ts +222 -57
- package/src/tests/modules/ResultDataProvider.test.ts +36 -14
- package/src/utils/mewpExternalIngestionUtils.ts +95 -47
|
@@ -62,17 +62,18 @@ export interface MewpL3L4Link {
|
|
|
62
62
|
title: string;
|
|
63
63
|
level: 'L3' | 'L4';
|
|
64
64
|
}
|
|
65
|
-
export interface
|
|
66
|
-
id: number | '';
|
|
67
|
-
title: string;
|
|
68
|
-
responsibility: string;
|
|
69
|
-
}
|
|
70
|
-
export interface MewpCoverageL3L4Cell {
|
|
65
|
+
export interface MewpL3L4Pair {
|
|
71
66
|
l3Id: string;
|
|
72
67
|
l3Title: string;
|
|
73
68
|
l4Id: string;
|
|
74
69
|
l4Title: string;
|
|
75
70
|
}
|
|
71
|
+
export interface MewpCoverageBugCell {
|
|
72
|
+
id: number | '';
|
|
73
|
+
title: string;
|
|
74
|
+
responsibility: string;
|
|
75
|
+
}
|
|
76
|
+
export type MewpCoverageL3L4Cell = MewpL3L4Pair;
|
|
76
77
|
export interface MewpCoverageRow {
|
|
77
78
|
'L2 REQ ID': string;
|
|
78
79
|
'L2 REQ Title': string;
|
|
@@ -118,6 +118,8 @@ export default class ResultDataProvider {
|
|
|
118
118
|
private fetchMewpL2Requirements;
|
|
119
119
|
private isMewpL2AreaPath;
|
|
120
120
|
private collapseMewpRequirementFamilies;
|
|
121
|
+
private buildMewpL2ToLinkedL1BaseKeys;
|
|
122
|
+
private buildMewpExternalJoinKeysByL2Requirement;
|
|
121
123
|
private buildRequirementFamilyMap;
|
|
122
124
|
private buildLinkedRequirementsByTestCase;
|
|
123
125
|
private resolveMewpRequirementScopeKeysFromQuery;
|
|
@@ -304,6 +304,7 @@ class ResultDataProvider {
|
|
|
304
304
|
const linkedRequirementsByTestCase = await this.buildLinkedRequirementsByTestCase(allRequirements, testData, projectName);
|
|
305
305
|
const scopedRequirementKeys = await this.resolveMewpRequirementScopeKeysFromQuery(linkedQueryRequest, allRequirements, linkedRequirementsByTestCase);
|
|
306
306
|
const requirements = this.collapseMewpRequirementFamilies(allRequirements, (scopedRequirementKeys === null || scopedRequirementKeys === void 0 ? void 0 : scopedRequirementKeys.size) ? scopedRequirementKeys : undefined);
|
|
307
|
+
const l2ToLinkedL1BaseKeys = await this.buildMewpL2ToLinkedL1BaseKeys(allRequirements, projectName, testData);
|
|
307
308
|
const requirementSapWbsByBaseKey = this.buildRequirementSapWbsByBaseKey(allRequirements);
|
|
308
309
|
const externalBugsByTestCase = await this.loadExternalBugsByTestCase(options === null || options === void 0 ? void 0 : options.externalBugsFile);
|
|
309
310
|
const externalL3L4ByBaseKey = await this.loadExternalL3L4ByBaseKey(options === null || options === void 0 ? void 0 : options.externalL3L4File, requirementSapWbsByBaseKey);
|
|
@@ -333,6 +334,7 @@ class ResultDataProvider {
|
|
|
333
334
|
if (requirements.length === 0) {
|
|
334
335
|
return Object.assign(Object.assign({}, defaultPayload), { sheetName: this.buildMewpCoverageSheetName(planName, testPlanId) });
|
|
335
336
|
}
|
|
337
|
+
const externalJoinKeysByL2 = this.buildMewpExternalJoinKeysByL2Requirement(requirements, l2ToLinkedL1BaseKeys);
|
|
336
338
|
const requirementIndex = new Map();
|
|
337
339
|
const observedTestCaseIdsByRequirement = new Map();
|
|
338
340
|
const requirementKeys = new Set();
|
|
@@ -382,8 +384,15 @@ class ResultDataProvider {
|
|
|
382
384
|
this.accumulateRequirementCountsFromActionResults(fallbackActionResults, testCaseId, requirementKeys, requirementIndex, observedTestCaseIdsByRequirement);
|
|
383
385
|
}
|
|
384
386
|
const requirementBaseKeys = new Set(requirements.map((item) => String((item === null || item === void 0 ? void 0 : item.baseKey) || '').trim()).filter((item) => !!item));
|
|
387
|
+
const externalJoinKeyUniverse = new Set();
|
|
388
|
+
for (const keySet of externalJoinKeysByL2.values()) {
|
|
389
|
+
for (const key of keySet) {
|
|
390
|
+
if (key)
|
|
391
|
+
externalJoinKeyUniverse.add(key);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
385
394
|
const externalL3L4BaseKeys = new Set([...externalL3L4ByBaseKey.keys()]);
|
|
386
|
-
const externalL3L4OverlapKeys = [...externalL3L4BaseKeys].filter((key) =>
|
|
395
|
+
const externalL3L4OverlapKeys = [...externalL3L4BaseKeys].filter((key) => externalJoinKeyUniverse.has(key));
|
|
387
396
|
const failedRequirementBaseKeys = new Set();
|
|
388
397
|
const failedTestCaseIds = new Set();
|
|
389
398
|
for (const [requirementBaseKey, byTestCase] of requirementIndex.entries()) {
|
|
@@ -404,9 +413,10 @@ class ResultDataProvider {
|
|
|
404
413
|
externalBugBaseKeys.add(key);
|
|
405
414
|
}
|
|
406
415
|
}
|
|
407
|
-
const externalBugRequirementOverlap = [...externalBugBaseKeys].filter((key) =>
|
|
408
|
-
const externalBugFailedRequirementOverlap = [...externalBugBaseKeys].filter((key) =>
|
|
416
|
+
const externalBugRequirementOverlap = [...externalBugBaseKeys].filter((key) => externalJoinKeyUniverse.has(key));
|
|
417
|
+
const externalBugFailedRequirementOverlap = [...externalBugBaseKeys].filter((key) => externalJoinKeyUniverse.has(key));
|
|
409
418
|
logger_1.default.info(`MEWP coverage join diagnostics: requirementBaseKeys=${requirementBaseKeys.size} ` +
|
|
419
|
+
`externalJoinKeys=${externalJoinKeyUniverse.size} ` +
|
|
410
420
|
`failedRequirementBaseKeys=${failedRequirementBaseKeys.size} failedTestCases=${failedTestCaseIds.size}; ` +
|
|
411
421
|
`externalL3L4BaseKeys=${externalL3L4BaseKeys.size} externalL3L4Overlap=${externalL3L4OverlapKeys.length}; ` +
|
|
412
422
|
`externalBugTestCases=${externalBugTestCaseIds.size} externalBugFailedTestCaseOverlap=${externalBugFailedTestCaseOverlap.length}; ` +
|
|
@@ -414,21 +424,25 @@ class ResultDataProvider {
|
|
|
414
424
|
`externalBugFailedRequirementOverlap=${externalBugFailedRequirementOverlap.length}`);
|
|
415
425
|
if (externalL3L4BaseKeys.size > 0 && externalL3L4OverlapKeys.length === 0) {
|
|
416
426
|
const sampleReq = [...requirementBaseKeys].slice(0, 5);
|
|
427
|
+
const sampleJoin = [...externalJoinKeyUniverse].slice(0, 5);
|
|
417
428
|
const sampleExt = [...externalL3L4BaseKeys].slice(0, 5);
|
|
418
429
|
logger_1.default.warn(`MEWP coverage join diagnostics: no L3/L4 key overlap found. ` +
|
|
419
|
-
`sampleRequirementKeys=${sampleReq.join(', ')}
|
|
430
|
+
`sampleRequirementKeys=${sampleReq.join(', ')} sampleJoinKeys=${sampleJoin.join(', ')} ` +
|
|
431
|
+
`sampleExternalL3L4Keys=${sampleExt.join(', ')}`);
|
|
420
432
|
}
|
|
421
433
|
if (externalBugBaseKeys.size > 0 && externalBugRequirementOverlap.length === 0) {
|
|
422
434
|
const sampleReq = [...requirementBaseKeys].slice(0, 5);
|
|
435
|
+
const sampleJoin = [...externalJoinKeyUniverse].slice(0, 5);
|
|
423
436
|
const sampleExt = [...externalBugBaseKeys].slice(0, 5);
|
|
424
437
|
logger_1.default.warn(`MEWP coverage join diagnostics: no bug requirement-key overlap found. ` +
|
|
425
|
-
`sampleRequirementKeys=${sampleReq.join(', ')}
|
|
438
|
+
`sampleRequirementKeys=${sampleReq.join(', ')} sampleJoinKeys=${sampleJoin.join(', ')} ` +
|
|
439
|
+
`sampleExternalBugKeys=${sampleExt.join(', ')}`);
|
|
426
440
|
}
|
|
427
441
|
if (externalBugTestCaseIds.size > 0 && externalBugFailedTestCaseOverlap.length === 0) {
|
|
428
442
|
logger_1.default.warn(`MEWP coverage join diagnostics: no overlap between external bug test cases and failed test cases. ` +
|
|
429
443
|
`Bug rows remain empty because bugs are shown only for failed L2s.`);
|
|
430
444
|
}
|
|
431
|
-
const rows = this.buildMewpCoverageRows(requirements, requirementIndex, observedTestCaseIdsByRequirement, linkedRequirementsByTestCase, externalL3L4ByBaseKey, externalBugsByTestCase);
|
|
445
|
+
const rows = this.buildMewpCoverageRows(requirements, requirementIndex, observedTestCaseIdsByRequirement, linkedRequirementsByTestCase, externalL3L4ByBaseKey, externalBugsByTestCase, externalJoinKeysByL2);
|
|
432
446
|
const coverageRowStats = rows.reduce((acc, row) => {
|
|
433
447
|
const hasBug = Number((row === null || row === void 0 ? void 0 : row['Bug ID']) || 0) > 0;
|
|
434
448
|
const hasL3 = String((row === null || row === void 0 ? void 0 : row['L3 REQ ID']) || '').trim() !== '';
|
|
@@ -493,12 +507,24 @@ class ResultDataProvider {
|
|
|
493
507
|
}
|
|
494
508
|
}
|
|
495
509
|
const validL2BaseKeys = new Set([...requirementFamilies.keys()]);
|
|
510
|
+
const diagnostics = {
|
|
511
|
+
totalTestCases: 0,
|
|
512
|
+
totalParsedSteps: 0,
|
|
513
|
+
totalStepsWithMentions: 0,
|
|
514
|
+
totalMentionedCustomerIds: 0,
|
|
515
|
+
testCasesWithoutMentionedCustomerIds: 0,
|
|
516
|
+
failingRows: 0,
|
|
517
|
+
};
|
|
496
518
|
for (const testCaseId of [...allTestCaseIds].sort((a, b) => a - b)) {
|
|
519
|
+
diagnostics.totalTestCases += 1;
|
|
497
520
|
const stepsXml = stepsXmlByTestCase.get(testCaseId) || '';
|
|
498
521
|
const parsedSteps = stepsXml && String(stepsXml).trim() !== ''
|
|
499
522
|
? await this.testStepParserHelper.parseTestSteps(stepsXml, new Map())
|
|
500
523
|
: [];
|
|
524
|
+
const executableSteps = parsedSteps.filter((step) => !(step === null || step === void 0 ? void 0 : step.isSharedStepTitle));
|
|
525
|
+
diagnostics.totalParsedSteps += executableSteps.length;
|
|
501
526
|
const mentionEntries = this.extractRequirementMentionsFromExpectedSteps(parsedSteps, true);
|
|
527
|
+
diagnostics.totalStepsWithMentions += mentionEntries.length;
|
|
502
528
|
const mentionedL2Only = new Set();
|
|
503
529
|
const mentionedCodeFirstStep = new Map();
|
|
504
530
|
const mentionedBaseFirstStep = new Map();
|
|
@@ -521,6 +547,10 @@ class ResultDataProvider {
|
|
|
521
547
|
}
|
|
522
548
|
}
|
|
523
549
|
}
|
|
550
|
+
diagnostics.totalMentionedCustomerIds += mentionedL2Only.size;
|
|
551
|
+
if (mentionedL2Only.size === 0) {
|
|
552
|
+
diagnostics.testCasesWithoutMentionedCustomerIds += 1;
|
|
553
|
+
}
|
|
524
554
|
const mentionedBaseKeys = new Set([...mentionedL2Only].map((code) => this.toRequirementKey(code)).filter((code) => !!code));
|
|
525
555
|
const expectedFamilyCodes = new Set();
|
|
526
556
|
for (const baseKey of mentionedBaseKeys) {
|
|
@@ -597,6 +627,14 @@ class ResultDataProvider {
|
|
|
597
627
|
.join('; ');
|
|
598
628
|
const linkedButNotMentioned = sortedExtraLinked.join('; ');
|
|
599
629
|
const validationStatus = mentionedButNotLinked || linkedButNotMentioned ? 'Fail' : 'Pass';
|
|
630
|
+
if (validationStatus === 'Fail')
|
|
631
|
+
diagnostics.failingRows += 1;
|
|
632
|
+
logger_1.default.debug(`MEWP internal validation parse diagnostics: ` +
|
|
633
|
+
`testCaseId=${testCaseId} parsedSteps=${executableSteps.length} ` +
|
|
634
|
+
`stepsWithMentions=${mentionEntries.length} customerIdsFound=${mentionedL2Only.size} ` +
|
|
635
|
+
`linkedRequirements=${linkedFullCodes.size} mentionedButNotLinked=${sortedMissingMentioned.length + sortedMissingFamily.length} ` +
|
|
636
|
+
`linkedButNotMentioned=${sortedExtraLinked.length} status=${validationStatus} ` +
|
|
637
|
+
`customerIdSample='${[...mentionedL2Only].slice(0, 5).join(', ')}'`);
|
|
600
638
|
rows.push({
|
|
601
639
|
'Test Case ID': testCaseId,
|
|
602
640
|
'Test Case Title': String(testCaseTitleMap.get(testCaseId) || '').trim(),
|
|
@@ -605,6 +643,11 @@ class ResultDataProvider {
|
|
|
605
643
|
'Validation Status': validationStatus,
|
|
606
644
|
});
|
|
607
645
|
}
|
|
646
|
+
logger_1.default.info(`MEWP internal validation summary: testCases=${diagnostics.totalTestCases} ` +
|
|
647
|
+
`parsedSteps=${diagnostics.totalParsedSteps} stepsWithMentions=${diagnostics.totalStepsWithMentions} ` +
|
|
648
|
+
`totalCustomerIdsFound=${diagnostics.totalMentionedCustomerIds} ` +
|
|
649
|
+
`testCasesWithoutCustomerIds=${diagnostics.testCasesWithoutMentionedCustomerIds} ` +
|
|
650
|
+
`failingRows=${diagnostics.failingRows}`);
|
|
608
651
|
return {
|
|
609
652
|
sheetName: this.buildInternalValidationSheetName(planName, testPlanId),
|
|
610
653
|
columnOrder: [...ResultDataProvider.INTERNAL_VALIDATION_COLUMNS],
|
|
@@ -718,30 +761,43 @@ class ResultDataProvider {
|
|
|
718
761
|
createEmptyMewpCoverageL3L4Cell() {
|
|
719
762
|
return { l3Id: '', l3Title: '', l4Id: '', l4Title: '' };
|
|
720
763
|
}
|
|
721
|
-
buildMewpCoverageL3L4Rows(
|
|
722
|
-
const
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
764
|
+
buildMewpCoverageL3L4Rows(pairs) {
|
|
765
|
+
const deduped = new Map();
|
|
766
|
+
for (const pair of pairs || []) {
|
|
767
|
+
const l3Id = String((pair === null || pair === void 0 ? void 0 : pair.l3Id) || '').trim();
|
|
768
|
+
const l3Title = String((pair === null || pair === void 0 ? void 0 : pair.l3Title) || '').trim();
|
|
769
|
+
const l4Id = String((pair === null || pair === void 0 ? void 0 : pair.l4Id) || '').trim();
|
|
770
|
+
const l4Title = String((pair === null || pair === void 0 ? void 0 : pair.l4Title) || '').trim();
|
|
771
|
+
if (!l3Id && !l4Id)
|
|
772
|
+
continue;
|
|
773
|
+
const key = `${l3Id}|${l4Id}`;
|
|
774
|
+
const existing = deduped.get(key);
|
|
775
|
+
if (!existing) {
|
|
776
|
+
deduped.set(key, { l3Id, l3Title, l4Id, l4Title });
|
|
777
|
+
continue;
|
|
778
|
+
}
|
|
779
|
+
deduped.set(key, {
|
|
780
|
+
l3Id: existing.l3Id || l3Id,
|
|
781
|
+
l3Title: existing.l3Title || l3Title,
|
|
782
|
+
l4Id: existing.l4Id || l4Id,
|
|
783
|
+
l4Title: existing.l4Title || l4Title,
|
|
735
784
|
});
|
|
736
785
|
}
|
|
737
|
-
return
|
|
786
|
+
return [...deduped.values()].sort((a, b) => {
|
|
787
|
+
const l3Compare = String((a === null || a === void 0 ? void 0 : a.l3Id) || '').localeCompare(String((b === null || b === void 0 ? void 0 : b.l3Id) || ''));
|
|
788
|
+
if (l3Compare !== 0)
|
|
789
|
+
return l3Compare;
|
|
790
|
+
return String((a === null || a === void 0 ? void 0 : a.l4Id) || '').localeCompare(String((b === null || b === void 0 ? void 0 : b.l4Id) || ''));
|
|
791
|
+
});
|
|
738
792
|
}
|
|
739
|
-
buildMewpCoverageRows(requirements, requirementIndex, observedTestCaseIdsByRequirement, linkedRequirementsByTestCase, l3l4ByBaseKey, externalBugsByTestCase) {
|
|
793
|
+
buildMewpCoverageRows(requirements, requirementIndex, observedTestCaseIdsByRequirement, linkedRequirementsByTestCase, l3l4ByBaseKey, externalBugsByTestCase, externalJoinKeysByL2) {
|
|
740
794
|
var _a;
|
|
741
795
|
const rows = [];
|
|
742
796
|
const linkedByRequirement = this.invertBaseRequirementLinks(linkedRequirementsByTestCase);
|
|
797
|
+
const joinKeysByRequirement = externalJoinKeysByL2 || new Map();
|
|
743
798
|
for (const requirement of requirements) {
|
|
744
799
|
const key = String((requirement === null || requirement === void 0 ? void 0 : requirement.baseKey) || this.toRequirementKey(requirement.requirementId) || '').trim();
|
|
800
|
+
const externalJoinKeys = joinKeysByRequirement.get(key) || new Set([key]);
|
|
745
801
|
const linkedTestCaseIds = ((requirement === null || requirement === void 0 ? void 0 : requirement.linkedTestCaseIds) || []).filter((id) => Number.isFinite(id) && Number(id) > 0);
|
|
746
802
|
const linkedByTestCase = key ? Array.from(linkedByRequirement.get(key) || []) : [];
|
|
747
803
|
const observedTestCaseIds = key
|
|
@@ -763,7 +819,7 @@ class ResultDataProvider {
|
|
|
763
819
|
const externalBugs = externalBugsByTestCase.get(testCaseId) || [];
|
|
764
820
|
for (const bug of externalBugs) {
|
|
765
821
|
const bugBaseKey = String((bug === null || bug === void 0 ? void 0 : bug.requirementBaseKey) || '').trim();
|
|
766
|
-
if (bugBaseKey && bugBaseKey
|
|
822
|
+
if (bugBaseKey && !externalJoinKeys.has(bugBaseKey))
|
|
767
823
|
continue;
|
|
768
824
|
const bugId = Number((bug === null || bug === void 0 ? void 0 : bug.id) || 0);
|
|
769
825
|
if (!Number.isFinite(bugId) || bugId <= 0)
|
|
@@ -781,20 +837,16 @@ class ResultDataProvider {
|
|
|
781
837
|
const bugsForRows = runStatus === 'Fail'
|
|
782
838
|
? Array.from(aggregatedBugs.values()).sort((a, b) => a.id - b.id)
|
|
783
839
|
: [];
|
|
784
|
-
const l3l4ForRows = [...(l3l4ByBaseKey.get(
|
|
785
|
-
const bugRows = bugsForRows.
|
|
786
|
-
?
|
|
787
|
-
:
|
|
840
|
+
const l3l4ForRows = [...externalJoinKeys].flatMap((joinKey) => l3l4ByBaseKey.get(joinKey) || []);
|
|
841
|
+
const bugRows = bugsForRows.map((bug) => ({
|
|
842
|
+
id: Number.isFinite(Number(bug === null || bug === void 0 ? void 0 : bug.id)) && Number(bug === null || bug === void 0 ? void 0 : bug.id) > 0 ? Number(bug === null || bug === void 0 ? void 0 : bug.id) : '',
|
|
843
|
+
title: String((bug === null || bug === void 0 ? void 0 : bug.title) || '').trim(),
|
|
844
|
+
responsibility: String((bug === null || bug === void 0 ? void 0 : bug.responsibility) || '').trim(),
|
|
845
|
+
}));
|
|
788
846
|
const l3l4Rows = this.buildMewpCoverageL3L4Rows(l3l4ForRows);
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
}
|
|
793
|
-
for (const bug of bugRows) {
|
|
794
|
-
rows.push(this.createMewpCoverageRow(requirement, runStatus, bug, this.createEmptyMewpCoverageL3L4Cell()));
|
|
795
|
-
}
|
|
796
|
-
for (const linkedL3L4 of l3l4Rows) {
|
|
797
|
-
rows.push(this.createMewpCoverageRow(requirement, runStatus, this.createEmptyMewpCoverageBugCell(), linkedL3L4));
|
|
847
|
+
const rowCount = Math.max(bugRows.length, l3l4Rows.length, 1);
|
|
848
|
+
for (let index = 0; index < rowCount; index += 1) {
|
|
849
|
+
rows.push(this.createMewpCoverageRow(requirement, runStatus, bugRows[index] || this.createEmptyMewpCoverageBugCell(), l3l4Rows[index] || this.createEmptyMewpCoverageL3L4Cell()));
|
|
798
850
|
}
|
|
799
851
|
}
|
|
800
852
|
return rows;
|
|
@@ -1456,6 +1508,119 @@ class ResultDataProvider {
|
|
|
1456
1508
|
})
|
|
1457
1509
|
.sort((a, b) => String(a.requirementId).localeCompare(String(b.requirementId)));
|
|
1458
1510
|
}
|
|
1511
|
+
async buildMewpL2ToLinkedL1BaseKeys(requirements, projectName, testData) {
|
|
1512
|
+
const out = new Map();
|
|
1513
|
+
const relatedIds = new Set();
|
|
1514
|
+
const linkedTestCaseIdsByL2 = new Map();
|
|
1515
|
+
const testCaseTitleMap = this.buildMewpTestCaseTitleMap(testData);
|
|
1516
|
+
for (const requirement of requirements || []) {
|
|
1517
|
+
const l2BaseKey = String((requirement === null || requirement === void 0 ? void 0 : requirement.baseKey) || '').trim();
|
|
1518
|
+
if (!l2BaseKey)
|
|
1519
|
+
continue;
|
|
1520
|
+
if (!out.has(l2BaseKey))
|
|
1521
|
+
out.set(l2BaseKey, new Set());
|
|
1522
|
+
if (!linkedTestCaseIdsByL2.has(l2BaseKey))
|
|
1523
|
+
linkedTestCaseIdsByL2.set(l2BaseKey, new Set());
|
|
1524
|
+
for (const testCaseId of (requirement === null || requirement === void 0 ? void 0 : requirement.linkedTestCaseIds) || []) {
|
|
1525
|
+
const numeric = Number(testCaseId);
|
|
1526
|
+
if (Number.isFinite(numeric) && numeric > 0) {
|
|
1527
|
+
linkedTestCaseIdsByL2.get(l2BaseKey).add(numeric);
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
for (const relatedId of (requirement === null || requirement === void 0 ? void 0 : requirement.relatedWorkItemIds) || []) {
|
|
1531
|
+
const id = Number(relatedId);
|
|
1532
|
+
if (Number.isFinite(id) && id > 0)
|
|
1533
|
+
relatedIds.add(id);
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
let titleDerivedCount = 0;
|
|
1537
|
+
for (const [l2BaseKey, testCaseIds] of linkedTestCaseIdsByL2.entries()) {
|
|
1538
|
+
const targetSet = out.get(l2BaseKey) || new Set();
|
|
1539
|
+
for (const testCaseId of testCaseIds) {
|
|
1540
|
+
const title = String(testCaseTitleMap.get(testCaseId) || '').trim();
|
|
1541
|
+
if (!title)
|
|
1542
|
+
continue;
|
|
1543
|
+
const fromTitleCodes = this.extractRequirementCodesFromExpectedText(title, false);
|
|
1544
|
+
if (fromTitleCodes.size > 0) {
|
|
1545
|
+
for (const code of fromTitleCodes) {
|
|
1546
|
+
const normalized = this.toRequirementKey(code);
|
|
1547
|
+
if (normalized)
|
|
1548
|
+
targetSet.add(normalized);
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
else {
|
|
1552
|
+
const normalized = this.toRequirementKey(title);
|
|
1553
|
+
if (normalized)
|
|
1554
|
+
targetSet.add(normalized);
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
if (targetSet.size > 0) {
|
|
1558
|
+
titleDerivedCount += 1;
|
|
1559
|
+
}
|
|
1560
|
+
out.set(l2BaseKey, targetSet);
|
|
1561
|
+
}
|
|
1562
|
+
if (relatedIds.size === 0) {
|
|
1563
|
+
const linkedL1Count = [...out.values()].reduce((sum, set) => sum + set.size, 0);
|
|
1564
|
+
logger_1.default.info(`MEWP L2->L1 mapping summary: l2Families=${out.size} ` +
|
|
1565
|
+
`fromTitle=${titleDerivedCount} fallbackFromLinkedL1=0 linkedL1Keys=${linkedL1Count}`);
|
|
1566
|
+
return out;
|
|
1567
|
+
}
|
|
1568
|
+
const relatedWorkItems = await this.fetchWorkItemsByIds(projectName, [...relatedIds], false);
|
|
1569
|
+
const l1BaseByWorkItemId = new Map();
|
|
1570
|
+
for (const workItem of relatedWorkItems || []) {
|
|
1571
|
+
const workItemId = Number((workItem === null || workItem === void 0 ? void 0 : workItem.id) || 0);
|
|
1572
|
+
if (!Number.isFinite(workItemId) || workItemId <= 0)
|
|
1573
|
+
continue;
|
|
1574
|
+
const fields = (workItem === null || workItem === void 0 ? void 0 : workItem.fields) || {};
|
|
1575
|
+
const customerId = this.extractMewpRequirementIdentifier(fields);
|
|
1576
|
+
const baseKey = this.toRequirementKey(customerId);
|
|
1577
|
+
if (!baseKey)
|
|
1578
|
+
continue;
|
|
1579
|
+
l1BaseByWorkItemId.set(workItemId, baseKey);
|
|
1580
|
+
}
|
|
1581
|
+
let linkedFallbackCount = 0;
|
|
1582
|
+
for (const requirement of requirements || []) {
|
|
1583
|
+
const l2BaseKey = String((requirement === null || requirement === void 0 ? void 0 : requirement.baseKey) || '').trim();
|
|
1584
|
+
if (!l2BaseKey)
|
|
1585
|
+
continue;
|
|
1586
|
+
if (!out.has(l2BaseKey))
|
|
1587
|
+
out.set(l2BaseKey, new Set());
|
|
1588
|
+
const targetSet = out.get(l2BaseKey);
|
|
1589
|
+
if (targetSet.size > 0) {
|
|
1590
|
+
continue;
|
|
1591
|
+
}
|
|
1592
|
+
for (const relatedId of (requirement === null || requirement === void 0 ? void 0 : requirement.relatedWorkItemIds) || []) {
|
|
1593
|
+
const baseKey = l1BaseByWorkItemId.get(Number(relatedId));
|
|
1594
|
+
if (baseKey)
|
|
1595
|
+
targetSet.add(baseKey);
|
|
1596
|
+
}
|
|
1597
|
+
if (targetSet.size > 0) {
|
|
1598
|
+
linkedFallbackCount += 1;
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
const l2Families = out.size;
|
|
1602
|
+
const withLinkedL1 = [...out.values()].filter((set) => set.size > 0).length;
|
|
1603
|
+
const linkedL1Count = [...out.values()].reduce((sum, set) => sum + set.size, 0);
|
|
1604
|
+
logger_1.default.info(`MEWP L2->L1 mapping summary: l2Families=${l2Families} withLinkedL1=${withLinkedL1} ` +
|
|
1605
|
+
`fromTitle=${titleDerivedCount} fallbackFromLinkedL1=${linkedFallbackCount} linkedL1Keys=${linkedL1Count}`);
|
|
1606
|
+
return out;
|
|
1607
|
+
}
|
|
1608
|
+
buildMewpExternalJoinKeysByL2Requirement(requirements, l2ToLinkedL1BaseKeys) {
|
|
1609
|
+
const out = new Map();
|
|
1610
|
+
for (const requirement of requirements || []) {
|
|
1611
|
+
const l2BaseKey = String((requirement === null || requirement === void 0 ? void 0 : requirement.baseKey) || '').trim();
|
|
1612
|
+
if (!l2BaseKey)
|
|
1613
|
+
continue;
|
|
1614
|
+
const joinKeys = new Set([l2BaseKey]);
|
|
1615
|
+
for (const l1Key of l2ToLinkedL1BaseKeys.get(l2BaseKey) || []) {
|
|
1616
|
+
const normalized = String(l1Key || '').trim();
|
|
1617
|
+
if (normalized)
|
|
1618
|
+
joinKeys.add(normalized);
|
|
1619
|
+
}
|
|
1620
|
+
out.set(l2BaseKey, joinKeys);
|
|
1621
|
+
}
|
|
1622
|
+
return out;
|
|
1623
|
+
}
|
|
1459
1624
|
buildRequirementFamilyMap(requirements, scopedRequirementKeys) {
|
|
1460
1625
|
const familyMap = new Map();
|
|
1461
1626
|
for (const requirement of requirements || []) {
|