WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit a144076

Browse files
author
Luigi Pellecchia
committed
Fix waterfall completion. Change coverage to completion in the UI. Extend Spdx manager to nested documents. Fix traceabilith graph generation considering duplicated items on separate branches (snippets).
Signed-off-by: Luigi Pellecchia <[email protected]>
1 parent e6d930b commit a144076

21 files changed

+161
-106
lines changed

api/api.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2649,8 +2649,13 @@ def get(self):
26492649
unmapped_sections = [x for x in mapping[_TSs] if not x["match"]]
26502650
unmapped_sections += [x for x in mapping[_Js] if not x["match"]]
26512651
unmapped_sections += [x for x in mapping[_Ds] if not x["match"]]
2652-
ret = {"mapped": mapped_sections, "unmapped": unmapped_sections}
26532652

2653+
for iMS in range(len(mapped_sections)):
2654+
for iD in range(len(mapped_sections[iMS][_Ds])):
2655+
document_children_data = get_document_children(dbi, mapped_sections[iMS][_Ds][iD])
2656+
mapped_sections[iMS][_Ds][iD] = document_children_data
2657+
2658+
ret = {"mapped": mapped_sections, "unmapped": unmapped_sections}
26542659
return ret
26552660

26562661
def post(self):
@@ -2967,8 +2972,13 @@ def get(self):
29672972
unmapped_sections = [x for x in mapping[_TCs] if not x["match"]]
29682973
unmapped_sections += [x for x in mapping[_Js] if not x["match"]]
29692974
unmapped_sections += [x for x in mapping[_Ds] if not x["match"]]
2970-
ret = {"mapped": mapped_sections, "unmapped": unmapped_sections}
29712975

2976+
for iMS in range(len(mapped_sections)):
2977+
for iD in range(len(mapped_sections[iMS][_Ds])):
2978+
document_children_data = get_document_children(dbi, mapped_sections[iMS][_Ds][iD])
2979+
mapped_sections[iMS][_Ds][iD] = document_children_data
2980+
2981+
ret = {"mapped": mapped_sections, "unmapped": unmapped_sections}
29722982
return ret
29732983

29742984
def post(self):
@@ -3552,6 +3562,7 @@ def get(self):
35523562

35533563
mapped_sections = get_split_sections(api_specification, mapping, [_J])
35543564
unmapped_sections = [x for x in mapping[_Js] if not x["match"]]
3565+
35553566
ret = {"mapped": mapped_sections, "unmapped": unmapped_sections}
35563567

35573568
return ret

api/spdx_manager.py

Lines changed: 97 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from db.models.api_test_case import ApiTestCaseModel # noqa E402
2222
from db.models.api_test_specification import ApiTestSpecificationModel # noqa E402
2323
from db.models.document import DocumentModel # noqa E402
24+
from db.models.document_document import DocumentDocumentModel # noqa E402
2425
from db.models.justification import JustificationModel # noqa E402
2526
from db.models.sw_requirement import SwRequirementModel # noqa E402
2627
from db.models.sw_requirement_sw_requirement import SwRequirementSwRequirementModel # noqa E402
@@ -1052,6 +1053,52 @@ def addTestRun(self, test_run: TestRunModel = None, dbsession=None):
10521053
self.add_to_sbom(tr_annotation)
10531054
return tr_file
10541055

1056+
def addDocumentsNestedElements(
1057+
self,
1058+
api: ApiModel = None,
1059+
xdoc: Optional[Union[ApiDocumentModel, DocumentDocumentModel]] = None,
1060+
spdx_doc: SPDXFile = None, # SPDX object of Document from xdoc.document
1061+
dbsession=None,
1062+
):
1063+
"""In BASIL user can create a complex hierarchy of Documents.
1064+
Moreover we can assign other work items to each Document in the chain.
1065+
This method navigate the hierarchy and return all the work items
1066+
1067+
:param api: software component where the mapping is defined
1068+
:param xdoc: Document mapping model instance
1069+
:param spdx_doc: DocumentSPDX instance
1070+
:param dbi: Database interface instance
1071+
:return:
1072+
"""
1073+
if isinstance(xdoc, ApiDocumentModel):
1074+
mapping_field = f"{ApiDocumentModel.__tablename__}"
1075+
mapping_field_id = f"{mapping_field}_id"
1076+
elif isinstance(xdoc, DocumentDocumentModel):
1077+
mapping_field = f"{DocumentDocumentModel.__tablename__}"
1078+
mapping_field_id = f"{mapping_field}_id"
1079+
else:
1080+
return
1081+
1082+
# DocumentDocumentModel
1083+
doc_docs = (
1084+
dbsession.query(DocumentDocumentModel)
1085+
.filter(getattr(DocumentDocumentModel, mapping_field_id) == xdoc.id)
1086+
.all()
1087+
)
1088+
for doc_doc in doc_docs:
1089+
spdx_doc_doc = self.addDocument(document=doc_doc.document, dbsession=dbsession)
1090+
self.addRelationship(
1091+
from_element=spdx_doc,
1092+
to=[spdx_doc_doc],
1093+
relationship_type="hasDocument",
1094+
completeness_percentage=doc_doc.coverage,
1095+
)
1096+
1097+
# DocumentDocument
1098+
self.addDocumentsNestedElements(
1099+
api=api, xdoc=doc_doc, spdx_doc=spdx_doc_doc, dbsession=dbsession
1100+
)
1101+
10551102
def addSoftwareRequirementNestedElements(
10561103
self,
10571104
api: ApiModel = None,
@@ -1275,6 +1322,8 @@ def addApiDocuments(self, spdx_api=None, spdx_api_ref_doc=None, api: ApiModel =
12751322
completeness_percentage=adoc.coverage,
12761323
)
12771324

1325+
self.addDocumentsNestedElements(api=api, xdoc=adoc, spdx_doc=spdx_doc, dbsession=dbsession)
1326+
12781327
def addApiJustifications(self, spdx_api=None, spdx_api_ref_doc=None, api: ApiModel = None, dbsession=None):
12791328
# ApiJustifications
12801329
api_justifications = (
@@ -1302,6 +1351,21 @@ def generate_diagraph(self, output_file: str = ""):
13021351
- output_file: output PNG file name
13031352
"""
13041353

1354+
def allowed_duplicate_node(node):
1355+
allowed_ids = [
1356+
"basil:document:",
1357+
"basil:software-requirement:",
1358+
"basil:test-specification:",
1359+
"basil:test-case:",
1360+
"basil:test-run:",
1361+
"basil:justification:",
1362+
]
1363+
1364+
ret = any(allowed_id in node.spdx_id for allowed_id in allowed_ids)
1365+
if ret:
1366+
return True
1367+
return False
1368+
13051369
def get_file_node_color(node):
13061370
purpose_colors = {
13071371
"library": "brown",
@@ -1339,45 +1403,59 @@ def add_edge(src, dst, label):
13391403
# Add edges with appropriate colors
13401404
relationships = [item for item in self.sbom if isinstance(item, SPDXRelationship)]
13411405

1406+
iRel = 0
13421407
for relationship in relationships:
13431408
if not [item for item in relationship.to if isinstance(item, SPDXFile)]:
13441409
continue
13451410

1411+
iRel += 1
13461412
for to_relationship in relationship.to:
1413+
# Allow duplicates nodes for
1414+
# each work items as using the same node can results into a wrong mapping graph
13471415
from_node = relationship.from_element
1348-
from_node_str = from_node.spdx_id.replace(":", "_")
1416+
from_node_label = from_node.spdx_id.replace(":", "_")
1417+
if allowed_duplicate_node(from_node):
1418+
from_node_id = f"{iRel-1}_{from_node_label}"
1419+
else:
1420+
from_node_id = from_node_label
13491421
from_color = get_file_node_color(from_node)
13501422

13511423
to_node = to_relationship
1352-
to_node_str = to_node.spdx_id.replace(":", "_")
1424+
to_node_label = to_node.spdx_id.replace(":", "_")
1425+
if allowed_duplicate_node(to_node):
1426+
to_node_id = f"{iRel}_{to_node_label}"
1427+
else:
1428+
to_node_id = to_node_label
13531429
to_color = get_file_node_color(to_node)
13541430

13551431
# Add 'from' node with color based on type
1356-
if from_node_str not in added_nodes:
1357-
dot.node(from_node_str, style="filled", fillcolor=from_color)
1358-
added_nodes[from_node_str] = from_color
1432+
if from_node_id not in added_nodes:
1433+
dot.node(from_node_id, label=from_node_label, style="filled", fillcolor=from_color)
1434+
added_nodes[from_node_id] = from_color
13591435

13601436
# Add 'to' node with color based on type
1361-
if to_node_str not in added_nodes:
1362-
dot.node(to_node_str, style="filled", fillcolor=to_color)
1363-
added_nodes[to_node_str] = to_color
1437+
if to_node_id not in added_nodes:
1438+
dot.node(to_node_id, label=to_node_label, style="filled", fillcolor=to_color)
1439+
added_nodes[to_node_id] = to_color
13641440

13651441
if isinstance(to_node, SPDXSnippet):
1366-
from_file_str = to_node.from_file.spdx_id.replace(":", "_")
1367-
if from_file_str not in added_nodes:
1368-
dot.node(from_file_str, style="filled", fillcolor="yellow")
1369-
added_nodes[from_file_str] = "yellow"
1370-
add_edge(from_file_str, to_node_str, "contains")
1442+
from_file_label = to_node.from_file.spdx_id.replace(":", "_")
1443+
from_file_id = from_file_label
1444+
if from_file_id not in added_nodes:
1445+
dot.node(from_file_id, label=from_file_label, style="filled", fillcolor="yellow")
1446+
added_nodes[from_file_id] = "yellow"
1447+
add_edge(from_file_id, to_node_id, "contains")
13711448

13721449
if isinstance(from_node, SPDXSnippet):
1373-
from_file_str = from_node.from_file.spdx_id.replace(":", "_")
1374-
if from_file_str not in added_nodes:
1375-
dot.node(from_file_str, style="filled", fillcolor="yellow")
1376-
added_nodes[from_file_str] = "yellow"
1377-
add_edge(from_file_str, from_node_str, "contains")
1450+
from_file_label = from_node.from_file.spdx_id.replace(":", "_")
1451+
from_file_id = from_file_label
1452+
if from_file_id not in added_nodes:
1453+
dot.node(from_file_id, label=from_file_label, style="filled", fillcolor="yellow")
1454+
added_nodes[from_file_id] = "yellow"
1455+
add_edge(from_file_id, from_node_id, "contains")
13781456

13791457
# Add edge without special color
1380-
add_edge(from_node_str, to_node_str, label=relationship.relationship_type)
1458+
add_edge(from_node_id, to_node_id, label=relationship.relationship_type)
13811459

13821460
# Populate dot edges
13831461
for edge in sorted(added_edges):

app/src/app/Constants/constants.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ export const API_AI_SUGGEST_TEST_SPEC_METADATA_ENDPOINT = '/ai/suggest/test-spec
5858
export const API_SPDX_API_EXPORT_ENDPOINT = '/spdx/apis'
5959
export const API_SPDX_API_EXPORT_DOWNLOAD_ENDPOINT = '/spdx/apis/export-download'
6060

61+
export const FORM_COMPLETION_LABEL = 'Completion (how much of the parent is covered by this work item) [0-100]:'
62+
6163
export const JSON_HEADER = {
6264
Accept: 'application/json',
6365
'Content-Type': 'application/json'

app/src/app/Custom/LeavesProgressBar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const LeavesProgressBar: React.FunctionComponent<LeavesProgressBarProps> = ({
5858
</div>
5959
<Tooltip
6060
id={progressId + '-ref2'}
61-
content={<div>Coverage {Constants.percentageStringFormat(limited_progress)}%</div>}
61+
content={<div>Completion {Constants.percentageStringFormat(limited_progress)}%</div>}
6262
triggerRef={() => document.getElementById(progressId) as HTMLElement}
6363
/>
6464
</React.Fragment>

app/src/app/Dashboard/APIListingTable.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ const APIListingTable: React.FunctionComponent<APIListingTableProps> = ({
8181
library_version: 'Version',
8282
created_by: 'Owner',
8383
category: 'Category',
84-
coverage: 'Last Coverage',
84+
coverage: 'Last Completion',
8585
notifications: 'Notifications',
8686
actions: 'Actions'
8787
}

app/src/app/Mapping/Form/DocumentForm.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ export const DocumentForm: React.FunctionComponent<DocumentFormProps> = ({
605605
) : (
606606
''
607607
)}
608-
<FormGroup label='Unique Coverage:' isRequired fieldId={`input-document-${formAction}-coverage-${formData.id}`}>
608+
<FormGroup label={Constants.FORM_COMPLETION_LABEL} isRequired fieldId={`input-document-${formAction}-coverage-${formData.id}`}>
609609
<TextInput
610610
isRequired
611611
id={`input-document-${formAction}-coverage-${formData.id}`}

app/src/app/Mapping/Form/JustificationForm.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,8 @@ export const JustificationForm: React.FunctionComponent<JustificationFormProps>
256256
)}
257257
</FormGroup>
258258

259-
<Grid hasGutter md={3}>
260-
<FormGroup label='Unique Coverage:' isRequired fieldId={`${INPUT_BASE_NAME}-${formAction}-coverage-${formData.id}`}>
259+
<Grid hasGutter md={4}>
260+
<FormGroup label={Constants.FORM_COMPLETION_LABEL} isRequired fieldId={`${INPUT_BASE_NAME}-${formAction}-coverage-${formData.id}`}>
261261
<TextInput
262262
isRequired
263263
id={`${INPUT_BASE_NAME}-${formAction}-coverage-${formData.id}`}

app/src/app/Mapping/Form/SwRequirementForm.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -422,8 +422,8 @@ export const SwRequirementForm: React.FunctionComponent<SwRequirementFormProps>
422422
</FormHelperText>
423423
)}
424424
</FormGroup>
425-
<Grid hasGutter md={3}>
426-
<FormGroup label='Unique Coverage:' fieldId={`${INPUT_BASE_NAME}-${formAction}-coverage-${formData.id}`}>
425+
<Grid hasGutter md={4}>
426+
<FormGroup label={Constants.FORM_COMPLETION_LABEL} fieldId={`${INPUT_BASE_NAME}-${formAction}-coverage-${formData.id}`}>
427427
<TextInput
428428
id={`${INPUT_BASE_NAME}-${formAction}-coverage-${formData.id}`}
429429
value={coverageValue || ''}

app/src/app/Mapping/Form/TestCaseForm.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -675,8 +675,8 @@ export const TestCaseForm: React.FunctionComponent<TestCaseFormProps> = ({
675675
) : (
676676
''
677677
)}
678-
<Grid hasGutter md={3}>
679-
<FormGroup label='Unique Coverage:' isRequired fieldId={`${INPUT_BASE_NAME}-${formAction}-coverage-${formData.id}`}>
678+
<Grid hasGutter md={4}>
679+
<FormGroup label={Constants.FORM_COMPLETION_LABEL} isRequired fieldId={`${INPUT_BASE_NAME}-${formAction}-coverage-${formData.id}`}>
680680
<TextInput
681681
isRequired
682682
id={`${INPUT_BASE_NAME}-${formAction}-coverage-${formData.id}`}

app/src/app/Mapping/Form/TestSpecificationForm.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -514,8 +514,8 @@ export const TestSpecificationForm: React.FunctionComponent<TestSpecificationFor
514514
)}
515515
</FormGroup>
516516

517-
<Grid hasGutter md={3}>
518-
<FormGroup label='Unique Coverage:' isRequired fieldId={`${INPUT_BASE_NAME}-${formAction}-coverage-${formData.id}`}>
517+
<Grid hasGutter md={4}>
518+
<FormGroup label={Constants.FORM_COMPLETION_LABEL} isRequired fieldId={`${INPUT_BASE_NAME}-${formAction}-coverage-${formData.id}`}>
519519
<TextInput
520520
isRequired
521521
id={`${INPUT_BASE_NAME}-${formAction}-coverage-${formData.id}`}

0 commit comments

Comments
 (0)