Skip to content

Commit 61c93ac

Browse files
authored
Add "(No value detected)" for Copyright and Holder charts #1697 (#1698)
Signed-off-by: tdruez <tdruez@nexb.com>
1 parent 3bfad95 commit 61c93ac

File tree

4 files changed

+51
-34
lines changed

4 files changed

+51
-34
lines changed

CHANGELOG.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ v34.12.0 (unreleased)
2626
Refine the CSS for the Resource viewer.
2727
https://github.com/aboutcode-org/scancode.io/pull/1692
2828

29+
- Add "(No value detected)" for Copyright and Holder charts.
30+
https://github.com/aboutcode-org/scancode.io/issues/1697
31+
2932
v34.11.0 (2025-05-02)
3033
---------------------
3134

scanpipe/tests/__init__.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,16 @@
4848
mocked_now = mock.Mock(now=lambda: datetime(2010, 10, 10, 10, 10, 10))
4949

5050

51+
def make_string(length):
52+
return str(uuid.uuid4())[:length]
53+
54+
5155
def make_project(name=None, **data):
5256
"""
5357
Create and return a Project instance.
5458
Labels can be provided using the labels=["labels1", "labels2"] argument.
5559
"""
56-
name = name or str(uuid.uuid4())[:8]
60+
name = name or make_string(8)
5761
pipelines = data.pop("pipelines", [])
5862
labels = data.pop("labels", [])
5963

@@ -68,26 +72,35 @@ def make_project(name=None, **data):
6872
return project
6973

7074

71-
def make_resource_file(project, path, **data):
75+
def make_resource(project, path, **data):
7276
return CodebaseResource.objects.create(
7377
project=project,
7478
path=path,
7579
name=path.split("/")[-1],
80+
tag=path.split("/")[0],
81+
**data,
82+
)
83+
84+
85+
def make_resource_file(project, path=None, **data):
86+
if path is None: # Empty string is allowed as path
87+
path = make_string(5)
88+
89+
return make_resource(
90+
project=project,
91+
path=path,
7692
extension="." + path.split(".")[-1],
7793
type=CodebaseResource.Type.FILE,
7894
is_text=True,
79-
tag=path.split("/")[0],
8095
**data,
8196
)
8297

8398

8499
def make_resource_directory(project, path, **data):
85-
return CodebaseResource.objects.create(
100+
return make_resource(
86101
project=project,
87102
path=path,
88-
name=path.split("/")[-1],
89103
type=CodebaseResource.Type.DIRECTORY,
90-
tag=path.split("/")[0],
91104
**data,
92105
)
93106

@@ -105,7 +118,7 @@ def make_dependency(project, **data):
105118

106119
def make_message(project, **data):
107120
if "model" not in data:
108-
data["model"] = str(uuid.uuid4())[:8]
121+
data["model"] = make_string(8)
109122

110123
if "severity" not in data:
111124
data["severity"] = ProjectMessage.Severity.ERROR

scanpipe/tests/test_views.py

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -491,30 +491,21 @@ def test_scanpipe_views_project_details_charts_view(self):
491491
self.assertNotContains(response, 'id="dependency-charts"')
492492
self.assertNotContains(response, 'id="resource-charts-charts"')
493493

494-
CodebaseResource.objects.create(
495-
project=self.project1,
496-
programming_language="Python",
497-
type=CodebaseResource.Type.FILE,
498-
)
494+
make_resource_file(self.project1, path="", programming_language="Python")
499495

500496
with self.assertNumQueries(12):
501497
response = self.client.get(url)
502498
self.assertContains(response, '{"Python": 1}')
503499

504500
def test_scanpipe_views_project_details_charts_compliance_alert(self):
505501
url = reverse("project_charts", args=[self.project1.slug])
502+
resource = make_resource_file(self.project1)
506503
expected = 'id="compliance_alert_chart"'
507504

508505
response = self.client.get(url)
509506
self.assertNotContains(response, expected)
510507

511-
response = self.client.get(url)
512-
self.assertNotContains(response, expected)
513-
514-
resource = CodebaseResource.objects.create(
515-
project=self.project1,
516-
type=CodebaseResource.Type.FILE,
517-
)
508+
# Do not trigger the save() logic.
518509
CodebaseResource.objects.filter(id=resource.id).update(
519510
compliance_alert=CodebaseResource.Compliance.ERROR
520511
)
@@ -523,6 +514,27 @@ def test_scanpipe_views_project_details_charts_compliance_alert(self):
523514
self.assertContains(response, expected)
524515
self.assertContains(response, '{"error": 1}')
525516

517+
def test_scanpipe_views_project_details_charts_copyrights(self):
518+
url = reverse("project_charts", args=[self.project1.slug])
519+
520+
make_resource_file(self.project1)
521+
copyrights = [
522+
{
523+
"copyright": "Copyright (c) nexB Inc. and others",
524+
"start_line": 2,
525+
"end_line": 2,
526+
}
527+
]
528+
make_resource_file(self.project1, copyrights=copyrights)
529+
530+
response = self.client.get(url)
531+
expected = (
532+
'<script id="file_copyrights" type="application/json">'
533+
'{"Copyright (c) nexB Inc. and others": 1, "(No value detected)": 1}'
534+
"</script>"
535+
)
536+
self.assertContains(response, expected)
537+
526538
def test_scanpipe_views_project_details_scan_summary_panels(self):
527539
url = self.project1.get_absolute_url()
528540

@@ -1089,18 +1101,8 @@ def test_scanpipe_views_codebase_relation_diff_view(self):
10891101
self.data / "codebase" / "b.txt",
10901102
]
10911103
copy_inputs(resource_files, self.project1.codebase_path)
1092-
resource1 = CodebaseResource.objects.create(
1093-
project=self.project1,
1094-
path="a.txt",
1095-
type=CodebaseResource.Type.FILE,
1096-
is_text=True,
1097-
)
1098-
resource2 = CodebaseResource.objects.create(
1099-
project=self.project1,
1100-
path="b.txt",
1101-
type=CodebaseResource.Type.FILE,
1102-
is_text=True,
1103-
)
1104+
resource1 = make_resource_file(self.project1, path="a.txt")
1105+
resource2 = make_resource_file(self.project1, path="b.txt")
11041106
data = {
11051107
"from_path": resource1.path,
11061108
"to_path": resource2.path,

scanpipe/views.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,10 +1029,9 @@ def get_context_data(self, **kwargs):
10291029
for field_name in fields:
10301030
if field_name in ["holders", "copyrights"]:
10311031
field_values = (
1032-
data.get(field_name[:-1])
1032+
data.get(field_name[:-1]) if isinstance(data, dict) else ""
10331033
for entry in qs_values
1034-
for data in entry.get(field_name, [])
1035-
if isinstance(data, dict)
1034+
for data in (entry.get(field_name, []) or [""])
10361035
)
10371036
else:
10381037
field_values = (entry[field_name] for entry in qs_values)

0 commit comments

Comments
 (0)