@elisra-devops/docgen-data-provider 1.77.0 → 1.79.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.
@@ -36,6 +36,7 @@ export interface MewpL2RequirementWorkItem {
36
36
  areaPath: string;
37
37
  }
38
38
  export interface MewpL2RequirementFamily {
39
+ workItemId?: number;
39
40
  requirementId: string;
40
41
  baseKey: string;
41
42
  title: string;
@@ -86,7 +86,6 @@ export default class ResultDataProvider {
86
86
  private createEmptyMewpCoverageBugCell;
87
87
  private createEmptyMewpCoverageL3L4Cell;
88
88
  private buildMewpCoverageL3L4Rows;
89
- private formatMewpCustomerId;
90
89
  private buildMewpCoverageRows;
91
90
  private resolveCoverageBugResponsibility;
92
91
  private resolveMewpL2RunStatus;
@@ -381,6 +381,53 @@ class ResultDataProvider {
381
381
  }));
382
382
  this.accumulateRequirementCountsFromActionResults(fallbackActionResults, testCaseId, requirementKeys, requirementIndex, observedTestCaseIdsByRequirement);
383
383
  }
384
+ const requirementBaseKeys = new Set(requirements.map((item) => String((item === null || item === void 0 ? void 0 : item.baseKey) || '').trim()).filter((item) => !!item));
385
+ const externalL3L4BaseKeys = new Set([...externalL3L4ByBaseKey.keys()]);
386
+ const externalL3L4OverlapKeys = [...externalL3L4BaseKeys].filter((key) => requirementBaseKeys.has(key));
387
+ const failedRequirementBaseKeys = new Set();
388
+ const failedTestCaseIds = new Set();
389
+ for (const [requirementBaseKey, byTestCase] of requirementIndex.entries()) {
390
+ for (const [testCaseId, counts] of byTestCase.entries()) {
391
+ if (Number((counts === null || counts === void 0 ? void 0 : counts.failed) || 0) > 0) {
392
+ failedRequirementBaseKeys.add(requirementBaseKey);
393
+ failedTestCaseIds.add(testCaseId);
394
+ }
395
+ }
396
+ }
397
+ const externalBugTestCaseIds = new Set([...externalBugsByTestCase.keys()]);
398
+ const externalBugFailedTestCaseOverlap = [...externalBugTestCaseIds].filter((id) => failedTestCaseIds.has(id));
399
+ const externalBugBaseKeys = new Set();
400
+ for (const bugs of externalBugsByTestCase.values()) {
401
+ for (const bug of bugs || []) {
402
+ const key = String((bug === null || bug === void 0 ? void 0 : bug.requirementBaseKey) || '').trim();
403
+ if (key)
404
+ externalBugBaseKeys.add(key);
405
+ }
406
+ }
407
+ const externalBugRequirementOverlap = [...externalBugBaseKeys].filter((key) => requirementBaseKeys.has(key));
408
+ const externalBugFailedRequirementOverlap = [...externalBugBaseKeys].filter((key) => failedRequirementBaseKeys.has(key));
409
+ logger_1.default.info(`MEWP coverage join diagnostics: requirementBaseKeys=${requirementBaseKeys.size} ` +
410
+ `failedRequirementBaseKeys=${failedRequirementBaseKeys.size} failedTestCases=${failedTestCaseIds.size}; ` +
411
+ `externalL3L4BaseKeys=${externalL3L4BaseKeys.size} externalL3L4Overlap=${externalL3L4OverlapKeys.length}; ` +
412
+ `externalBugTestCases=${externalBugTestCaseIds.size} externalBugFailedTestCaseOverlap=${externalBugFailedTestCaseOverlap.length}; ` +
413
+ `externalBugBaseKeys=${externalBugBaseKeys.size} externalBugRequirementOverlap=${externalBugRequirementOverlap.length} ` +
414
+ `externalBugFailedRequirementOverlap=${externalBugFailedRequirementOverlap.length}`);
415
+ if (externalL3L4BaseKeys.size > 0 && externalL3L4OverlapKeys.length === 0) {
416
+ const sampleReq = [...requirementBaseKeys].slice(0, 5);
417
+ const sampleExt = [...externalL3L4BaseKeys].slice(0, 5);
418
+ logger_1.default.warn(`MEWP coverage join diagnostics: no L3/L4 key overlap found. ` +
419
+ `sampleRequirementKeys=${sampleReq.join(', ')} sampleExternalL3L4Keys=${sampleExt.join(', ')}`);
420
+ }
421
+ if (externalBugBaseKeys.size > 0 && externalBugRequirementOverlap.length === 0) {
422
+ const sampleReq = [...requirementBaseKeys].slice(0, 5);
423
+ const sampleExt = [...externalBugBaseKeys].slice(0, 5);
424
+ logger_1.default.warn(`MEWP coverage join diagnostics: no bug requirement-key overlap found. ` +
425
+ `sampleRequirementKeys=${sampleReq.join(', ')} sampleExternalBugKeys=${sampleExt.join(', ')}`);
426
+ }
427
+ if (externalBugTestCaseIds.size > 0 && externalBugFailedTestCaseOverlap.length === 0) {
428
+ logger_1.default.warn(`MEWP coverage join diagnostics: no overlap between external bug test cases and failed test cases. ` +
429
+ `Bug rows remain empty because bugs are shown only for failed L2s.`);
430
+ }
384
431
  const rows = this.buildMewpCoverageRows(requirements, requirementIndex, observedTestCaseIdsByRequirement, linkedRequirementsByTestCase, externalL3L4ByBaseKey, externalBugsByTestCase);
385
432
  const coverageRowStats = rows.reduce((acc, row) => {
386
433
  const hasBug = Number((row === null || row === void 0 ? void 0 : row['Bug ID']) || 0) > 0;
@@ -647,7 +694,8 @@ class ResultDataProvider {
647
694
  return `MEWP Internal Validation - ${suffix}`;
648
695
  }
649
696
  createMewpCoverageRow(requirement, runStatus, bug, linkedL3L4) {
650
- const l2ReqId = this.formatMewpCustomerId(requirement.requirementId);
697
+ const l2ReqIdNumeric = Number((requirement === null || requirement === void 0 ? void 0 : requirement.workItemId) || 0);
698
+ const l2ReqId = l2ReqIdNumeric > 0 ? String(l2ReqIdNumeric) : '';
651
699
  const l2ReqTitle = this.toMewpComparableText(requirement.title);
652
700
  const l2SubSystem = this.toMewpComparableText(requirement.subSystem);
653
701
  return {
@@ -688,15 +736,6 @@ class ResultDataProvider {
688
736
  }
689
737
  return rows;
690
738
  }
691
- formatMewpCustomerId(rawValue) {
692
- const normalized = this.normalizeMewpRequirementCode(this.toMewpComparableText(rawValue));
693
- if (normalized)
694
- return normalized;
695
- const onlyDigits = String(rawValue || '').replace(/\D/g, '');
696
- if (onlyDigits)
697
- return `SR${onlyDigits}`;
698
- return '';
699
- }
700
739
  buildMewpCoverageRows(requirements, requirementIndex, observedTestCaseIdsByRequirement, linkedRequirementsByTestCase, l3l4ByBaseKey, externalBugsByTestCase) {
701
740
  var _a;
702
741
  const rows = [];
@@ -1322,7 +1361,7 @@ class ResultDataProvider {
1322
1361
  const workItems = await this.fetchWorkItemsByIds(projectName, requirementIds, true);
1323
1362
  const requirements = workItems.map((wi) => {
1324
1363
  const fields = (wi === null || wi === void 0 ? void 0 : wi.fields) || {};
1325
- const requirementId = this.extractMewpRequirementIdentifier(fields, Number((wi === null || wi === void 0 ? void 0 : wi.id) || 0));
1364
+ const requirementId = this.extractMewpRequirementIdentifier(fields);
1326
1365
  const areaPath = this.toMewpComparableText(fields === null || fields === void 0 ? void 0 : fields['System.AreaPath']);
1327
1366
  return {
1328
1367
  workItemId: Number((wi === null || wi === void 0 ? void 0 : wi.id) || 0),
@@ -1404,13 +1443,14 @@ class ResultDataProvider {
1404
1443
  }
1405
1444
  return [...families.entries()]
1406
1445
  .map(([baseKey, family]) => {
1407
- var _a, _b, _c, _d;
1446
+ var _a, _b, _c, _d, _e;
1408
1447
  return ({
1409
- requirementId: String(((_a = family === null || family === void 0 ? void 0 : family.representative) === null || _a === void 0 ? void 0 : _a.requirementId) || baseKey),
1448
+ workItemId: Number(((_a = family === null || family === void 0 ? void 0 : family.representative) === null || _a === void 0 ? void 0 : _a.workItemId) || 0),
1449
+ requirementId: String(((_b = family === null || family === void 0 ? void 0 : family.representative) === null || _b === void 0 ? void 0 : _b.requirementId) || baseKey),
1410
1450
  baseKey,
1411
- title: String(((_b = family === null || family === void 0 ? void 0 : family.representative) === null || _b === void 0 ? void 0 : _b.title) || ''),
1412
- subSystem: String(((_c = family === null || family === void 0 ? void 0 : family.representative) === null || _c === void 0 ? void 0 : _c.subSystem) || ''),
1413
- responsibility: String(((_d = family === null || family === void 0 ? void 0 : family.representative) === null || _d === void 0 ? void 0 : _d.responsibility) || ''),
1451
+ title: String(((_c = family === null || family === void 0 ? void 0 : family.representative) === null || _c === void 0 ? void 0 : _c.title) || ''),
1452
+ subSystem: String(((_d = family === null || family === void 0 ? void 0 : family.representative) === null || _d === void 0 ? void 0 : _d.subSystem) || ''),
1453
+ responsibility: String(((_e = family === null || family === void 0 ? void 0 : family.representative) === null || _e === void 0 ? void 0 : _e.responsibility) || ''),
1414
1454
  linkedTestCaseIds: [...family.linkedTestCaseIds].sort((a, b) => a - b),
1415
1455
  });
1416
1456
  })
@@ -1666,48 +1706,30 @@ class ResultDataProvider {
1666
1706
  }
1667
1707
  return [...out].sort((a, b) => a - b);
1668
1708
  }
1669
- extractMewpRequirementIdentifier(fields, fallbackWorkItemId) {
1709
+ extractMewpRequirementIdentifier(fields) {
1670
1710
  const entries = Object.entries(fields || {});
1671
- // First pass: only trusted identifier-like fields.
1672
- const strictHints = [
1711
+ const normalizeFieldKey = (value) => String(value || '')
1712
+ .toLowerCase()
1713
+ .replace(/[^a-z0-9]/g, '');
1714
+ // Strict MEWP mode: only explicit MEWP customer-id fields are accepted.
1715
+ // API display name: "Customer ID"
1716
+ // API reference name: "Custom.CustomerID"
1717
+ const customerIdFieldKeys = new Set([
1673
1718
  'customerid',
1674
- 'customer id',
1675
- 'customerrequirementid',
1676
- 'requirementid',
1677
- 'externalid',
1678
- 'srid',
1679
- 'sapwbsid',
1680
- ];
1719
+ 'customcustomerid',
1720
+ ]);
1681
1721
  for (const [key, value] of entries) {
1682
- const normalizedKey = String(key || '').toLowerCase();
1683
- if (!strictHints.some((hint) => normalizedKey.includes(hint)))
1722
+ const normalizedKey = normalizeFieldKey(key);
1723
+ if (!customerIdFieldKeys.has(normalizedKey))
1684
1724
  continue;
1685
1725
  const valueAsString = this.toMewpComparableText(value);
1686
1726
  if (!valueAsString)
1687
1727
  continue;
1688
- const normalized = this.normalizeMewpRequirementCodeWithSuffix(valueAsString);
1689
- if (normalized)
1690
- return normalized;
1728
+ const normalizedRequirementId = this.normalizeMewpRequirementCodeWithSuffix(valueAsString);
1729
+ if (normalizedRequirementId)
1730
+ return normalizedRequirementId;
1691
1731
  }
1692
- // Second pass: weaker hints, but still key-based only.
1693
- const looseHints = ['customer', 'requirement', 'external', 'sapwbs', 'sr'];
1694
- for (const [key, value] of entries) {
1695
- const normalizedKey = String(key || '').toLowerCase();
1696
- if (!looseHints.some((hint) => normalizedKey.includes(hint)))
1697
- continue;
1698
- const valueAsString = this.toMewpComparableText(value);
1699
- if (!valueAsString)
1700
- continue;
1701
- const normalized = this.normalizeMewpRequirementCodeWithSuffix(valueAsString);
1702
- if (normalized)
1703
- return normalized;
1704
- }
1705
- // Optional fallback from title only (avoid scanning all fields and accidental SR matches).
1706
- const title = this.toMewpComparableText(fields === null || fields === void 0 ? void 0 : fields['System.Title']);
1707
- const titleCode = this.normalizeMewpRequirementCodeWithSuffix(title);
1708
- if (titleCode)
1709
- return titleCode;
1710
- return fallbackWorkItemId ? `SR${fallbackWorkItemId}` : '';
1732
+ return '';
1711
1733
  }
1712
1734
  deriveMewpResponsibility(fields) {
1713
1735
  const explicitSapWbs = this.toMewpComparableText(fields === null || fields === void 0 ? void 0 : fields['Custom.SAPWBS']);