Skip to content

Commit 64df5f7

Browse files
authored
Add ability to filter by run status on Project list #413 (#490)
1 parent b4806e5 commit 64df5f7

File tree

5 files changed

+79
-9
lines changed

5 files changed

+79
-9
lines changed

CHANGELOG.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ v31.0.0 (next)
5353
- Creation date displayed under the project name
5454
- Add ability to sort by date and name
5555
- Add ability to filter by pipeline type
56+
- Add ability to filter by run status
5657

5758
https://github.com/nexB/scancode.io/issues/413
5859

Makefile

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ PYTHON_EXE?=python3
2525
MANAGE=bin/python manage.py
2626
ACTIVATE?=. bin/activate;
2727
VIRTUALENV_PYZ=etc/thirdparty/virtualenv.pyz
28-
BLACK_ARGS=--exclude="migrations|data|lib|bin|var" .
28+
BLACK_ARGS=--exclude="migrations|data|lib|bin|var"
29+
PYCODESTYLE_ARGS=--max-line-length=88 \
30+
--exclude=lib,thirdparty,docs,bin,migrations,settings.py,data,pipelines,var
2931
# Do not depend on Python to generate the SECRET_KEY
3032
GET_SECRET_KEY=`base64 /dev/urandom | head -c50`
3133
# Customize with `$ make envfile ENV_FILE=/etc/scancodeio/.env`
@@ -64,11 +66,11 @@ envfile:
6466

6567
isort:
6668
@echo "-> Apply isort changes to ensure proper imports ordering"
67-
bin/isort .
69+
@${ACTIVATE} isort .
6870

6971
black:
7072
@echo "-> Apply black code formatter"
71-
bin/black ${BLACK_ARGS}
73+
@${ACTIVATE} black ${BLACK_ARGS} .
7274

7375
doc8:
7476
@echo "-> Run doc8 validation"
@@ -78,11 +80,11 @@ valid: isort black doc8
7880

7981
check: doc8
8082
@echo "-> Run pycodestyle (PEP8) validation"
81-
@${ACTIVATE} pycodestyle --max-line-length=88 --exclude=lib,thirdparty,docs,bin,migrations,settings.py,data,pipelines,var .
83+
@${ACTIVATE} pycodestyle ${PYCODESTYLE_ARGS} .
8284
@echo "-> Run isort imports ordering validation"
8385
@${ACTIVATE} isort --check-only .
8486
@echo "-> Run black validation"
85-
@${ACTIVATE} black --check ${BLACK_ARGS}
87+
@${ACTIVATE} black --check ${BLACK_ARGS} .
8688

8789
clean:
8890
@echo "-> Clean the Python env"
@@ -111,7 +113,7 @@ sqlitedb:
111113
@$(MAKE) migrate
112114

113115
run:
114-
${MANAGE} runserver 8001 --noreload --insecure
116+
${MANAGE} runserver 8001 --insecure --noreload
115117

116118
test:
117119
@echo "-> Run the test suite"
@@ -122,7 +124,7 @@ worker:
122124

123125
bump:
124126
@echo "-> Bump the version"
125-
bin/bumpver update --no-fetch --patch
127+
@${ACTIVATE} bumpver update --no-fetch --patch
126128

127129
docs:
128130
rm -rf docs/_build/

scanpipe/filters.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from scanpipe.models import DiscoveredPackage
3333
from scanpipe.models import Project
3434
from scanpipe.models import ProjectError
35+
from scanpipe.models import Run
3536

3637
scanpipe_app = apps.get_app_config("scanpipe")
3738

@@ -153,6 +154,18 @@ class ProjectFilterSet(FilterSetUtilsMixin, django_filters.FilterSet):
153154
choices=scanpipe_app.get_pipeline_choices(include_blank=False),
154155
widget=BulmaDropdownWidget,
155156
)
157+
status = django_filters.ChoiceFilter(
158+
label="Status",
159+
method="filter_run_status",
160+
choices=[
161+
("not_started", "Not started"),
162+
("queued", "Queued"),
163+
("running", "Running"),
164+
("succeed", "Success"),
165+
("failed", "Failure"),
166+
],
167+
widget=BulmaDropdownWidget,
168+
)
156169

157170
class Meta:
158171
model = Project
@@ -177,6 +190,14 @@ def __init__(self, data=None, *args, **kwargs):
177190
]
178191
)
179192

193+
def filter_run_status(self, queryset, name, value):
194+
"""
195+
Filter by Run status using the `RunQuerySet` methods.
196+
"""
197+
run_queryset_method = value
198+
run_queryset = getattr(Run.objects, run_queryset_method)()
199+
return queryset.filter(runs__in=run_queryset)
200+
180201

181202
class JSONContainsFilter(django_filters.CharFilter):
182203
"""

scanpipe/templates/scanpipe/project_list.html

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
<div>
2222
{% include 'scanpipe/includes/breadcrumb.html' %}
2323
{{ filter.form.is_archived }}
24+
{% if filter.is_active %}
25+
<a class="is-grey-link" href="{% url 'project_list' %}">
26+
<i class="fas fa-times"></i> Clear search and filters
27+
</a>
28+
{% endif %}
2429
</div>
2530
<a href="{% url 'project_add' %}" class="button is-link">New Project</a>
2631
</div>
@@ -31,6 +36,7 @@
3136
</div>
3237
<div>
3338
{% include 'scanpipe/includes/filter_dropdown.html' with filter_form_field=filter.form.pipeline only %}
39+
{% include 'scanpipe/includes/filter_dropdown.html' with filter_form_field=filter.form.status only %}
3440
{% include 'scanpipe/includes/filter_dropdown.html' with filter_form_field=filter.form.sort only %}
3541
</div>
3642
</div>
@@ -41,8 +47,8 @@
4147
<div class="tile is-ancestor">
4248
<div class="tile is-parent">
4349
<article class="tile is-child box has-text-centered border-dashed">
44-
{% if filter.form.search.value %}
45-
No Projects found. <a href="{% url 'project_list' %}">Clear the search</a>
50+
{% if filter.is_active %}
51+
No Projects found. <a href="{% url 'project_list' %}">Clear search and filters</a>
4652
{% else %}
4753
<a href="{% url 'project_add' %}">New Project</a>
4854
{% endif %}

scanpipe/tests/test_filters.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,57 @@
2020
# ScanCode.io is a free software code scanning tool from nexB Inc. and others.
2121
# Visit https://github.com/nexB/scancode.io for support and download.
2222

23+
import uuid
24+
2325
from django.test import TestCase
26+
from django.utils import timezone
2427

28+
from scanpipe.filters import ProjectFilterSet
2529
from scanpipe.filters import ResourceFilterSet
2630
from scanpipe.models import CodebaseResource
2731
from scanpipe.models import Project
32+
from scanpipe.models import Run
2833

2934

3035
class ScanPipeFiltersTest(TestCase):
3136
def setUp(self):
3237
self.project1 = Project.objects.create(name="Analysis")
3338

39+
def test_scanpipe_filters_project_filterset_status(self):
40+
now = timezone.now()
41+
not_started = Project.objects.create(name="not_started")
42+
Run.objects.create(project=not_started)
43+
queued = Project.objects.create(name="queued")
44+
Run.objects.create(project=queued, task_id=uuid.uuid4())
45+
running = Project.objects.create(name="running")
46+
Run.objects.create(project=running, task_start_date=now, task_id=uuid.uuid4())
47+
succeed = Project.objects.create(name="succeed")
48+
Run.objects.create(
49+
project=succeed, task_start_date=now, task_end_date=now, task_exitcode=0
50+
)
51+
failed = Project.objects.create(name="failed")
52+
Run.objects.create(
53+
project=failed, task_start_date=now, task_end_date=now, task_exitcode=1
54+
)
55+
56+
filterset = ProjectFilterSet(data={"status": ""})
57+
self.assertEqual(6, len(filterset.qs))
58+
59+
filterset = ProjectFilterSet(data={"status": "not_started"})
60+
self.assertEqual([not_started], list(filterset.qs))
61+
62+
filterset = ProjectFilterSet(data={"status": "queued"})
63+
self.assertEqual([queued], list(filterset.qs))
64+
65+
filterset = ProjectFilterSet(data={"status": "running"})
66+
self.assertEqual([running], list(filterset.qs))
67+
68+
filterset = ProjectFilterSet(data={"status": "succeed"})
69+
self.assertEqual([succeed], list(filterset.qs))
70+
71+
filterset = ProjectFilterSet(data={"status": "failed"})
72+
self.assertEqual([failed], list(filterset.qs))
73+
3474
def test_scanpipe_filters_filter_queryset_empty_values(self):
3575
resource1 = CodebaseResource.objects.create(
3676
project=self.project1,

0 commit comments

Comments
 (0)