From 2585c80155beb3b136ed8d97912462d6d8e35822 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Sat, 13 May 2017 01:44:09 +0200 Subject: README: describe running unit tests / coverage --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 1f251647..48249ac1 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,20 @@ required. A simple debugging SMTP server can be setup using Python. In local_settings.py change the EMAIL_HOST to 'localhost' and the EMAIL_PORT to 1025. +# Running tests and coverage + +To the unittests execute the following commands: + + ./manage.py collectstatic --noinput + ./manage.py test + +Running coverage: + + pip install coverage + coverage run --omit='env*' --source='.' manage.py test + coverage report + + # Production Installation Ask someone who knows, or you are going to be in trouble. -- cgit v1.2.2 From 5922d9321a10bdf32c46b543ae13008faec2ae76 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Tue, 16 May 2017 21:53:55 +0200 Subject: Coverage \o/ --- .travis.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 81cef987..4757641f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,11 @@ language: python python: - "2.7" -install: "pip install -r requirements.txt" +install: "pip install -r requirements.txt && pip install coveralls" script: - python manage.py collectstatic --noinput - - python manage.py test + - coverage run --omit='env*' --source='.' manage.py test + +after_success: + - coveralls -- cgit v1.2.2 From 4d3a4e654ea67ed30c4547900d35b5d8df4db748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Angel=20Vel=C3=A1squez?= Date: Thu, 18 May 2017 03:16:47 -0400 Subject: Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 48249ac1..7e8eb870 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Archweb README +[![Coverage Status](https://coveralls.io/repos/github/archlinux/archweb/badge.svg?branch=master)](https://coveralls.io/github/archlinux/archweb?branch=master) + To get a pretty version of this document, run $ markdown README > README.html -- cgit v1.2.2 From ec2fc380dac586013da565bf70d3239ce71c7c47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Angel=20Vel=C3=A1squez?= Date: Thu, 18 May 2017 03:19:11 -0400 Subject: Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7e8eb870..a908a8fa 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # Archweb README +[![Build Status](https://travis-ci.org/archlinux/archweb.svg?branch=master)](https://travis-ci.org/archlinux/archweb) [![Coverage Status](https://coveralls.io/repos/github/archlinux/archweb/badge.svg?branch=master)](https://coveralls.io/github/archlinux/archweb?branch=master) To get a pretty version of this document, run -- cgit v1.2.2 From 7f703343edd432f111574a5c121465493a37189f Mon Sep 17 00:00:00 2001 From: Felix Yan Date: Thu, 18 May 2017 17:20:25 +0800 Subject: Fix a typo in templates/releng/thanks.html --- templates/releng/thanks.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/releng/thanks.html b/templates/releng/thanks.html index 2462dafd..3a10b532 100644 --- a/templates/releng/thanks.html +++ b/templates/releng/thanks.html @@ -6,7 +6,7 @@

Thanks!

Thank you for taking the time to give us this information! - Your results have been succesfully added to our database.

+ Your results have been successfully added to our database.

You can now go back to the results, give more feedback, or have a look at the look at -- cgit v1.2.2 From 053473545b686682c8b71acddcb023375617b151 Mon Sep 17 00:00:00 2001 From: Angel Velasquez Date: Thu, 18 May 2017 10:10:25 -0400 Subject: Update requirements_prod Now requirements.txt contains the base packages and is being included from requirements_prod Signed-off-by: Angel Velasquez --- requirements_prod.txt | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/requirements_prod.txt b/requirements_prod.txt index 7d311e3e..ecee1292 100644 --- a/requirements_prod.txt +++ b/requirements_prod.txt @@ -1,13 +1,4 @@ --e git+git://github.com/fredj/cssmin.git@master#egg=cssmin -Django==1.7.8 -IPy==0.83 -Markdown==2.6.2 -MarkupSafe==0.23 -bencode==1.0 -django-countries==3.3 -jsmin==2.1.1 -pgpdump==1.5 +-r requirements.txt psycopg2==2.6.1 pyinotify==0.9.6 python-memcached==1.54 -pytz>=2015.4 -- cgit v1.2.2 From 2214611dd108acb100161b8d1ae01c9dce1a5fab Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Fri, 19 May 2017 22:53:15 +0200 Subject: Fix invalid code tags Code tags should be closed with a tag Signed-off-by: Jelle van der Waa --- templates/public/download.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/public/download.html b/templates/public/download.html index 62fb3fae..6f9f558b 100644 --- a/templates/public/download.html +++ b/templates/public/download.html @@ -20,9 +20,9 @@

Release Info

The image can be burned to a CD, mounted as an ISO file, - or be directly written to a USB stick using a utility like dd. It + or be directly written to a USB stick using a utility like dd. It is intended for new installations only; an existing Arch Linux system - can always be updated with pacman -Syu.

+ can always be updated with pacman -Syu.

    {% if release.version %}
  • Current Release: {{ release.version }}
  • {% endif %} -- cgit v1.2.2 From 9c1669a7371e838af4b4ae58b2fdd9c79591ce00 Mon Sep 17 00:00:00 2001 From: Evangelos Foutras Date: Mon, 22 May 2017 11:37:32 +0300 Subject: Remove invalid filter call from mirrors/status_table.html The filter was passed an undefined variable which caused the template to be rendered as empty. Since the other table columns default to an empty string instead of "unknown", simply remove the default:"unknown" filter. Also correct a closing %} tag. --- templates/mirrors/status_table.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/mirrors/status_table.html b/templates/mirrors/status_table.html index 3f8cd2d9..1effe5a2 100644 --- a/templates/mirrors/status_table.html +++ b/templates/mirrors/status_table.html @@ -14,12 +14,12 @@ - {% for m_url in urls %} + {% for m_url in urls %} {{ m_url.url }} {{ m_url.protocol }} {% country_flag m_url.country %}{{ m_url.country.name }} {{ m_url.completion_pct|percentage:1 }} - {{ m_url.delay|duration|default:unknown }} + {{ m_url.delay|duration }} {{ m_url.duration_avg|floatvalue:2 }} {{ m_url.duration_stddev|floatvalue:2 }} {{ m_url.score|floatvalue:1|default:'∞' }} -- cgit v1.2.2 From 4a7db9346417923bcb75f8e4daf7e55ef155df6f Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Mon, 22 May 2017 14:49:06 +0200 Subject: settings: use one import for importing path --- settings.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/settings.py b/settings.py index 4a0ca9d2..dd9384a3 100644 --- a/settings.py +++ b/settings.py @@ -1,5 +1,5 @@ -import os # Django settings for archweb project. +from os import path ## Set the debug values DEBUG = False @@ -15,7 +15,7 @@ MANAGERS = ADMINS NOTIFICATIONS = ['arch-notifications@archlinux.org'] # Full path to the data directory -DEPLOY_PATH = os.path.dirname(os.path.realpath(__file__)) +DEPLOY_PATH = path.dirname(path.realpath(__file__)) # If you set this to False, Django will not use timezone-aware datetimes. USE_TZ = True @@ -44,7 +44,6 @@ LOGIN_REDIRECT_URL = '/' # Set django's User stuff to use our profile model AUTH_PROFILE_MODULE = 'devel.UserProfile' -from os import path TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', @@ -81,11 +80,11 @@ ROOT_URLCONF = 'urls' STATIC_URL = '/static/' # Location to collect static files -STATIC_ROOT = os.path.join(DEPLOY_PATH, 'collected_static') +STATIC_ROOT = path.join(DEPLOY_PATH, 'collected_static') # Look for more static files in these locations STATICFILES_DIRS = ( - os.path.join(DEPLOY_PATH, 'sitestatic'), + path.join(DEPLOY_PATH, 'sitestatic'), ) # Static files backend that allows us to use far future Expires headers -- cgit v1.2.2 From 9f7ad1aa841ea038a1ca540624d334816b8c8e84 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Mon, 22 May 2017 14:55:02 +0200 Subject: Allow templates to be debugged locally template debugging was never enabled, since TEMPLATES where defined before the local_settings where imported. So move the TEMPLATES definition under the local_settings import. --- settings.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/settings.py b/settings.py index dd9384a3..e59fb753 100644 --- a/settings.py +++ b/settings.py @@ -44,25 +44,6 @@ LOGIN_REDIRECT_URL = '/' # Set django's User stuff to use our profile model AUTH_PROFILE_MODULE = 'devel.UserProfile' -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [ - path.join(DEPLOY_PATH, 'templates') - ], - 'APP_DIRS': True, - 'OPTIONS': { - 'debug': DEBUG, - 'context_processors': [ - 'django.contrib.auth.context_processors.auth', - 'django.core.context_processors.debug', - 'django.contrib.messages.context_processors.messages', - 'main.context_processors.secure', - ], - } - } -] - MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', @@ -189,6 +170,25 @@ try: except ImportError: pass +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [ + path.join(DEPLOY_PATH, 'templates') + ], + 'APP_DIRS': True, + 'OPTIONS': { + 'debug': DEBUG, + 'context_processors': [ + 'django.contrib.auth.context_processors.auth', + 'django.core.context_processors.debug', + 'django.contrib.messages.context_processors.messages', + 'main.context_processors.secure', + ], + } + } +] + # Enable the debug toolbar if requested if DEBUG_TOOLBAR: MIDDLEWARE_CLASSES = \ -- cgit v1.2.2 From ab84d3f9459a6c536da9ee315f2284c77f60caf2 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Sat, 13 May 2017 01:51:58 +0200 Subject: mirrors: add simple test for mirror stats Add a simple /mirrors/status and MirrorUrl model tests --- mirrors/tests.py | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 mirrors/tests.py diff --git a/mirrors/tests.py b/mirrors/tests.py new file mode 100644 index 00000000..30b2d730 --- /dev/null +++ b/mirrors/tests.py @@ -0,0 +1,62 @@ +import json + +from django.test import TestCase + +from models import MirrorUrl, MirrorProtocol, Mirror + +def create_mirror_url(): + mirror = Mirror.objects.create(name='mirror1', admin_email='admin@archlinux.org') + mirror_protocol = MirrorProtocol.objects.create(protocol='http') + mirror_url = MirrorUrl.objects.create(url='https://archlinux.org', protocol=mirror_protocol, + mirror=mirror, country='US') + return mirror_url + +class MirrorUrlTest(TestCase): + def setUp(self): + self.mirror_url = create_mirror_url() + + def testAddressFamilies(self): + self.assertEqual(self.mirror_url.address_families(), [2, 10]) + + def testHostname(self): + self.assertEqual(self.mirror_url.hostname, 'archlinux.org') + + def testGetAbsoluteUrl(self): + absolute_url = self.mirror_url.get_absolute_url() + expected = '/mirrors/%s/%d/' % (self.mirror_url.mirror.name, self.mirror_url.pk) + self.assertEqual(absolute_url, expected) + + def testClean(self): + # TODO: add test for self.mirror_url.clean() + pass + + def tearDown(self): + self.mirror_url.delete() + +class MirrorStatusTest(TestCase): + def test_status(self): + response = self.client.get('/mirrors/status/') + self.assertEqual(response.status_code, 200) + + def test_json_endpoint(self): + response = self.client.get('/mirrors/status/json/') + self.assertEqual(response.status_code, 200) + data = json.loads(response.content) + self.assertEqual(data['urls'], []) + + mirror_url = create_mirror_url() + + # Verify that the cache works + response = self.client.get('/mirrors/status/json/') + self.assertEqual(response.status_code, 200) + data = json.loads(response.content) + + # Disables the cache_function's cache + with self.settings(CACHES={'default': {'BACKEND': 'django.core.cache.backends.dummy.DummyCache'}}): + response = self.client.get('/mirrors/status/json/') + self.assertEqual(response.status_code, 200) + data = json.loads(response.content) + + self.assertEqual(len(data['urls']), 1) + mirror = data['urls'][0] + self.assertEqual(mirror['url'], mirror_url.url) -- cgit v1.2.2 From a215f25efad5c37ac6e55715b619a25f452e06cc Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Mon, 22 May 2017 20:27:10 +0200 Subject: releng: Fix django warnings Fixes warnings for releng.Test.modules and releng.Test.rollback_modules (fields.W340) null has no effect on ManyToManyField. --- packages/migrations/0003_auto_20170524_0704.py | 19 +++++++++++++++++ releng/migrations/0004_auto_20170524_0704.py | 29 ++++++++++++++++++++++++++ releng/models.py | 4 ++-- 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 packages/migrations/0003_auto_20170524_0704.py create mode 100644 releng/migrations/0004_auto_20170524_0704.py diff --git a/packages/migrations/0003_auto_20170524_0704.py b/packages/migrations/0003_auto_20170524_0704.py new file mode 100644 index 00000000..997f329e --- /dev/null +++ b/packages/migrations/0003_auto_20170524_0704.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('packages', '0002_auto_20160731_0556'), + ] + + operations = [ + migrations.AlterField( + model_name='flagrequest', + name='user_email', + field=models.EmailField(max_length=254, verbose_name=b'email address'), + ), + ] diff --git a/releng/migrations/0004_auto_20170524_0704.py b/releng/migrations/0004_auto_20170524_0704.py new file mode 100644 index 00000000..fe4e6a66 --- /dev/null +++ b/releng/migrations/0004_auto_20170524_0704.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('releng', '0003_release_populate_last_modified'), + ] + + operations = [ + migrations.AlterField( + model_name='test', + name='modules', + field=models.ManyToManyField(to='releng.Module', blank=True), + ), + migrations.AlterField( + model_name='test', + name='rollback_modules', + field=models.ManyToManyField(related_name='rollback_test_set', to='releng.Module', blank=True), + ), + migrations.AlterField( + model_name='test', + name='user_email', + field=models.EmailField(max_length=254, verbose_name=b'email address'), + ), + ] diff --git a/releng/models.py b/releng/models.py index 66771b32..c85ab547 100644 --- a/releng/models.py +++ b/releng/models.py @@ -101,12 +101,12 @@ class Test(models.Model): source = models.ForeignKey(Source) clock_choice = models.ForeignKey(ClockChoice) filesystem = models.ForeignKey(Filesystem) - modules = models.ManyToManyField(Module, null=True, blank=True) + modules = models.ManyToManyField(Module, blank=True) bootloader = models.ForeignKey(Bootloader) rollback_filesystem = models.ForeignKey(Filesystem, related_name="rollback_test_set", null=True, blank=True) rollback_modules = models.ManyToManyField(Module, - related_name="rollback_test_set", null=True, blank=True) + related_name="rollback_test_set", blank=True) success = models.BooleanField(default=True) comments = models.TextField(null=True, blank=True) -- cgit v1.2.2 From ecc70364bb86675e1132b2dcc4677455e1a69610 Mon Sep 17 00:00:00 2001 From: Angel Velasquez Date: Wed, 24 May 2017 14:14:35 -0400 Subject: Update .gitignore Add rope cache dir to .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 5362f518..7a03c3b9 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,6 @@ tags collected_static/ testing/ env/ + +# rope +.ropeproject/ -- cgit v1.2.2 From 063784db760a85236068a8bbacd01af2d1036d4b Mon Sep 17 00:00:00 2001 From: Angel Velasquez Date: Wed, 24 May 2017 14:15:12 -0400 Subject: Fix broken reports This should fix reports that were broken cause username was passed and it wasn't needed. Also some format changes were done. --- devel/reports.py | 156 +++++++++++++++++++++++++++++-------------------------- devel/views.py | 143 +++++++++++++++++++++++++------------------------- 2 files changed, 152 insertions(+), 147 deletions(-) diff --git a/devel/reports.py b/devel/reports.py index b754b264..3d8b0fbd 100644 --- a/devel/reports.py +++ b/devel/reports.py @@ -1,17 +1,24 @@ from datetime import timedelta -import pytz +import pytz from django.db.models import F from django.template.defaultfilters import filesizeformat from django.utils.timezone import now +from main.models import PackageFile +from packages.models import Depend, PackageRelation from .models import DeveloperKey -from main.models import PackageFile -from packages.models import PackageRelation, Depend + class DeveloperReport(object): - def __init__(self, slug, name, desc, packages_func, - names=None, attrs=None, personal=True): + def __init__(self, + slug, + name, + desc, + packages_func, + names=None, + attrs=None, + personal=True): self.slug = slug self.name = name self.description = desc @@ -23,41 +30,38 @@ class DeveloperReport(object): def old(packages): cutoff = now() - timedelta(days=365 * 2) - return packages.filter( - build_date__lt=cutoff).order_by('build_date') + return packages.filter(build_date__lt=cutoff).order_by('build_date') def outofdate(packages): cutoff = now() - timedelta(days=30) - return packages.filter( - flag_date__lt=cutoff).order_by('flag_date') + return packages.filter(flag_date__lt=cutoff).order_by('flag_date') def big(packages): cutoff = 50 * 1024 * 1024 packages = packages.filter( - compressed_size__gte=cutoff).order_by('-compressed_size') + compressed_size__gte=cutoff).order_by('-compressed_size') # Format the compressed and installed sizes with MB/GB/etc suffixes for package in packages: package.compressed_size_pretty = filesizeformat( package.compressed_size) - package.installed_size_pretty = filesizeformat( - package.installed_size) + package.installed_size_pretty = filesizeformat(package.installed_size) return packages def badcompression(packages): cutoff = 0.90 * F('installed_size') - packages = packages.filter(compressed_size__gt=25*1024, - installed_size__gt=25*1024, - compressed_size__gte=cutoff).order_by('-compressed_size') + packages = packages.filter( + compressed_size__gt=25 * 1024, + installed_size__gt=25 * 1024, + compressed_size__gte=cutoff).order_by('-compressed_size') # Format the compressed and installed sizes with MB/GB/etc suffixes for package in packages: package.compressed_size_pretty = filesizeformat( package.compressed_size) - package.installed_size_pretty = filesizeformat( - package.installed_size) + package.installed_size_pretty = filesizeformat(package.installed_size) ratio = package.compressed_size / float(package.installed_size) package.ratio = '%.3f' % ratio package.compress_type = package.filename.split('.')[-1] @@ -67,18 +71,17 @@ def badcompression(packages): def uncompressed_man(packages, username): # checking for all '.0'...'.9' + '.n' extensions - bad_files = PackageFile.objects.filter(is_directory=False, - directory__contains='/man/', - filename__regex=r'\.[0-9n]').exclude( - filename__endswith='.gz').exclude( + bad_files = PackageFile.objects.filter( + is_directory=False, + directory__contains='/man/', + filename__regex=r'\.[0-9n]').exclude(filename__endswith='.gz').exclude( filename__endswith='.xz').exclude( - filename__endswith='.bz2').exclude( - filename__endswith='.html') + filename__endswith='.bz2').exclude(filename__endswith='.html') if username: pkg_ids = set(packages.values_list('id', flat=True)) bad_files = bad_files.filter(pkg__in=pkg_ids) - bad_files = bad_files.values_list( - 'pkg_id', flat=True).order_by().distinct() + bad_files = bad_files.values_list('pkg_id', + flat=True).order_by().distinct() return packages.filter(id__in=set(bad_files)) @@ -86,12 +89,13 @@ def uncompressed_info(packages, username): # we don't worry about looking for '*.info-1', etc., given that an # uncompressed root page probably exists in the package anyway bad_files = PackageFile.objects.filter(is_directory=False, - directory__endswith='/info/', filename__endswith='.info') + directory__endswith='/info/', + filename__endswith='.info') if username: pkg_ids = set(packages.values_list('id', flat=True)) bad_files = bad_files.filter(pkg__in=pkg_ids) - bad_files = bad_files.values_list( - 'pkg_id', flat=True).order_by().distinct() + bad_files = bad_files.values_list('pkg_id', + flat=True).order_by().distinct() return packages.filter(id__in=set(bad_files)) @@ -99,16 +103,15 @@ def unneeded_orphans(packages): owned = PackageRelation.objects.all().values('pkgbase') required = Depend.objects.all().values('name') # The two separate calls to exclude is required to do the right thing - return packages.exclude(pkgbase__in=owned).exclude( - pkgname__in=required) + return packages.exclude(pkgbase__in=owned).exclude(pkgname__in=required) def mismatched_signature(packages): filtered = [] packages = packages.select_related( - 'arch', 'repo', 'packager').filter(signature_bytes__isnull=False) - known_keys = DeveloperKey.objects.select_related( - 'owner').filter(owner__isnull=False) + 'arch', 'repo', 'packager').filter(signature_bytes__isnull=False) + known_keys = DeveloperKey.objects.select_related('owner').filter( + owner__isnull=False) known_keys = {dk.key: dk for dk in known_keys} for package in packages: bad = False @@ -131,7 +134,7 @@ def signature_time(packages): cutoff = timedelta(hours=24) filtered = [] packages = packages.select_related( - 'arch', 'repo', 'packager').filter(signature_bytes__isnull=False) + 'arch', 'repo', 'packager').filter(signature_bytes__isnull=False) for package in packages: sig = package.signature sig_date = sig.creation_time.replace(tzinfo=pytz.utc) @@ -142,57 +145,60 @@ def signature_time(packages): return filtered -REPORT_OLD = DeveloperReport('old', 'Old', - 'Packages last built more than two years ago', old) +REPORT_OLD = DeveloperReport( + 'old', 'Old', 'Packages last built more than two years ago', old) -REPORT_OUTOFDATE = DeveloperReport('long-out-of-date', 'Long Out-of-date', - 'Packages marked out-of-date more than 30 days ago', outofdate) +REPORT_OUTOFDATE = DeveloperReport( + 'long-out-of-date', 'Long Out-of-date', + 'Packages marked out-of-date more than 30 days ago', outofdate) -REPORT_BIG = DeveloperReport('big', 'Big', - 'Packages with compressed size > 50 MiB', big, - ['Compressed Size', 'Installed Size'], - ['compressed_size_pretty', 'installed_size_pretty']) +REPORT_BIG = DeveloperReport( + 'big', 'Big', 'Packages with compressed size > 50 MiB', big, + ['Compressed Size', 'Installed Size'], + ['compressed_size_pretty', 'installed_size_pretty']) -REPORT_BADCOMPRESS = DeveloperReport('badcompression', 'Bad Compression', - 'Packages > 25 KiB with a compression ratio < 10%', badcompression, - ['Compressed Size', 'Installed Size', 'Ratio', 'Type'], - ['compressed_size_pretty', 'installed_size_pretty','ratio', 'compress_type']) +REPORT_BADCOMPRESS = DeveloperReport( + 'badcompression', 'Bad Compression', + 'Packages > 25 KiB with a compression ratio < 10%', badcompression, + ['Compressed Size', 'Installed Size', 'Ratio', 'Type'], + ['compressed_size_pretty', 'installed_size_pretty', 'ratio', + 'compress_type']) REPORT_MAN = DeveloperReport('uncompressed-man', 'Uncompressed Manpages', - 'Packages with uncompressed manpages', uncompressed_man) + 'Packages with uncompressed manpages', + uncompressed_man) REPORT_INFO = DeveloperReport('uncompressed-info', 'Uncompressed Info Pages', - 'Packages with uncompressed info pages', uncompressed_info) + 'Packages with uncompressed info pages', + uncompressed_info) -REPORT_ORPHANS = DeveloperReport('unneeded-orphans', 'Unneeded Orphans', - 'Packages that have no maintainer and are not required by any ' - + 'other package in any repository', unneeded_orphans, - personal=False) +REPORT_ORPHANS = DeveloperReport( + 'unneeded-orphans', + 'Unneeded Orphans', + 'Packages that have no maintainer and are not required by any ' + + 'other package in any repository', + unneeded_orphans, + personal=False) -REPORT_SIGNATURE = DeveloperReport('mismatched-signature', - 'Mismatched Signatures', - 'Packages where the signing key is unknown or signer != packager', - mismatched_signature, - ['Signed By', 'Packager'], - ['sig_by', 'packager']) +REPORT_SIGNATURE = DeveloperReport( + 'mismatched-signature', 'Mismatched Signatures', + 'Packages where the signing key is unknown or signer != packager', + mismatched_signature, ['Signed By', 'Packager'], ['sig_by', 'packager']) -REPORT_SIG_TIME = DeveloperReport('signature-time', 'Signature Time', - 'Packages where the signature timestamp is more than 24 hours ' - + 'after the build timestamp', - signature_time, - ['Signature Date', 'Packager'], - ['sig_date', 'packager']) +REPORT_SIG_TIME = DeveloperReport( + 'signature-time', 'Signature Time', + 'Packages where the signature timestamp is more than 24 hours ' + + 'after the build timestamp', signature_time, + ['Signature Date', 'Packager'], ['sig_date', 'packager']) def available_reports(): - return ( - REPORT_OLD, - REPORT_OUTOFDATE, - REPORT_BIG, - REPORT_BADCOMPRESS, - REPORT_MAN, - REPORT_INFO, - REPORT_ORPHANS, - REPORT_SIGNATURE, - REPORT_SIG_TIME, - ) + return (REPORT_OLD, + REPORT_OUTOFDATE, + REPORT_BIG, + REPORT_BADCOMPRESS, + REPORT_MAN, + REPORT_INFO, + REPORT_ORPHANS, + REPORT_SIGNATURE, + REPORT_SIG_TIME, ) diff --git a/devel/views.py b/devel/views.py index 66f6a965..e86c60c1 100644 --- a/devel/views.py +++ b/devel/views.py @@ -1,33 +1,32 @@ -from datetime import timedelta import operator import time +from datetime import timedelta -from django.http import HttpResponseRedirect -from django.contrib.auth.decorators import \ - login_required, permission_required, user_passes_test from django.contrib import admin -from django.contrib.admin.models import LogEntry, ADDITION +from django.contrib.admin.models import ADDITION, LogEntry +from django.contrib.auth.decorators import (login_required, + permission_required, + user_passes_test) from django.contrib.auth.models import User from django.contrib.contenttypes.models import ContentType from django.db import transaction from django.db.models import Count, Max -from django.http import Http404 +from django.http import Http404, HttpResponseRedirect from django.shortcuts import get_object_or_404, render -from django.views.decorators.cache import never_cache from django.utils.encoding import force_unicode from django.utils.http import http_date from django.utils.timezone import now - -from .forms import ProfileForm, UserProfileForm, NewUserForm -from .models import UserProfile -from .reports import available_reports -from main.models import Package -from main.models import Arch, Repo +from django.views.decorators.cache import never_cache +from main.models import Arch, Package, Repo from news.models import News -from packages.models import PackageRelation, Signoff, FlagRequest +from packages.models import FlagRequest, PackageRelation, Signoff from packages.utils import get_signoff_groups from todolists.models import TodolistPackage from todolists.utils import get_annotated_todolists + +from .forms import NewUserForm, ProfileForm, UserProfileForm +from .models import UserProfile +from .reports import available_reports from .utils import get_annotated_maintainers @@ -41,25 +40,26 @@ def index(request): inner_q = inner_q.values('pkgbase') flagged = Package.objects.normal().filter( - flag_date__isnull=False, pkgbase__in=inner_q).order_by('pkgname') + flag_date__isnull=False, pkgbase__in=inner_q).order_by('pkgname') todopkgs = TodolistPackage.objects.select_related( - 'todolist', 'pkg', 'arch', 'repo').exclude( + 'todolist', 'pkg', 'arch', 'repo').exclude( status=TodolistPackage.COMPLETE).filter(removed__isnull=True) - todopkgs = todopkgs.filter(pkgbase__in=inner_q).order_by( - 'todolist__name', 'pkgname') + todopkgs = todopkgs.filter(pkgbase__in=inner_q).order_by('todolist__name', + 'pkgname') todolists = get_annotated_todolists(incomplete_only=True) - signoffs = sorted(get_signoff_groups(user=request.user), - key=operator.attrgetter('pkgbase')) + signoffs = sorted( + get_signoff_groups(user=request.user), + key=operator.attrgetter('pkgbase')) page_dict = { - 'todos': todolists, - 'flagged': flagged, - 'todopkgs': todopkgs, - 'signoffs': signoffs, - 'reports': available_reports(), + 'todos': todolists, + 'flagged': flagged, + 'todopkgs': todopkgs, + 'signoffs': signoffs, + 'reports': available_reports(), } return render(request, 'devel/index.html', page_dict) @@ -69,35 +69,37 @@ def index(request): def stats(request): """The second half of the dev dashboard.""" arches = Arch.objects.all().annotate( - total_ct=Count('packages'), flagged_ct=Count('packages__flag_date')) + total_ct=Count('packages'), + flagged_ct=Count('packages__flag_date')) repos = Repo.objects.all().annotate( - total_ct=Count('packages'), flagged_ct=Count('packages__flag_date')) + total_ct=Count('packages'), + flagged_ct=Count('packages__flag_date')) # the join is huge unless we do this separately, so merge the result here repo_maintainers = dict(Repo.objects.order_by().filter( - userprofile__user__is_active=True).values_list('id').annotate( - Count('userprofile'))) + userprofile__user__is_active=True).values_list('id').annotate(Count( + 'userprofile'))) for repo in repos: repo.maintainer_ct = repo_maintainers.get(repo.id, 0) maintainers = get_annotated_maintainers() maintained = PackageRelation.objects.filter( - type=PackageRelation.MAINTAINER).values('pkgbase') + type=PackageRelation.MAINTAINER).values('pkgbase') total_orphans = Package.objects.exclude(pkgbase__in=maintained).count() total_flagged_orphans = Package.objects.filter( - flag_date__isnull=False).exclude(pkgbase__in=maintained).count() + flag_date__isnull=False).exclude(pkgbase__in=maintained).count() total_updated = Package.objects.filter(packager__isnull=True).count() orphan = { - 'package_count': total_orphans, - 'flagged_count': total_flagged_orphans, - 'updated_count': total_updated, + 'package_count': total_orphans, + 'flagged_count': total_flagged_orphans, + 'updated_count': total_updated, } page_dict = { - 'arches': arches, - 'repos': repos, - 'maintainers': maintainers, - 'orphan': orphan, + 'arches': arches, + 'repos': repos, + 'maintainers': maintainers, + 'orphan': orphan, } return render(request, 'devel/stats.html', page_dict) @@ -106,25 +108,23 @@ def stats(request): @login_required def clock(request): devs = User.objects.filter(is_active=True).order_by( - 'first_name', 'last_name').select_related('userprofile') + 'first_name', 'last_name').select_related('userprofile') - latest_news = dict(News.objects.filter( - author__is_active=True).values_list('author').order_by( - ).annotate(last_post=Max('postdate'))) + latest_news = dict(News.objects.filter(author__is_active=True).values_list( + 'author').order_by().annotate(last_post=Max('postdate'))) latest_package = dict(Package.objects.filter( - packager__is_active=True).values_list('packager').order_by( - ).annotate(last_build=Max('build_date'))) + packager__is_active=True).values_list('packager').order_by().annotate( + last_build=Max('build_date'))) latest_signoff = dict(Signoff.objects.filter( - user__is_active=True).values_list('user').order_by( - ).annotate(last_signoff=Max('created'))) + user__is_active=True).values_list('user').order_by().annotate( + last_signoff=Max('created'))) # The extra() bit ensures we can use our 'user_id IS NOT NULL' index latest_flagreq = dict(FlagRequest.objects.filter( - user__is_active=True).extra( - where=['user_id IS NOT NULL']).values_list('user_id').order_by( - ).annotate(last_flagrequest=Max('created'))) + user__is_active=True).extra(where=['user_id IS NOT NULL']).values_list( + 'user_id').order_by().annotate(last_flagrequest=Max('created'))) latest_log = dict(LogEntry.objects.filter( - user__is_active=True).values_list('user').order_by( - ).annotate(last_log=Max('action_time'))) + user__is_active=True).values_list('user').order_by().annotate( + last_log=Max('action_time'))) for dev in devs: dates = [ @@ -142,10 +142,7 @@ def clock(request): dev.last_action = None current_time = now() - page_dict = { - 'developers': devs, - 'utc_now': current_time, - } + page_dict = {'developers': devs, 'utc_now': current_time, } response = render(request, 'devel/clock.html', page_dict) if not response.has_header('Expires'): @@ -162,8 +159,9 @@ def change_profile(request): profile, _ = UserProfile.objects.get_or_create(user=request.user) if request.POST: form = ProfileForm(request.POST) - profile_form = UserProfileForm(request.POST, request.FILES, - instance=profile) + profile_form = UserProfileForm(request.POST, + request.FILES, + instance=profile) if form.is_valid() and profile_form.is_valid(): request.user.email = form.cleaned_data['email'] if form.cleaned_data['passwd1']: @@ -176,7 +174,8 @@ def change_profile(request): form = ProfileForm(initial={'email': request.user.email}) profile_form = UserProfileForm(instance=profile) return render(request, 'devel/profile.html', - {'form': form, 'profile_form': profile_form}) + {'form': form, + 'profile_form': profile_form}) @login_required @@ -190,14 +189,18 @@ def report(request, report_name, username=None): user = None if username: user = get_object_or_404(User, username=username, is_active=True) - maintained = PackageRelation.objects.filter(user=user, - type=PackageRelation.MAINTAINER).values('pkgbase') + maintained = PackageRelation.objects.filter( + user=user, type=PackageRelation.MAINTAINER).values('pkgbase') packages = packages.filter(pkgbase__in=maintained) maints = User.objects.filter(id__in=PackageRelation.objects.filter( type=PackageRelation.MAINTAINER).values('user')) - packages = report.packages(packages, username) + if report.slug == 'uncompressed-man' or report.slug == 'uncompressed-info': + packages = report.packages(packages, username) + else: + packages = report.packages(packages) + arches = {pkg.arch for pkg in packages} repos = {pkg.repo for pkg in packages} context = { @@ -217,13 +220,12 @@ def report(request, report_name, username=None): def log_addition(request, obj): """Cribbed from ModelAdmin.log_addition.""" LogEntry.objects.log_action( - user_id = request.user.pk, - content_type_id = ContentType.objects.get_for_model(obj).pk, - object_id = obj.pk, - object_repr = force_unicode(obj), - action_flag = ADDITION, - change_message = "Added via Create New User form." - ) + user_id=request.user.pk, + content_type_id=ContentType.objects.get_for_model(obj).pk, + object_id=obj.pk, + object_repr=force_unicode(obj), + action_flag=ADDITION, + change_message="Added via Create New User form.") @permission_required('auth.add_user') @@ -257,10 +259,7 @@ def admin_log(request, username=None): user = None if username: user = get_object_or_404(User, username=username) - context = { - 'title': "Admin Action Log", - 'log_user': user, - } + context = {'title': "Admin Action Log", 'log_user': user, } context.update(admin.site.each_context()) return render(request, 'devel/admin_log.html', context) -- cgit v1.2.2