Skip to content

Commit d3d022d

Browse files
committed
feat(#590): add "Testing Version" column to todo lists; include new fixtures for todolist
dev(#590): add missing fixtures for todo lists cleanup ci/cd: fix ruff address-review: refactor for cleaner code
1 parent a7a872f commit d3d022d

6 files changed

Lines changed: 292 additions & 12 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ probably want the following:
5252
uv run ./manage.py loaddata devel/fixtures/*.json
5353
uv run ./manage.py loaddata mirrors/fixtures/*.json
5454
uv run ./manage.py loaddata releng/fixtures/*.json
55+
uv run ./manage.py loaddata todolists/fixtures/*.json
5556
7. Use the following commands to start a service instance
5657

5758
uv run ./manage.py runserver

templates/todolists/view.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ <h3>Filter Todo List Packages</h3>
7575
<th>Name</th>
7676
<th>Current Version</th>
7777
<th>Staging Version</th>
78+
<th>Testing Version</th>
7879
<th>Maintainers</th>
7980
<th>Status</th>
8081
<th>Last Touched By</th>
@@ -96,6 +97,9 @@ <h3>Filter Todo List Packages</h3>
9697
{% with staging=pkg.staging %}
9798
<td>{% if staging %}{% pkg_details_link staging staging.full_version %}{% endif %}</td>
9899
{% endwith %}
100+
{% with testing=pkg.testing %}
101+
<td>{% if testing %}{% pkg_details_link testing testing.full_version %}{% endif %}</td>
102+
{% endwith %}
99103
<td>{{ pkg.maintainers|join:', ' }}</td>
100104
<td>
101105
{% if perms.todolists.change_todolistpackage %}

todolists/fixtures/todolist.json

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
[
2+
{
3+
"model": "auth.user",
4+
"pk": 1,
5+
"fields": {
6+
"username": "developer",
7+
"first_name": "Test",
8+
"last_name": "Developer",
9+
"email": "developer@archlinux.org",
10+
"password": "pbkdf2_sha256$1000000$5mOVHaWggfkqKGsKsVpWH8$kS2tNunBSv+rrDohZXeuP9L/kX8oDe09vzab+m3WQXo=",
11+
"is_staff": true,
12+
"is_active": true,
13+
"is_superuser": true,
14+
"date_joined": "2024-01-01T00:00:00Z",
15+
"last_login": null,
16+
"groups": [],
17+
"user_permissions": []
18+
}
19+
},
20+
{
21+
"model": "main.package",
22+
"pk": 6,
23+
"fields": {
24+
"repo": 3,
25+
"arch": 3,
26+
"pkgname": "linux",
27+
"pkgbase": "linux",
28+
"pkgver": "6.9.1",
29+
"pkgrel": "2",
30+
"epoch": 0,
31+
"pkgdesc": "The Linux kernel and modules",
32+
"url": "https://www.kernel.org/",
33+
"filename": "linux-6.9.1-2-x86_64.pkg.tar.zst",
34+
"compressed_size": 72000000,
35+
"installed_size": 91000000,
36+
"build_date": "2024-05-20T10:00:00Z",
37+
"last_update": "2024-05-20T10:00:00Z",
38+
"files_last_update": null,
39+
"created": "2024-05-20T10:00:00Z",
40+
"packager_str": "Test Developer <developer@archlinux.org>",
41+
"packager": null,
42+
"signature_bytes": null,
43+
"flag_date": null
44+
}
45+
},
46+
{
47+
"model": "main.package",
48+
"pk": 7,
49+
"fields": {
50+
"repo": 16,
51+
"arch": 3,
52+
"pkgname": "systemd",
53+
"pkgbase": "systemd",
54+
"pkgver": "256.1",
55+
"pkgrel": "1",
56+
"epoch": 0,
57+
"pkgdesc": "system and service manager",
58+
"url": "https://www.github.com/systemd/systemd",
59+
"filename": "systemd-256.1-1-x86_64.pkg.tar.zst",
60+
"compressed_size": 4100000,
61+
"installed_size": 19000000,
62+
"build_date": "2024-05-22T08:00:00Z",
63+
"last_update": "2024-05-22T08:00:00Z",
64+
"files_last_update": null,
65+
"created": "2024-05-22T08:00:00Z",
66+
"packager_str": "Test Developer <developer@archlinux.org>",
67+
"packager": null,
68+
"signature_bytes": null,
69+
"flag_date": null
70+
}
71+
},
72+
{
73+
"model": "todolists.todolist",
74+
"pk": 1,
75+
"fields": {
76+
"slug": "glibc-2-40-rebuild",
77+
"name": "glibc 2.40 rebuild",
78+
"description": "Rebuild of packages affected by the glibc 2.40 soname bump.",
79+
"creator": 1,
80+
"created": "2024-05-20T09:00:00Z",
81+
"kind": 0,
82+
"last_modified": "2024-05-22T08:00:00Z",
83+
"raw": "linux\ncoreutils\npacman\nsystemd"
84+
}
85+
},
86+
{
87+
"model": "todolists.todolistpackage",
88+
"pk": 1,
89+
"fields": {
90+
"todolist": 1,
91+
"pkg": 1,
92+
"pkgname": "linux",
93+
"pkgbase": "linux",
94+
"arch": 3,
95+
"repo": 1,
96+
"created": "2024-05-20T09:00:00Z",
97+
"last_modified": "2024-05-20T09:00:00Z",
98+
"removed": null,
99+
"status": 0,
100+
"user": null,
101+
"comments": null
102+
}
103+
},
104+
{
105+
"model": "todolists.todolistpackage",
106+
"pk": 2,
107+
"fields": {
108+
"todolist": 1,
109+
"pkg": 2,
110+
"pkgname": "coreutils",
111+
"pkgbase": "coreutils",
112+
"arch": 3,
113+
"repo": 1,
114+
"created": "2024-05-20T09:00:00Z",
115+
"last_modified": "2024-05-21T14:30:00Z",
116+
"removed": null,
117+
"status": 1,
118+
"user": 1,
119+
"comments": null
120+
}
121+
},
122+
{
123+
"model": "todolists.todolistpackage",
124+
"pk": 3,
125+
"fields": {
126+
"todolist": 1,
127+
"pkg": 4,
128+
"pkgname": "pacman",
129+
"pkgbase": "pacman",
130+
"arch": 3,
131+
"repo": 1,
132+
"created": "2024-05-20T09:00:00Z",
133+
"last_modified": "2024-05-22T10:00:00Z",
134+
"removed": null,
135+
"status": 2,
136+
"user": 1,
137+
"comments": null
138+
}
139+
},
140+
{
141+
"model": "todolists.todolistpackage",
142+
"pk": 4,
143+
"fields": {
144+
"todolist": 1,
145+
"pkg": 5,
146+
"pkgname": "systemd",
147+
"pkgbase": "systemd",
148+
"arch": 3,
149+
"repo": 1,
150+
"created": "2024-05-20T09:00:00Z",
151+
"last_modified": "2024-05-20T09:00:00Z",
152+
"removed": null,
153+
"status": 0,
154+
"user": null,
155+
"comments": null
156+
}
157+
}
158+
]

todolists/tests/test_utils.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import pytest
2+
from django.utils.timezone import now
3+
4+
from main.models import Package, Repo
5+
from todolists.models import TodolistPackage
6+
from todolists.utils import attach_staging, attach_testing
7+
8+
9+
def make_package(pkgname, repo, arch):
10+
return Package.objects.create(
11+
pkgname=pkgname,
12+
pkgbase=pkgname,
13+
pkgver='1.0',
14+
pkgrel='1',
15+
epoch=0,
16+
pkgdesc='Test package',
17+
url='https://example.com',
18+
filename=f'{pkgname}-1.0-1-x86_64.pkg.tar.zst',
19+
compressed_size=1000,
20+
installed_size=2000,
21+
build_date=now(),
22+
last_update=now(),
23+
created=now(),
24+
packager_str='Test Packager',
25+
repo=repo,
26+
arch=arch,
27+
)
28+
29+
30+
@pytest.fixture
31+
def stable_pkg(repos, package):
32+
return Package.objects.get(pkgname='linux')
33+
34+
35+
@pytest.fixture
36+
def todolist_with_linux(todolist, stable_pkg, user):
37+
arch = stable_pkg.arch
38+
repo = stable_pkg.repo
39+
tlpkg = TodolistPackage.objects.create(
40+
todolist=todolist,
41+
pkg=stable_pkg,
42+
pkgname=stable_pkg.pkgname,
43+
pkgbase=stable_pkg.pkgbase,
44+
arch=arch,
45+
repo=repo,
46+
user=user,
47+
)
48+
yield todolist
49+
tlpkg.delete()
50+
51+
52+
def test_attach_testing_no_testing_pkg(todolist_with_linux):
53+
todolist = todolist_with_linux
54+
attach_testing(todolist.packages(), todolist.pk)
55+
for pkg in todolist.packages():
56+
assert pkg.testing is None
57+
58+
59+
def test_attach_testing_finds_testing_pkg(todolist_with_linux):
60+
todolist = todolist_with_linux
61+
stable_pkg = Package.objects.get(pkgname='linux', repo__testing=False, repo__staging=False)
62+
testing_repo = Repo.objects.get(name='Core-Testing')
63+
64+
testing_pkg = make_package('linux', testing_repo, stable_pkg.arch)
65+
try:
66+
attach_testing(todolist.packages(), todolist.pk)
67+
for pkg in todolist.packages():
68+
if pkg.pkgname == 'linux':
69+
assert pkg.testing is not None
70+
assert pkg.testing.repo.testing is True
71+
finally:
72+
testing_pkg.delete()
73+
74+
75+
def test_attach_testing_ignores_staging_repos(todolist_with_linux):
76+
todolist = todolist_with_linux
77+
stable_pkg = Package.objects.get(pkgname='linux', repo__testing=False, repo__staging=False)
78+
staging_repo = Repo.objects.get(name='Core-Staging')
79+
80+
staging_pkg = make_package('linux', staging_repo, stable_pkg.arch)
81+
try:
82+
attach_testing(todolist.packages(), todolist.pk)
83+
for pkg in todolist.packages():
84+
if pkg.pkgname == 'linux':
85+
assert pkg.testing is None
86+
finally:
87+
staging_pkg.delete()
88+
89+
90+
def test_attach_staging_still_works(todolist_with_linux):
91+
todolist = todolist_with_linux
92+
stable_pkg = Package.objects.get(pkgname='linux', repo__testing=False, repo__staging=False)
93+
staging_repo = Repo.objects.get(name='Core-Staging')
94+
95+
staging_pkg = make_package('linux', staging_repo, stable_pkg.arch)
96+
try:
97+
attach_staging(todolist.packages(), todolist.pk)
98+
for pkg in todolist.packages():
99+
if pkg.pkgname == 'linux':
100+
assert pkg.staging is not None
101+
assert pkg.staging.repo.staging is True
102+
finally:
103+
staging_pkg.delete()

todolists/utils.py

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,34 @@ def get_annotated_todolists(incomplete_only=False):
3939
return lists
4040

4141

42-
def attach_staging(packages, list_id):
43-
'''Look for any staging version of the packages provided and attach them
44-
to the 'staging' attribute on each package if found.'''
42+
def _attach_repo_version(packages, list_id, kind):
43+
'''Look for related packages in repos flagged by kind and attach them.
44+
45+
kind is a Repo boolean field name used as repo__{kind}=True. Only
46+
'staging' and 'testing' are used; they set package.staging or
47+
package.testing for the todolist templates.
48+
'''
4549
pkgnames = TodolistPackage.objects.filter(
4650
todolist_id=list_id).values('pkgname')
47-
staging_pkgs = Package.objects.normal().filter(repo__staging=True,
48-
pkgname__in=pkgnames)
49-
# now build a lookup dict to attach to the correct package
50-
lookup = {(p.pkgname, p.arch): p for p in staging_pkgs}
51+
related_pkgs = Package.objects.normal().filter(
52+
**{f'repo__{kind}': True},
53+
pkgname__in=pkgnames,
54+
)
55+
lookup = {(p.pkgname, p.arch): p for p in related_pkgs}
5156

52-
annotated = []
5357
for package in packages:
54-
in_staging = lookup.get((package.pkgname, package.arch), None)
55-
package.staging = in_staging
58+
setattr(package, kind, lookup.get((package.pkgname, package.arch)))
59+
60+
61+
def attach_staging(packages, list_id):
62+
'''Look for any staging version of the packages provided and attach them
63+
to the 'staging' attribute on each package if found.'''
64+
_attach_repo_version(packages, list_id, 'staging')
65+
5666

57-
return annotated
67+
def attach_testing(packages, list_id):
68+
'''Look for any testing version of the packages provided and attach them
69+
to the 'testing' attribute on each package if found.'''
70+
_attach_repo_version(packages, list_id, 'testing')
5871

5972
# vim: set ts=4 sw=4 et:

todolists/views.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from packages.utils import PackageJSONEncoder, attach_maintainers
1717

1818
from .models import Todolist, TodolistPackage
19-
from .utils import attach_staging, get_annotated_todolists
19+
from .utils import attach_staging, attach_testing, get_annotated_todolists
2020

2121

2222
class TodoListForm(forms.ModelForm):
@@ -65,6 +65,7 @@ def view(request, slug):
6565
# so accessing maintainers in the template is now cheap
6666
attach_maintainers(todolist.packages())
6767
attach_staging(todolist.packages(), todolist.pk)
68+
attach_testing(todolist.packages(), todolist.pk)
6869
arches = {tp.arch for tp in todolist.packages()}
6970
repos = {tp.repo for tp in todolist.packages()}
7071
context = {

0 commit comments

Comments
 (0)