12 Commits

Author SHA1 Message Date
Jelle van der Waa
336d686ca2 public: add spacing between past donors and a past donor
Some checks failed
Github-Actions / build (push) Failing after 7s
2025-01-25 12:10:38 +01:00
Christian Heusel
4f0e24f1f7 donate: Add link to DotcomMonitor
Signed-off-by: Christian Heusel <christian@heusel.eu>
2025-01-25 11:55:13 +01:00
Jelle van der Waa
e07054c8ea .github: run ruff in CI
Some checks failed
Github-Actions / build (push) Failing after 56s
2025-01-18 16:17:17 +01:00
Jelle van der Waa
97aae09dce flake8: limit line length to 118
Apply the same limit as the ruff configuration. flake8 is still used as
the relevant E* rules are still in preview mode.
2025-01-18 16:17:17 +01:00
Jelle van der Waa
0ce1a0ea5f main: fix last remaining line length violation 2025-01-18 16:17:17 +01:00
Jelle van der Waa
f38770be76 ruff.toml: ignore cssmin code 2025-01-18 16:17:17 +01:00
Jelle van der Waa
2d39dc6379 bump Python version to 3.13 2025-01-18 16:17:17 +01:00
Jelle van der Waa
df4b0bfd67 Fix domain being None in opensearch results
The domain came from HTTP_HOST which in our nginx configuration is not
set, furthermore other code already uses Site to obtain the domain.

Closes: #541
2025-01-18 13:18:51 +01:00
Jelle van der Waa
5da7fa80c5 treewide: reduce line length to 118 2025-01-18 12:42:02 +01:00
Jelle van der Waa
8d495d4fa7 planet: reduce line length to 118 2025-01-18 12:42:02 +01:00
Jelle van der Waa
796c3f410f todolists: reduce line length to 118 2025-01-18 12:42:02 +01:00
dependabot[bot]
37687bf9e4 build(deps): bump django from 5.0.10 to 5.0.11
Bumps [django](https://github.com/django/django) from 5.0.10 to 5.0.11.
- [Commits](https://github.com/django/django/compare/5.0.10...5.0.11)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-15 09:48:13 +01:00
28 changed files with 93 additions and 41 deletions

View File

@@ -1,3 +1,3 @@
[flake8] [flake8]
max-line-length = 300 max-line-length = 118
ignore = E731, E241, E741 ignore = E731, E241, E741

View File

@@ -9,14 +9,17 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Set up Python 3.11 - name: Set up Python 3.13
uses: actions/setup-python@v4 uses: actions/setup-python@v4
with: with:
python-version: 3.11 python-version: 3.13
- name: Install dependencies - name: Install dependencies
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install -r requirements.txt && pip install -r requirements_test.txt pip install -r requirements.txt && pip install -r requirements_test.txt && pip install ruff
- name: Run ruff
run: |
ruff check .
- name: Lint with flake8 - name: Lint with flake8
run: | run: |
make lint make lint

View File

@@ -71,7 +71,8 @@ class Database(object):
retry = False retry = False
except OperationalError as exc: except OperationalError as exc:
retry_count += 1 retry_count += 1
logger.error('Unable to update database \'%s\', retrying=%d', self.path, retry_count, exc_info=exc) logger.error('Unable to update database \'%s\', retrying=%d',
self.path, retry_count, exc_info=exc)
time.sleep(5) time.sleep(5)
if retry_count == self.retry_limit: if retry_count == self.retry_limit:

View File

@@ -89,7 +89,9 @@ class Command(BaseCommand):
for name in all_paths: for name in all_paths:
manager.add_watch(name, mask) manager.add_watch(name, mask)
handler = EventHandler(arch_paths=arch_path_map, filename_suffix='.links.tar.gz', callback_func=wrapper_read_links) handler = EventHandler(arch_paths=arch_path_map,
filename_suffix='.links.tar.gz',
callback_func=wrapper_read_links)
return pyinotify.Notifier(manager, handler) return pyinotify.Notifier(manager, handler)

View File

@@ -539,7 +539,9 @@ def parse_info(pkgname, filename, iofile):
elif blockname: elif blockname:
store[blockname].append(line) store[blockname].append(line)
else: else:
raise Exception("%s: Read package info outside a block while reading from %s: %s" % (pkgname, filename, line)) raise Exception("%s: Read package info outside a block while reading from %s: %s" % (pkgname,
filename,
line))
return store return store

View File

@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import zoneinfo import zoneinfo
from django.contrib.auth.models import Group, User from django.contrib.auth.models import Group, User
from django.core.validators import MaxValueValidator, MinValueValidator from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models from django.db import models

View File

@@ -202,7 +202,8 @@ def non_existing_dependencies(packages):
def non_reproducible_packages(packages): def non_reproducible_packages(packages):
statuses = RebuilderdStatus.objects.select_related().filter(status=RebuilderdStatus.BAD, pkg__pkgname__in=packages.values('pkgname')) statuses = RebuilderdStatus.objects.select_related().filter(status=RebuilderdStatus.BAD,
pkg__pkgname__in=packages.values('pkgname'))
return linkify_non_reproducible_packages(statuses) return linkify_non_reproducible_packages(statuses)
@@ -227,7 +228,7 @@ def orphan_dependencies(packages):
JOIN packages_packagerelation ppr ON pp.pkgbase = ppr.pkgbase JOIN packages_packagerelation ppr ON pp.pkgbase = ppr.pkgbase
JOIN (SELECT DISTINCT cp.pkgname FROM packages cp LEFT JOIN packages_packagerelation pr ON cp.pkgbase = pr.pkgbase WHERE pr.id IS NULL) child ON ppd.name = child.pkgname JOIN (SELECT DISTINCT cp.pkgname FROM packages cp LEFT JOIN packages_packagerelation pr ON cp.pkgbase = pr.pkgbase WHERE pr.id IS NULL) child ON ppd.name = child.pkgname
ORDER BY child.pkgname; ORDER BY child.pkgname;
""" """ # noqa: E501
cursor.execute(query) cursor.execute(query)
for row in cursor.fetchall(): for row in cursor.fetchall():

View File

@@ -216,7 +216,9 @@ def tier0_mirror_auth(request):
token = credentials[1] token = credentials[1]
groups = Group.objects.filter(name__in=SELECTED_GROUPS) groups = Group.objects.filter(name__in=SELECTED_GROUPS)
user = User.objects.filter(username=username, is_active=True, groups__in=groups).select_related('userprofile').first() user = User.objects.filter(username=username,
is_active=True,
groups__in=groups).select_related('userprofile').first()
if not user: if not user:
return unauthorized return unauthorized

View File

@@ -280,7 +280,8 @@ class Package(models.Model):
dep_pkgs = list(dep_pkgs) dep_pkgs = list(dep_pkgs)
dep = dep_pkgs[0] dep = dep_pkgs[0]
if len(dep_pkgs) > 1: if len(dep_pkgs) > 1:
dep_pkgs = [d for d in dep_pkgs if d.pkg.repo.testing == self.repo.testing and d.pkg.repo.staging == self.repo.staging] dep_pkgs = [d for d in dep_pkgs
if d.pkg.repo.testing == self.repo.testing and d.pkg.repo.staging == self.repo.staging]
if len(dep_pkgs) > 0: if len(dep_pkgs) > 0:
dep = dep_pkgs[0] dep = dep_pkgs[0]
trimmed.append(dep) trimmed.append(dep)

View File

@@ -1,9 +1,10 @@
import cssmin
import jsmin import jsmin
from django.contrib.staticfiles.storage import ManifestStaticFilesStorage from django.contrib.staticfiles.storage import ManifestStaticFilesStorage
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
from django.utils.encoding import smart_str from django.utils.encoding import smart_str
import cssmin
class MinifiedStaticFilesStorage(ManifestStaticFilesStorage): class MinifiedStaticFilesStorage(ManifestStaticFilesStorage):
""" """

View File

@@ -35,7 +35,7 @@ def pgp_dev_key_link(key_id):
key_id = pad_key_id(key_id) key_id = pad_key_id(key_id)
if not key_id: if not key_id:
return "Unknown" return "Unknown"
link_text = (''.join((f'<span>{key_id[i:i+4]}</span>' for i in range(0, len(key_id), 4)))) link_text = (''.join((f'<span>{key_id[i:i + 4]}</span>' for i in range(0, len(key_id), 4))))
link_text = f'<div class="pgp-key-ids">{link_text}</div>' link_text = f'<div class="pgp-key-ids">{link_text}</div>'
return pgp_key_link(key_id, link_text) return pgp_key_link(key_id, link_text)
@@ -51,7 +51,9 @@ def pgp_key_link(key_id, link_text=None):
return format_key(key_id) return format_key(key_id)
pgp_server_secure = getattr(settings, 'PGP_SERVER_SECURE', False) pgp_server_secure = getattr(settings, 'PGP_SERVER_SECURE', False)
scheme = 'https' if pgp_server_secure else 'http' scheme = 'https' if pgp_server_secure else 'http'
url = '%s://%s/pks/lookup?op=vindex&amp;fingerprint=on&amp;exact=on&amp;search=0x%s' % (scheme, pgp_server, key_id) url = '%s://%s/pks/lookup?op=vindex&amp;fingerprint=on&amp;exact=on&amp;search=0x%s' % (scheme,
pgp_server,
key_id)
if link_text is None: if link_text is None:
link_text = '0x%s' % key_id[-8:] link_text = '0x%s' % key_id[-8:]
values = (url, format_key(key_id), link_text) values = (url, format_key(key_id), link_text)

View File

@@ -54,10 +54,12 @@ class NewsCreateView(CreateView):
if settings.MAILMAN_PASSWORD: if settings.MAILMAN_PASSWORD:
headers['Approved'] = settings.MAILMAN_PASSWORD headers['Approved'] = settings.MAILMAN_PASSWORD
template = loader.get_template('news/news_email_notification.txt') template = loader.get_template('news/news_email_notification.txt')
author = newsitem.author.get_full_name()
from_ = f'"Arch Linux: Recent news updates: {author}" <{settings.ANNOUNCE_EMAIL}>'
EmailMessage( EmailMessage(
subject=f'[arch-announce] {newsitem.title}', subject=f'[arch-announce] {newsitem.title}',
body=template.render(ctx), body=template.render(ctx),
from_email=f'"Arch Linux: Recent news updates: {newsitem.author.get_full_name()}" <{settings.ANNOUNCE_EMAIL}>', from_email=from_,
to=[settings.ANNOUNCE_EMAIL], to=[settings.ANNOUNCE_EMAIL],
headers=headers).send() headers=headers).send()
return super(NewsCreateView, self).form_valid(form) return super(NewsCreateView, self).form_valid(form)

View File

@@ -53,7 +53,8 @@ def create_specification(package, log, finder):
def get_tag_info(repo, pkgbase, version): def get_tag_info(repo, pkgbase, version):
# Gitlab requires the path to the gitlab repo to be html encoded and project name encoded in a different special way # Gitlab requires the path to the gitlab repo to be html encoded and
# project name encoded in a different special way
pkgrepo = urllib.parse.quote_plus(f'{settings.GITLAB_PACKAGE_REPO}/') + gitlab_project_name_to_path(pkgbase) pkgrepo = urllib.parse.quote_plus(f'{settings.GITLAB_PACKAGE_REPO}/') + gitlab_project_name_to_path(pkgbase)
url = f'https://{settings.GITLAB_INSTANCE}/api/v4/projects/{pkgrepo}/repository/tags' url = f'https://{settings.GITLAB_INSTANCE}/api/v4/projects/{pkgrepo}/repository/tags'
@@ -112,7 +113,8 @@ def cleanup_signoff_comments():
id_signoffs = [signoff.id for g in groups for signoff in g.signoffs] id_signoffs = [signoff.id for g in groups for signoff in g.signoffs]
logger.info("Keeping %s signoffs", len(id_signoffs)) logger.info("Keeping %s signoffs", len(id_signoffs))
# FakeSignoffSpecification's have no id # FakeSignoffSpecification's have no id
id_signoffspecs = [g.specification.id for g in groups if not isinstance(g.specification, FakeSignoffSpecification)] id_signoffspecs = [g.specification.id for g in groups if not isinstance(g.specification,
FakeSignoffSpecification)]
logger.info("Keeping %s signoffspecifications", len(id_signoffspecs)) logger.info("Keeping %s signoffspecifications", len(id_signoffspecs))
Signoff.objects.exclude(id__in=id_signoffs).delete() Signoff.objects.exclude(id__in=id_signoffs).delete()

View File

@@ -253,7 +253,8 @@ class UpdateManager(models.Manager):
if new_pkg: if new_pkg:
update.action_flag = CHANGE update.action_flag = CHANGE
# ensure we should even be logging this # ensure we should even be logging this
if old_pkg.pkgver == new_pkg.pkgver and old_pkg.pkgrel == new_pkg.pkgrel and old_pkg.epoch == new_pkg.epoch: if old_pkg.pkgver == new_pkg.pkgver and old_pkg.pkgrel == new_pkg.pkgrel \
and old_pkg.epoch == new_pkg.epoch:
# all relevant fields were the same; e.g. a force update # all relevant fields were the same; e.g. a force update
return return
else: else:
@@ -395,7 +396,8 @@ class RelatedToBase(models.Model):
# actually satisfy the requirements # actually satisfy the requirements
if self.comparison and self.version: if self.comparison and self.version:
alpm = AlpmAPI() alpm = AlpmAPI()
pkgs = [pkg for pkg in pkgs if not alpm.available or alpm.compare_versions(pkg.full_version, self.comparison, self.version)] pkgs = [pkg for pkg in pkgs if not alpm.available or alpm.compare_versions(pkg.full_version,
self.comparison, self.version)]
if len(pkgs) == 0: if len(pkgs) == 0:
# couldn't find a package in the DB # couldn't find a package in the DB
# it should be a virtual depend (or a removed package) # it should be a virtual depend (or a removed package)

View File

@@ -67,6 +67,7 @@ def test_sort(client, package):
def test_packages(client, package): def test_packages(client, package):
response = client.get('/opensearch/packages/') response = client.get('/opensearch/packages/')
assert response.status_code == 200 assert response.status_code == 200
assert 'template="example.com/opensearch/packages/"' in response.content.decode()
def test_packages_suggest(client, package): def test_packages_suggest(client, package):

View File

@@ -5,6 +5,7 @@ from collections import defaultdict
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import permission_required from django.contrib.auth.decorators import permission_required
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.core.cache import cache from django.core.cache import cache
from django.db.models import Q from django.db.models import Q
from django.http import HttpResponse, HttpResponseBadRequest from django.http import HttpResponse, HttpResponseBadRequest
@@ -21,10 +22,10 @@ from ..utils import get_wrong_permissions, multilib_differences
@require_safe @require_safe
@cache_control(public=True, max_age=86400) @cache_control(public=True, max_age=86400)
def opensearch(request): def opensearch(request):
domain = "%s://%s" % (request.scheme, request.META.get('HTTP_HOST')) current_site = Site.objects.get_current()
return render(request, 'packages/opensearch.xml', return render(request, 'packages/opensearch.xml',
{'domain': domain}, {'domain': current_site.domain},
content_type='application/opensearchdescription+xml') content_type='application/opensearchdescription+xml')
@@ -140,8 +141,14 @@ def sonames(request):
name = request.GET.get('name') name = request.GET.get('name')
if name: if name:
sonames = Soname.objects.filter(name__startswith=name).values('pkg__pkgname', 'pkg__pkgver', 'pkg__pkgrel', 'pkg__epoch', 'pkg__repo__name') sonames = Soname.objects.filter(name__startswith=name).values('pkg__pkgname',
packages = [{'pkgname': soname['pkg__pkgname'], 'pkgrel': soname['pkg__pkgrel'], 'pkgver': soname['pkg__pkgver'], 'epoch': soname['pkg__epoch'], 'repo': soname['pkg__repo__name'].lower()} for soname in sonames] 'pkg__pkgver',
'pkg__pkgrel',
'pkg__epoch',
'pkg__repo__name')
packages = [{'pkgname': soname['pkg__pkgname'], 'pkgrel': soname['pkg__pkgrel'],
'pkgver': soname['pkg__pkgver'], 'epoch': soname['pkg__epoch'],
'repo': soname['pkg__repo__name'].lower()} for soname in sonames]
else: else:
return HttpResponseBadRequest('name parameter is required') return HttpResponseBadRequest('name parameter is required')

View File

@@ -38,7 +38,8 @@ class FlagForm(forms.Form):
# make sure the message isn't garbage (only punctuation or whitespace) # make sure the message isn't garbage (only punctuation or whitespace)
# or spam (using a simple denylist) # or spam (using a simple denylist)
# and ensure a certain minimum length # and ensure a certain minimum length
if re.match(r'^[^0-9A-Za-z]+$', data) or any(fd.keyword in data for fd in FlagDenylist.objects.all()) or len(data) < 3: if re.match(r'^[^0-9A-Za-z]+$', data) or any(fd.keyword in data for fd in FlagDenylist.objects.all()) \
or len(data) < 3:
raise forms.ValidationError("Enter a valid and useful out-of-date message.") raise forms.ValidationError("Enter a valid and useful out-of-date message.")
return data return data

View File

@@ -50,7 +50,8 @@ class Migration(migrations.Migration):
('author', models.CharField(max_length=255)), ('author', models.CharField(max_length=255)),
('publishdate', models.DateTimeField(db_index=True, verbose_name='publish date')), ('publishdate', models.DateTimeField(db_index=True, verbose_name='publish date')),
('url', models.CharField(max_length=255, verbose_name='URL')), ('url', models.CharField(max_length=255, verbose_name='URL')),
('feed', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='feed', to='planet.Feed')), ('feed', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE,
related_name='feed', to='planet.Feed')),
], ],
options={ options={
'verbose_name_plural': 'Feed Items', 'verbose_name_plural': 'Feed Items',

View File

@@ -14,6 +14,7 @@ class Migration(migrations.Migration):
migrations.AlterField( migrations.AlterField(
model_name='feeditem', model_name='feeditem',
name='feed', name='feed',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='items', to='planet.feed'), field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE,
related_name='items', to='planet.feed'),
), ),
] ]

View File

@@ -3,6 +3,7 @@ from datetime import datetime
from operator import attrgetter from operator import attrgetter
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.db.models import Count, Q from django.db.models import Count, Q
from django.http import HttpResponse from django.http import HttpResponse
from django.shortcuts import get_object_or_404, render from django.shortcuts import get_object_or_404, render
@@ -25,12 +26,12 @@ def index(request):
else: else:
def updates(): def updates():
return get_recent_updates() return get_recent_updates()
domain = "%s://%s" % (request.scheme, request.META.get('HTTP_HOST')) current_site = Site.objects.get_current()
context = { context = {
'news_updates': News.objects.order_by('-postdate', '-id')[:15], 'news_updates': News.objects.order_by('-postdate', '-id')[:15],
'pkg_updates': updates, 'pkg_updates': updates,
'staff_groups': StaffGroup.objects.all(), 'staff_groups': StaffGroup.objects.all(),
'domain': domain, 'domain': current_site.domain,
} }
return render(request, 'public/index.html', context) return render(request, 'public/index.html', context)
@@ -92,8 +93,9 @@ def feeds(request):
@cache_control(max_age=307) @cache_control(max_age=307)
def keys(request): def keys(request):
profile_ids = UserProfile.allowed_repos.through.objects.values('userprofile_id') profile_ids = UserProfile.allowed_repos.through.objects.values('userprofile_id')
users = User.objects.filter( users = User.objects.filter(is_active=True,
is_active=True, userprofile__id__in=profile_ids).order_by('first_name', 'last_name').select_related('userprofile') userprofile__id__in=profile_ids).order_by('first_name',
'last_name').select_related('userprofile')
user_key_ids = frozenset(user.userprofile.pgp_key[-16:] for user in users user_key_ids = frozenset(user.userprofile.pgp_key[-16:] for user in users
if user.userprofile.pgp_key) if user.userprofile.pgp_key)

View File

@@ -9,8 +9,10 @@ from .views import ReleaseDetailView, ReleaseListView
releases_patterns = [ releases_patterns = [
path('', ReleaseListView.as_view(), name='releng-release-list'), path('', ReleaseListView.as_view(), name='releng-release-list'),
path('json/', views.releases_json, name='releng-release-list-json'), path('json/', views.releases_json, name='releng-release-list-json'),
re_path(r'^(?P<version>[-.\w]+)/$', cache_page(311)(ReleaseDetailView.as_view()), name='releng-release-detail'), re_path(r'^(?P<version>[-.\w]+)/$', cache_page(311)(ReleaseDetailView.as_view()),
re_path(r'^(?P<version>[-.\w]+)/torrent/$', cache_page(311)(views.release_torrent), name='releng-release-torrent'), name='releng-release-detail'),
re_path(r'^(?P<version>[-.\w]+)/torrent/$', cache_page(311)(views.release_torrent),
name='releng-release-torrent'),
] ]
netboot_patterns = [ netboot_patterns = [

View File

@@ -1,5 +1,5 @@
-e git+https://github.com/fredj/cssmin.git@master#egg=cssmin -e git+https://github.com/fredj/cssmin.git@master#egg=cssmin
Django==5.0.10 Django==5.0.11
IPy==1.1 IPy==1.1
Markdown==3.3.7 Markdown==3.3.7
bencode.py==4.0.0 bencode.py==4.0.0

View File

@@ -24,7 +24,6 @@ select = [
] ]
ignore = [ ignore = [
"E501", # line lengt violation
"E731", # Do not assign a `lambda` expression, use a `def` "E731", # Do not assign a `lambda` expression, use a `def`
"B904", # Within an `except` clause, raise exceptions with `raise ... from err` "B904", # Within an `except` clause, raise exceptions with `raise ... from err`
"RUF012", # Mutable class attributes should be annotated with `typing.ClassVar` "RUF012", # Mutable class attributes should be annotated with `typing.ClassVar`
@@ -34,3 +33,8 @@ ignore = [
"DJ008", # Model does not define `__str__` method "DJ008", # Model does not define `__str__` method
"DJ012", # Order of model's inner classes, methods, and fields does not follow the Django Style Guide: `Meta` class should come before `get_absolute_url` "DJ012", # Order of model's inner classes, methods, and fields does not follow the Django Style Guide: `Meta` class should come before `get_absolute_url`
] ]
exclude = [
"*/migrations/*.py", # Ignore Django migrations
"src/cssmin/*" # cssmin, not our code
]

View File

@@ -266,7 +266,9 @@ if DEBUG_TOOLBAR:
INSTALLED_APPS = [*list(INSTALLED_APPS), 'debug_toolbar'] INSTALLED_APPS = [*list(INSTALLED_APPS), 'debug_toolbar']
if PROMETHEUS_METRICS: if PROMETHEUS_METRICS:
MIDDLEWARE = ['django_prometheus.middleware.PrometheusBeforeMiddleware', *list(MIDDLEWARE), 'django_prometheus.middleware.PrometheusAfterMiddleware'] MIDDLEWARE = ['django_prometheus.middleware.PrometheusBeforeMiddleware',
*list(MIDDLEWARE),
'django_prometheus.middleware.PrometheusAfterMiddleware']
INSTALLED_APPS = [*list(INSTALLED_APPS), 'django_prometheus'] INSTALLED_APPS = [*list(INSTALLED_APPS), 'django_prometheus']

View File

@@ -84,6 +84,8 @@
<h3>Past donors</h3> <h3>Past donors</h3>
<p><a href="http://www.dotcom-monitor.com/" title="Dotcom-Monitor">Dotcom-Monitor</a></p>
<div id="donor-list"> <div id="donor-list">
<ul> <ul>
{% for donor in donors %} {% for donor in donors %}

View File

@@ -28,7 +28,9 @@ class Migration(migrations.Migration):
('created', models.DateTimeField(db_index=True)), ('created', models.DateTimeField(db_index=True)),
('last_modified', models.DateTimeField(editable=False)), ('last_modified', models.DateTimeField(editable=False)),
('raw', models.TextField(blank=True)), ('raw', models.TextField(blank=True)),
('creator', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='created_todolists', to=settings.AUTH_USER_MODEL)), ('creator', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT,
related_name='created_todolists',
to=settings.AUTH_USER_MODEL)),
], ],
options={ options={
'get_latest_by': 'created', 'get_latest_by': 'created',
@@ -43,13 +45,16 @@ class Migration(migrations.Migration):
('created', models.DateTimeField(editable=False)), ('created', models.DateTimeField(editable=False)),
('last_modified', models.DateTimeField(editable=False)), ('last_modified', models.DateTimeField(editable=False)),
('removed', models.DateTimeField(blank=True, null=True)), ('removed', models.DateTimeField(blank=True, null=True)),
('status', models.SmallIntegerField(choices=[(0, 'Incomplete'), (1, 'Complete'), (2, 'In-progress')], default=0)), ('status', models.SmallIntegerField(choices=[(0, 'Incomplete'), (1, 'Complete'), (2, 'In-progress')],
default=0)),
('comments', models.TextField(blank=True, null=True)), ('comments', models.TextField(blank=True, null=True)),
('arch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='main.Arch')), ('arch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='main.Arch')),
('pkg', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='main.Package')), ('pkg', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL,
to='main.Package')),
('repo', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='main.Repo')), ('repo', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='main.Repo')),
('todolist', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='todolists.Todolist')), ('todolist', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='todolists.Todolist')),
('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL,
to=settings.AUTH_USER_MODEL)),
], ],
options={ options={
'get_latest_by': 'created', 'get_latest_by': 'created',

View File

@@ -13,6 +13,7 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='todolist', model_name='todolist',
name='kind', name='kind',
field=models.SmallIntegerField(choices=[(0, 'Rebuild'), (1, 'Task')], default=0, help_text='(Rebuild for soname bumps, Task for independent tasks)'), field=models.SmallIntegerField(choices=[(0, 'Rebuild'), (1, 'Task')], default=0,
help_text='(Rebuild for soname bumps, Task for independent tasks)'),
), ),
] ]

View File

@@ -23,7 +23,8 @@ class Todolist(models.Model):
description = models.TextField() description = models.TextField()
creator = models.ForeignKey(User, on_delete=models.PROTECT, related_name="created_todolists") creator = models.ForeignKey(User, on_delete=models.PROTECT, related_name="created_todolists")
created = models.DateTimeField(db_index=True) created = models.DateTimeField(db_index=True)
kind = models.SmallIntegerField(default=REBUILD, choices=KIND_CHOICES, help_text='(Rebuild for soname bumps, Task for independent tasks)') kind = models.SmallIntegerField(default=REBUILD, choices=KIND_CHOICES,
help_text='(Rebuild for soname bumps, Task for independent tasks)')
last_modified = models.DateTimeField(editable=False) last_modified = models.DateTimeField(editable=False)
raw = models.TextField(blank=True) raw = models.TextField(blank=True)