@elisra-devops/docgen-data-provider 1.84.0 → 1.85.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.
@@ -88,6 +88,7 @@ export default class ResultDataProvider {
88
88
  private buildMewpCoverageL3L4Rows;
89
89
  private buildMewpCoverageRows;
90
90
  private resolveCoverageBugResponsibility;
91
+ private buildMewpTestCaseResponsibilityMap;
91
92
  private resolveMewpL2RunStatus;
92
93
  private fetchMewpScopedTestData;
93
94
  private extractRelNumberFromSuite;
@@ -134,6 +135,7 @@ export default class ResultDataProvider {
134
135
  private extractLinkedWorkItemIdsFromRelations;
135
136
  private extractMewpRequirementIdentifier;
136
137
  private deriveMewpResponsibility;
138
+ private deriveMewpTestCaseResponsibility;
137
139
  private deriveMewpSubSystem;
138
140
  private resolveBugResponsibility;
139
141
  private resolveMewpResponsibility;
@@ -306,6 +306,7 @@ class ResultDataProvider {
306
306
  const requirements = this.collapseMewpRequirementFamilies(allRequirements, (scopedRequirementKeys === null || scopedRequirementKeys === void 0 ? void 0 : scopedRequirementKeys.size) ? scopedRequirementKeys : undefined);
307
307
  const l2ToLinkedL1BaseKeys = await this.buildMewpL2ToLinkedL1BaseKeys(allRequirements, projectName, testData);
308
308
  const requirementSapWbsByBaseKey = this.buildRequirementSapWbsByBaseKey(allRequirements);
309
+ const testCaseResponsibilityById = await this.buildMewpTestCaseResponsibilityMap(testData, projectName);
309
310
  const externalBugsByTestCase = await this.loadExternalBugsByTestCase(options === null || options === void 0 ? void 0 : options.externalBugsFile);
310
311
  const externalL3L4ByBaseKey = await this.loadExternalL3L4ByBaseKey(options === null || options === void 0 ? void 0 : options.externalL3L4File, requirementSapWbsByBaseKey);
311
312
  const hasExternalBugsFile = !!String(((_a = options === null || options === void 0 ? void 0 : options.externalBugsFile) === null || _a === void 0 ? void 0 : _a.name) ||
@@ -442,7 +443,7 @@ class ResultDataProvider {
442
443
  logger_1.default.warn(`MEWP coverage join diagnostics: no overlap between external bug test cases and failed test cases. ` +
443
444
  `Bug rows remain empty because bugs are shown only for failed L2s.`);
444
445
  }
445
- const rows = this.buildMewpCoverageRows(requirements, requirementIndex, observedTestCaseIdsByRequirement, linkedRequirementsByTestCase, externalL3L4ByBaseKey, externalBugsByTestCase, externalJoinKeysByL2);
446
+ const rows = this.buildMewpCoverageRows(requirements, requirementIndex, observedTestCaseIdsByRequirement, linkedRequirementsByTestCase, externalL3L4ByBaseKey, externalBugsByTestCase, externalJoinKeysByL2, testCaseResponsibilityById);
446
447
  const coverageRowStats = rows.reduce((acc, row) => {
447
448
  const hasBug = Number((row === null || row === void 0 ? void 0 : row['Bug ID']) || 0) > 0;
448
449
  const hasL3 = String((row === null || row === void 0 ? void 0 : row['L3 REQ ID']) || '').trim() !== '';
@@ -813,7 +814,7 @@ class ResultDataProvider {
813
814
  return String((a === null || a === void 0 ? void 0 : a.l4Id) || '').localeCompare(String((b === null || b === void 0 ? void 0 : b.l4Id) || ''));
814
815
  });
815
816
  }
816
- buildMewpCoverageRows(requirements, requirementIndex, observedTestCaseIdsByRequirement, linkedRequirementsByTestCase, l3l4ByBaseKey, externalBugsByTestCase, externalJoinKeysByL2) {
817
+ buildMewpCoverageRows(requirements, requirementIndex, observedTestCaseIdsByRequirement, linkedRequirementsByTestCase, l3l4ByBaseKey, externalBugsByTestCase, externalJoinKeysByL2, testCaseResponsibilityById) {
817
818
  var _a;
818
819
  const rows = [];
819
820
  const linkedByRequirement = this.invertBaseRequirementLinks(linkedRequirementsByTestCase);
@@ -847,7 +848,7 @@ class ResultDataProvider {
847
848
  const bugId = Number((bug === null || bug === void 0 ? void 0 : bug.id) || 0);
848
849
  if (!Number.isFinite(bugId) || bugId <= 0)
849
850
  continue;
850
- aggregatedBugs.set(bugId, Object.assign(Object.assign({}, bug), { responsibility: this.resolveCoverageBugResponsibility(String((bug === null || bug === void 0 ? void 0 : bug.responsibility) || ''), requirement) }));
851
+ aggregatedBugs.set(bugId, Object.assign(Object.assign({}, bug), { responsibility: this.resolveCoverageBugResponsibility(String((bug === null || bug === void 0 ? void 0 : bug.responsibility) || ''), requirement, String((testCaseResponsibilityById === null || testCaseResponsibilityById === void 0 ? void 0 : testCaseResponsibilityById.get(testCaseId)) || '')) }));
851
852
  }
852
853
  }
853
854
  }
@@ -874,18 +875,114 @@ class ResultDataProvider {
874
875
  }
875
876
  return rows;
876
877
  }
877
- resolveCoverageBugResponsibility(rawResponsibility, requirement) {
878
- const direct = String(rawResponsibility || '').trim();
878
+ resolveCoverageBugResponsibility(rawResponsibility, requirement, testCaseResponsibility = '') {
879
+ const normalizeDisplay = (value) => {
880
+ const direct = String(value || '').trim();
881
+ if (!direct)
882
+ return '';
883
+ const resolved = this.resolveMewpResponsibility(this.toMewpComparableText(direct));
884
+ if (resolved === 'ESUK')
885
+ return 'ESUK';
886
+ if (resolved === 'IL')
887
+ return 'Elisra';
888
+ return direct;
889
+ };
890
+ const direct = normalizeDisplay(rawResponsibility);
879
891
  if (direct && direct.toLowerCase() !== 'unknown')
880
892
  return direct;
881
- const requirementResponsibility = String((requirement === null || requirement === void 0 ? void 0 : requirement.responsibility) || '')
882
- .trim()
883
- .toUpperCase();
884
- if (requirementResponsibility === 'ESUK')
885
- return 'ESUK';
886
- if (requirementResponsibility === 'IL' || requirementResponsibility === 'ELISRA')
887
- return 'Elisra';
888
- return direct || 'Unknown';
893
+ const fromTestCase = normalizeDisplay(testCaseResponsibility);
894
+ if (fromTestCase && fromTestCase.toLowerCase() !== 'unknown')
895
+ return fromTestCase;
896
+ const fromRequirement = normalizeDisplay(String((requirement === null || requirement === void 0 ? void 0 : requirement.responsibility) || ''));
897
+ if (fromRequirement && fromRequirement.toLowerCase() !== 'unknown')
898
+ return fromRequirement;
899
+ return direct || fromTestCase || fromRequirement || 'Unknown';
900
+ }
901
+ async buildMewpTestCaseResponsibilityMap(testData, projectName) {
902
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
903
+ const out = new Map();
904
+ const unresolved = new Set();
905
+ const extractFromWorkItemFields = (workItemFields) => {
906
+ const fields = {};
907
+ if (!Array.isArray(workItemFields))
908
+ return fields;
909
+ for (const field of workItemFields) {
910
+ const keyCandidates = [field === null || field === void 0 ? void 0 : field.key, field === null || field === void 0 ? void 0 : field.name, field === null || field === void 0 ? void 0 : field.referenceName]
911
+ .map((item) => String(item || '').trim())
912
+ .filter((item) => !!item);
913
+ for (const key of keyCandidates) {
914
+ fields[key] = field === null || field === void 0 ? void 0 : field.value;
915
+ }
916
+ }
917
+ return fields;
918
+ };
919
+ for (const suite of testData || []) {
920
+ const testCasesItems = Array.isArray(suite === null || suite === void 0 ? void 0 : suite.testCasesItems) ? suite.testCasesItems : [];
921
+ for (const testCase of testCasesItems) {
922
+ const testCaseId = Number(((_a = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _a === void 0 ? void 0 : _a.id) || (testCase === null || testCase === void 0 ? void 0 : testCase.testCaseId) || (testCase === null || testCase === void 0 ? void 0 : testCase.id) || 0);
923
+ if (!Number.isFinite(testCaseId) || testCaseId <= 0 || out.has(testCaseId))
924
+ continue;
925
+ const workItemFieldsMap = ((_b = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _b === void 0 ? void 0 : _b.fields) || {};
926
+ const workItemFieldsList = extractFromWorkItemFields((_c = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _c === void 0 ? void 0 : _c.workItemFields);
927
+ const directFieldAliases = Object.fromEntries(Object.entries({
928
+ 'System.AreaPath': ((_d = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _d === void 0 ? void 0 : _d.areaPath) ||
929
+ ((_e = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _e === void 0 ? void 0 : _e.AreaPath) ||
930
+ (testCase === null || testCase === void 0 ? void 0 : testCase.areaPath) ||
931
+ (testCase === null || testCase === void 0 ? void 0 : testCase.AreaPath) ||
932
+ ((_f = testCase === null || testCase === void 0 ? void 0 : testCase.testCase) === null || _f === void 0 ? void 0 : _f.areaPath) ||
933
+ ((_g = testCase === null || testCase === void 0 ? void 0 : testCase.testCase) === null || _g === void 0 ? void 0 : _g.AreaPath),
934
+ 'Area Path': ((_h = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _h === void 0 ? void 0 : _h['Area Path']) ||
935
+ (testCase === null || testCase === void 0 ? void 0 : testCase['Area Path']) ||
936
+ ((_j = testCase === null || testCase === void 0 ? void 0 : testCase.testCase) === null || _j === void 0 ? void 0 : _j['Area Path']),
937
+ AreaPath: ((_k = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _k === void 0 ? void 0 : _k.AreaPath) ||
938
+ (testCase === null || testCase === void 0 ? void 0 : testCase.AreaPath) ||
939
+ ((_l = testCase === null || testCase === void 0 ? void 0 : testCase.testCase) === null || _l === void 0 ? void 0 : _l.AreaPath),
940
+ }).filter(([, value]) => value !== undefined && value !== null && String(value).trim() !== ''));
941
+ const fromWorkItem = this.deriveMewpTestCaseResponsibility(Object.assign(Object.assign(Object.assign({}, directFieldAliases), workItemFieldsList), workItemFieldsMap));
942
+ if (fromWorkItem) {
943
+ out.set(testCaseId, fromWorkItem);
944
+ }
945
+ else {
946
+ unresolved.add(testCaseId);
947
+ }
948
+ }
949
+ const testPointsItems = Array.isArray(suite === null || suite === void 0 ? void 0 : suite.testPointsItems) ? suite.testPointsItems : [];
950
+ for (const testPoint of testPointsItems) {
951
+ const testCaseId = Number((testPoint === null || testPoint === void 0 ? void 0 : testPoint.testCaseId) || ((_m = testPoint === null || testPoint === void 0 ? void 0 : testPoint.testCase) === null || _m === void 0 ? void 0 : _m.id) || 0);
952
+ if (!Number.isFinite(testCaseId) || testCaseId <= 0 || out.has(testCaseId))
953
+ continue;
954
+ const fromPoint = this.deriveMewpTestCaseResponsibility({
955
+ 'System.AreaPath': (testPoint === null || testPoint === void 0 ? void 0 : testPoint.areaPath) || (testPoint === null || testPoint === void 0 ? void 0 : testPoint.AreaPath),
956
+ 'Area Path': testPoint === null || testPoint === void 0 ? void 0 : testPoint['Area Path'],
957
+ AreaPath: testPoint === null || testPoint === void 0 ? void 0 : testPoint.AreaPath,
958
+ });
959
+ if (fromPoint) {
960
+ out.set(testCaseId, fromPoint);
961
+ unresolved.delete(testCaseId);
962
+ }
963
+ else {
964
+ unresolved.add(testCaseId);
965
+ }
966
+ }
967
+ }
968
+ if (unresolved.size > 0) {
969
+ try {
970
+ const workItems = await this.fetchWorkItemsByIds(projectName, [...unresolved], false);
971
+ for (const workItem of workItems || []) {
972
+ const testCaseId = Number((workItem === null || workItem === void 0 ? void 0 : workItem.id) || 0);
973
+ if (!Number.isFinite(testCaseId) || testCaseId <= 0 || out.has(testCaseId))
974
+ continue;
975
+ const resolved = this.deriveMewpTestCaseResponsibility((workItem === null || workItem === void 0 ? void 0 : workItem.fields) || {});
976
+ if (!resolved)
977
+ continue;
978
+ out.set(testCaseId, resolved);
979
+ }
980
+ }
981
+ catch (error) {
982
+ logger_1.default.warn(`MEWP coverage: failed to enrich test-case responsibility fallback: ${(error === null || error === void 0 ? void 0 : error.message) || error}`);
983
+ }
984
+ }
985
+ return out;
889
986
  }
890
987
  resolveMewpL2RunStatus(input) {
891
988
  if (((input === null || input === void 0 ? void 0 : input.failed) || 0) > 0)
@@ -1998,11 +2095,42 @@ class ResultDataProvider {
1998
2095
  return fromExplicitLabel;
1999
2096
  if (explicitSapWbsByLabel)
2000
2097
  return explicitSapWbsByLabel;
2001
- const areaPath = this.toMewpComparableText(fields === null || fields === void 0 ? void 0 : fields['System.AreaPath']);
2002
- const fromAreaPath = this.resolveMewpResponsibility(areaPath);
2003
- if (fromAreaPath)
2004
- return fromAreaPath;
2005
- const keyHints = ['sapwbs', 'responsibility', 'owner'];
2098
+ const areaPathCandidates = [
2099
+ fields === null || fields === void 0 ? void 0 : fields['System.AreaPath'],
2100
+ fields === null || fields === void 0 ? void 0 : fields['Area Path'],
2101
+ fields === null || fields === void 0 ? void 0 : fields['AreaPath'],
2102
+ ];
2103
+ for (const candidate of areaPathCandidates) {
2104
+ const normalized = this.toMewpComparableText(candidate);
2105
+ const resolved = this.resolveMewpResponsibility(normalized);
2106
+ if (resolved)
2107
+ return resolved;
2108
+ }
2109
+ const keyHints = ['sapwbs', 'responsibility', 'owner', 'areapath', 'area path'];
2110
+ for (const [key, value] of Object.entries(fields || {})) {
2111
+ const normalizedKey = String(key || '').toLowerCase();
2112
+ if (!keyHints.some((hint) => normalizedKey.includes(hint)))
2113
+ continue;
2114
+ const resolved = this.resolveMewpResponsibility(this.toMewpComparableText(value));
2115
+ if (resolved)
2116
+ return resolved;
2117
+ }
2118
+ return '';
2119
+ }
2120
+ // Test-case responsibility must come from test-case path context (not SAPWBS).
2121
+ deriveMewpTestCaseResponsibility(fields) {
2122
+ const areaPathCandidates = [
2123
+ fields === null || fields === void 0 ? void 0 : fields['System.AreaPath'],
2124
+ fields === null || fields === void 0 ? void 0 : fields['Area Path'],
2125
+ fields === null || fields === void 0 ? void 0 : fields['AreaPath'],
2126
+ ];
2127
+ for (const candidate of areaPathCandidates) {
2128
+ const normalized = this.toMewpComparableText(candidate);
2129
+ const resolved = this.resolveMewpResponsibility(normalized);
2130
+ if (resolved)
2131
+ return resolved;
2132
+ }
2133
+ const keyHints = ['areapath', 'area path', 'responsibility', 'owner'];
2006
2134
  for (const [key, value] of Object.entries(fields || {})) {
2007
2135
  const normalizedKey = String(key || '').toLowerCase();
2008
2136
  if (!keyHints.some((hint) => normalizedKey.includes(hint)))
@@ -2404,7 +2532,6 @@ class ResultDataProvider {
2404
2532
  logger_1.default.warn(`Invalid run result ${runId} or result ${resultId}`);
2405
2533
  return null;
2406
2534
  }
2407
- logger_1.default.warn(`Current Test point for Test case ${point.testCaseId} is in Active state`);
2408
2535
  const url = `${this.orgUrl}${projectName}/_apis/wit/workItems/${point.testCaseId}?$expand=all`;
2409
2536
  const testCaseData = await tfs_1.TFSServices.getItemContent(url, this.token);
2410
2537
  const newResultData = {