Skip to content

Commit 0e40aeb

Browse files
authored
fix: run "Improve from PurlDB" asynchronously (#570)
Signed-off-by: tdruez <tdruez@aboutcode.org>
1 parent 6d3e9d7 commit 0e40aeb

6 files changed

Lines changed: 62 additions & 30 deletions

File tree

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ start:
2323
@echo "-> Start the Docker compose services in background"
2424
${COMPOSE} up -d
2525

26+
stop:
27+
@echo "-> Stop the Docker compose services"
28+
${COMPOSE} stop
29+
2630
# make logs TAIL=100 SERVICE=db
2731
logs:
2832
${COMPOSE} logs -f --tail=${TAIL:-50} ${SERVICE}

product_portfolio/templates/product_portfolio/tabs/tab_activity.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
{% include 'product_portfolio/tabs/tab_activity_summary.html' %}
77
{% endblock %}
88

9-
{% block imports %}
10-
{% include 'product_portfolio/tabs/tab_activity_imports.html' %}
9+
{% block actions %}
10+
{% include 'product_portfolio/tabs/tab_activity_actions.html' %}
1111
{% endblock %}
1212

1313
{% block requests %}

product_portfolio/templates/product_portfolio/tabs/tab_activity_imports.html renamed to product_portfolio/templates/product_portfolio/tabs/tab_activity_actions.html

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
{% if has_projects_in_progress %}
55
<div class="alert alert-primary" role="alert">
66
<i class="fas fa-spinner fa-spin"></i>
7-
Imports are currently in progress. This view will automatically refresh upon
8-
completion of the import process.
7+
Actions are currently in progress.
8+
This view will automatically refresh upon completion.
99
</div>
1010
{% endif %}
1111

12-
<div class="border rounded-3 p-3 mb-4" id="activity-imports">
12+
<div class="border rounded-3 p-3 mb-4" id="activity-actions">
1313
<div class="d-flex justify-content-between align-items-center mb-3">
1414
<h3 class="fs-5 fw-medium mb-0">
15-
Imports
15+
Actions
1616
{% if scancode_projects %}<span class="text-body-tertiary fw-normal ms-1">{{ scancode_projects|length }}</span>{% endif %}
1717
</h3>
1818
{% if has_projects_in_progress %}
@@ -27,9 +27,9 @@ <h3 class="fs-5 fw-medium mb-0">
2727
<table class="table table-sm mb-0 align-middle">
2828
<thead>
2929
<tr>
30-
<th class="fw-medium">Type</th>
30+
<th class="fw-medium" style="min-width: 200px;">Type</th>
3131
<th class="fw-medium" style="width: 200px;">Status</th>
32-
<th class="fw-medium">Input</th>
32+
<th class="fw-medium" style="min-width: 200px;">Input</th>
3333
<th class="fw-medium">Log</th>
3434
</tr>
3535
</thead>
@@ -79,7 +79,7 @@ <h3 class="fs-5 fw-medium mb-0">
7979
</div>
8080
{% else %}
8181
<div class="text-body-tertiary small">
82-
No imports yet
82+
No actions yet
8383
</div>
8484
{% endif %}
8585
</div>

product_portfolio/templates/product_portfolio/tabs/tab_activity_summary.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<div class="row g-3 mb-4">
22

33
<div class="col-6 col-md-4">
4-
<div class="bg-body-secondary rounded-3 p-3 cursor-pointer" role="button" data-scroll-to="activity-imports">
5-
<div class="small text-body-secondary mb-1">Imports</div>
4+
<div class="bg-body-secondary rounded-3 p-3 cursor-pointer" role="button" data-scroll-to="activity-actions">
5+
<div class="small text-body-secondary mb-1">Actions</div>
66
<div class="fs-4 fw-medium lh-sm {% if has_projects_in_progress %}text-primary{% endif %}">{{ scancode_projects|length }}</div>
77
</div>
88
</div>

product_portfolio/tests/test_views.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ def test_product_portfolio_detail_view_tab_activit_view(self):
205205
url = self.product1.get_url("tab_activity")
206206

207207
response = self.client.get(url)
208-
self.assertContains(response, "No imports yet")
208+
self.assertContains(response, "No actions yet")
209209
self.assertContains(response, "No requests yet")
210210
self.assertContains(response, "No changes yet")
211211

@@ -220,7 +220,7 @@ def test_product_portfolio_detail_view_tab_activit_view(self):
220220
self.assertTrue(response.context["has_projects_in_progress"])
221221
htmx_refresh = 'hx-trigger="load delay:10s" hx-swap="outerHTML"'
222222
self.assertContains(response, htmx_refresh)
223-
self.assertContains(response, "Imports are currently in progress.")
223+
self.assertContains(response, "Actions are currently in progress.")
224224
self.assertContains(response, "Import SBOM")
225225

226226
project.status = ScanCodeProject.Status.SUCCESS
@@ -229,7 +229,7 @@ def test_product_portfolio_detail_view_tab_activit_view(self):
229229
self.assertFalse(response.context["has_projects_in_progress"])
230230
self.assertContains(response, "Import SBOM")
231231
self.assertNotContains(response, "hx-trigger")
232-
self.assertNotContains(response, "Imports are currently in progress.")
232+
self.assertNotContains(response, "Actions are currently in progress.")
233233

234234
expected = "File:"
235235
download_url = reverse(
@@ -243,6 +243,28 @@ def test_product_portfolio_detail_view_tab_activit_view(self):
243243
self.assertContains(response, expected)
244244
self.assertContains(response, download_url)
245245

246+
def test_product_portfolio_detail_view_tab_activity_in_progress_any_type(self):
247+
"""has_projects_in_progress is not limited to the ScanCode.io submitted types."""
248+
self.client.login(username="nexb_user", password="secret")
249+
url = self.product1.get_url("tab_activity")
250+
251+
project = ScanCodeProject.objects.create(
252+
product=self.product1,
253+
dataspace=self.product1.dataspace,
254+
type=ScanCodeProject.ProjectType.IMPROVE_FROM_PURLDB,
255+
status=ScanCodeProject.Status.IMPORT_STARTED,
256+
)
257+
258+
response = self.client.get(url)
259+
self.assertTrue(response.context["has_projects_in_progress"])
260+
self.assertContains(response, "Actions are currently in progress.")
261+
262+
project.status = ScanCodeProject.Status.SUCCESS
263+
project.save()
264+
response = self.client.get(url)
265+
self.assertFalse(response.context["has_projects_in_progress"])
266+
self.assertNotContains(response, "Actions are currently in progress.")
267+
246268
def test_product_portfolio_detail_view_tab_dependency_view(self):
247269
self.client.login(username="nexb_user", password="secret")
248270
url = self.product1.get_url("tab_dependencies")

product_portfolio/views.py

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1492,13 +1492,7 @@ class ProductTabActivityView(
14921492
def get_context_data(self, **kwargs):
14931493
context_data = super().get_context_data(**kwargs)
14941494
scancode_projects = self.object.scancodeprojects.all()
1495-
submitted_projects = self.get_submitted_projects(scancode_projects)
1496-
1497-
# Check the status of the "submitted" projects on ScanCode.io and update the
1498-
# local ScanCodeProject instances accordingly.
1499-
scancodeio = ScanCodeIO(self.request.user.dataspace)
1500-
for submitted_project in submitted_projects:
1501-
self.synchronize(scancodeio=scancodeio, project=submitted_project)
1495+
self.synchronize_scancodeio_projects(scancode_projects)
15021496

15031497
history_entries = (
15041498
History.objects.get_for_object(self.object)
@@ -1509,9 +1503,9 @@ def get_context_data(self, **kwargs):
15091503
context_data.update(
15101504
{
15111505
"tab_view_url": self.object.get_url("tab_activity"),
1512-
# Imports
1506+
# Actions
15131507
"scancode_projects": scancode_projects,
1514-
"has_projects_in_progress": bool(submitted_projects),
1508+
"has_projects_in_progress": scancode_projects.in_progress().exists(),
15151509
# Requests
15161510
"requests": self.object.get_requests(self.request.user),
15171511
# History
@@ -1521,20 +1515,32 @@ def get_context_data(self, **kwargs):
15211515

15221516
return context_data
15231517

1524-
@staticmethod
1525-
def get_submitted_projects(scancode_projects):
1526-
submitted_types = [
1518+
def synchronize_scancodeio_projects(self, scancode_projects):
1519+
"""
1520+
Poll ScanCode.io for the run status of the projects submitted to it as
1521+
external pipeline runs (SBOM and manifest imports), and update the
1522+
local ScanCodeProject status accordingly.
1523+
Other action types are handled entirely by local RQ tasks and have no
1524+
external run to poll.
1525+
"""
1526+
scancodeio_project_types = [
15271527
ScanCodeProject.ProjectType.LOAD_SBOMS,
15281528
ScanCodeProject.ProjectType.IMPORT_FROM_MANIFEST,
15291529
]
1530-
return [
1530+
pending_scancodeio_projects = [
15311531
project
15321532
for project in scancode_projects
15331533
if project.status == ScanCodeProject.Status.SUBMITTED
1534-
and project.type in submitted_types
1534+
and project.type in scancodeio_project_types
15351535
]
1536+
if not pending_scancodeio_projects:
1537+
return
1538+
1539+
scancodeio = ScanCodeIO(self.request.user.dataspace)
1540+
for project in pending_scancodeio_projects:
1541+
self.synchronize_scancodeio_project_status(scancodeio, project)
15361542

1537-
def synchronize(self, scancodeio, project):
1543+
def synchronize_scancodeio_project_status(self, scancodeio, project):
15381544
scan_detail_url = scancodeio.get_scan_detail_url(project.project_uuid)
15391545
scan_data = scancodeio.fetch_scan_data(scan_detail_url)
15401546
if not scan_data:
@@ -2899,7 +2905,7 @@ def improve_packages_from_purldb_view(request, dataspace, name, version=""):
28992905
messages.error(request, "Improve Packages already in progress...")
29002906
else:
29012907
transaction.on_commit(
2902-
lambda: improve_packages_from_purldb_task(
2908+
lambda: improve_packages_from_purldb_task.delay(
29032909
product_uuid=product.uuid,
29042910
user_uuid=user.uuid,
29052911
)

0 commit comments

Comments
 (0)