import os
import sys
-import django
from django.core.management.base import BaseCommand
from patchwork import models
models.CoverLetter: 0,
models.Comment: 0,
}
- duplicates = 0
dropped = 0
errors = 0
results[type(obj)] += 1
else:
dropped += 1
- except django.db.utils.IntegrityError:
- duplicates += 1
except ValueError:
# TODO(stephenfin): Perhaps we should store the broken patch
# somewhere for future reference?
' %(covers)4d cover letters\n'
' %(patches)4d patches\n'
' %(comments)4d comments\n'
- ' %(duplicates)4d duplicates\n'
' %(dropped)4d dropped\n'
' %(errors)4d errors\n'
'Total: %(new)s new entries' % {
'covers': results[models.CoverLetter],
'patches': results[models.Patch],
'comments': results[models.Comment],
- 'duplicates': duplicates,
'dropped': dropped,
'errors': errors,
- 'new': count - duplicates - dropped - errors,
+ 'new': count - dropped - errors,
})
mbox.close()
import re
from django.contrib.auth.models import User
+from django.db.utils import IntegrityError
from django.utils import six
from patchwork.models import Comment
list_id (str): Mailing list ID
Returns:
- None
+ patch/cover letter/comment
+ Or None if nothing is found in the mail
+ or X-P-H: ignore
+ or project not found
+
+ Raises:
+ ValueError if there is an error in parsing or a duplicate mail
+ Other truly unexpected issues may bubble up from the DB.
"""
# some basic sanity checks
if 'From' not in mail:
filenames = find_filenames(diff)
delegate = find_delegate_by_filename(project, filenames)
- patch = Patch.objects.create(
- msgid=msgid,
- project=project,
- patch_project=project,
- name=name[:255],
- date=date,
- headers=headers,
- submitter=author,
- content=message,
- diff=diff,
- pull_url=pull_url,
- delegate=delegate,
- state=find_state(mail))
- logger.debug('Patch saved')
+ try:
+ patch = Patch.objects.create(
+ msgid=msgid,
+ project=project,
+ patch_project=project,
+ name=name[:255],
+ date=date,
+ headers=headers,
+ submitter=author,
+ content=message,
+ diff=diff,
+ pull_url=pull_url,
+ delegate=delegate,
+ state=find_state(mail))
+ logger.debug('Patch saved')
+ except IntegrityError:
+ logger.error("Duplicate mail for message ID %s" % msgid)
+ return None
# if we don't have a series marker, we will never have an existing
# series to match against.
def test_missing_project_path(self):
path = os.path.join(TEST_MAIL_DIR, '0001-git-pull-request.mbox')
- with self.assertRaises(SystemExit) as exc:
- call_command('parsemail', infile=path)
+ call_command('parsemail', infile=path)
- self.assertEqual(exc.exception.code, 1)
+ count = models.Patch.objects.all().count()
+ self.assertEqual(count, 0)
def test_missing_project_stdin(self):
path = os.path.join(TEST_MAIL_DIR, '0001-git-pull-request.mbox')
sys.stdin.close()
sys.stdin = open(path)
- with self.assertRaises(SystemExit) as exc:
- call_command('parsemail', infile=None)
+ call_command('parsemail', infile=None)
sys.stdin.close()
- self.assertEqual(exc.exception.code, 1)
+ count = models.Patch.objects.all().count()
+ self.assertEqual(count, 0)
def test_valid_path(self):
project = utils.create_project()
utils.create_state()
path = os.path.join(TEST_MAIL_DIR, '0001-git-pull-request.mbox')
- with self.assertRaises(SystemExit) as exc:
- call_command('parsemail', infile=path, list_id=project.listid)
-
- self.assertEqual(exc.exception.code, 0)
+ call_command('parsemail', infile=path, list_id=project.listid)
count = models.Patch.objects.filter(project=project.id).count()
self.assertEqual(count, 1)
path = os.path.join(TEST_MAIL_DIR, '0001-git-pull-request.mbox')
sys.stdin.close()
sys.stdin = open(path)
- with self.assertRaises(SystemExit) as exc:
- call_command('parsemail', infile=None,
- list_id=project.listid)
+ call_command('parsemail', infile=None, list_id=project.listid)
sys.stdin.close()
- self.assertEqual(exc.exception.code, 0)
count = models.Patch.objects.filter(project=project.id).count()
self.assertEqual(count, 1)
utils.create_state()
path = os.path.join(TEST_MAIL_DIR, '0013-with-utf8-body.mbox')
- with self.assertRaises(SystemExit) as exc:
- call_command('parsemail', infile=path, list_id=project.listid)
-
- self.assertEqual(exc.exception.code, 0)
+ call_command('parsemail', infile=path, list_id=project.listid)
count = models.Patch.objects.filter(project=project.id).count()
self.assertEqual(count, 1)
path = os.path.join(TEST_MAIL_DIR, '0013-with-utf8-body.mbox')
sys.stdin.close()
sys.stdin = open(path)
- with self.assertRaises(SystemExit) as exc:
- call_command('parsemail', infile=None,
- list_id=project.listid)
+ call_command('parsemail', infile=None, list_id=project.listid)
- self.assertEqual(exc.exception.code, 0)
+ count = models.Patch.objects.filter(project=project.id).count()
+ self.assertEqual(count, 1)
+
+ def test_dup_mail(self):
+ project = utils.create_project()
+ utils.create_state()
+
+ path = os.path.join(TEST_MAIL_DIR, '0001-git-pull-request.mbox')
+ call_command('parsemail', infile=path, list_id=project.listid)
count = models.Patch.objects.filter(project=project.id).count()
self.assertEqual(count, 1)
+ # the parser should return None, not throwing an exception
+ # as this is a pretty normal part of life on a busy site
+ call_command('parsemail', infile=path, list_id=project.listid)
+
+ # this would be lovely but doesn't work because we caused an error in
+ # the transaction and we have no way to reset it
+ # count = models.Patch.objects.filter(project=project.id).count()
+ # self.assertEqual(count, 1)
+
class ParsearchiveTest(TestCase):
def test_invalid_path(self):