from email import message_from_file
from email.header import Header, decode_header
from email.utils import parsedate_tz, mktime_tz
+from fnmatch import fnmatch
from functools import reduce
import logging
import operator
from django.utils import six
from django.utils.six.moves import map
-from patchwork.models import (
- Patch, Project, Person, Comment, State, get_default_initial_patch_state)
-from patchwork.parser import parse_patch
+from patchwork.models import (Patch, Project, Person, Comment, State,
+ DelegationRule, get_default_initial_patch_state)
+from patchwork.parser import parse_patch, patch_get_filenames
LOGGER = logging.getLogger(__name__)
patch = None
comment = None
+ filenames = None
+
+ if patchbuf:
+ filenames = patch_get_filenames(patchbuf)
if pullurl or patchbuf:
name = clean_subject(mail.get('Subject'), [project.linkname])
else:
cpatch = find_patch_for_comment(project, mail)
if not cpatch:
- return (None, None)
+ return (None, None, None)
comment = Comment(patch=cpatch, date=mail_date(mail),
content=clean_content(commentbuf),
headers=mail_headers(mail))
- return (patch, comment)
+ return (patch, comment, filenames)
def find_patch_for_comment(project, mail):
return get_default_initial_patch_state()
+def auto_delegate(project, filenames):
+ if not filenames:
+ return None
+
+ rules = list(DelegationRule.objects.filter(project=project))
+
+ patch_delegate = None
+
+ for filename in filenames:
+ file_delegate = None
+ for rule in rules:
+ if fnmatch(filename, rule.path):
+ file_delegate = rule.user
+ break
+
+ if file_delegate is None:
+ return None
+
+ if patch_delegate is not None and file_delegate != patch_delegate:
+ return None
+
+ patch_delegate = file_delegate
+
+ return patch_delegate
+
+
def get_delegate(delegate_email):
"""Return the delegate with the given email or None."""
if delegate_email:
(author, save_required) = find_author(mail)
- (patch, comment) = find_content(project, mail)
+ (patch, comment, filenames) = find_content(project, mail)
if patch:
+ delegate = get_delegate(mail.get('X-Patchwork-Delegate', '').strip())
+ if not delegate:
+ delegate = auto_delegate(project, filenames)
+
# we delay the saving until we know we have a patch.
if save_required:
author.save()
class InlinePatchTest(PatchTest):
patch_filename = '0001-add-line.patch'
test_comment = 'Test for attached patch'
+ expected_filenames = ['meep.text']
def setUp(self):
self.orig_patch = read_patch(self.patch_filename)
email = create_email(self.test_comment + '\n' + self.orig_patch)
- (self.patch, self.comment) = find_content(self.project, email)
+ self.patch, self.comment, self.filenames = find_content(
+ self.project, email)
def testPatchPresence(self):
self.assertTrue(self.patch is not None)
def testCommentContent(self):
self.assertEqual(self.comment.content, self.test_comment)
+ def testFilenames(self):
+ self.assertEqual(self.filenames, self.expected_filenames)
+
class AttachmentPatchTest(InlinePatchTest):
patch_filename = '0001-add-line.patch'
email = create_email(self.test_comment, multipart=True)
attachment = MIMEText(self.orig_patch, _subtype=self.content_subtype)
email.attach(attachment)
- (self.patch, self.comment) = find_content(self.project, email)
+ self.patch, self.comment, self.filenames = find_content(
+ self.project, email)
class AttachmentXDiffPatchTest(AttachmentPatchTest):
self.orig_patch = read_patch(self.patch_filename, self.patch_encoding)
email = create_email(self.test_comment + '\n' + self.orig_patch,
content_encoding=self.patch_encoding)
- (self.patch, self.comment) = find_content(self.project, email)
+ self.patch, self.comment, self.filenames = find_content(
+ self.project, email)
class NoCharsetInlinePatchTest(InlinePatchTest):
email = create_email(self.test_comment + '\n' + self.orig_patch)
del email['Content-Type']
del email['Content-Transfer-Encoding']
- (self.patch, self.comment) = find_content(self.project, email)
+ self.patch, self.comment, self.filenames = find_content(
+ self.project, email)
class SignatureCommentTest(InlinePatchTest):
email = create_email(
self.test_comment + '\n' +
'-- \nsig\n' + self.orig_patch)
- (self.patch, self.comment) = find_content(self.project, email)
+ self.patch, self.comment, self.filenames = find_content(
+ self.project, email)
class ListFooterTest(InlinePatchTest):
'_______________________________________________\n' +
'Linuxppc-dev mailing list\n' +
self.orig_patch)
- (self.patch, self.comment) = find_content(self.project, email)
+ self.patch, self.comment, self.filenames = find_content(
+ self.project, email)
class DiffWordInCommentTest(InlinePatchTest):
self.email = message_from_string(mail)
def testSubjectEncoding(self):
- (patch, comment) = find_content(self.project, self.email)
+ patch, comment, _ = find_content(self.project, self.email)
self.assertEqual(patch.name, self.subject)
mail_file = '0001-git-pull-request.mbox'
def testGitPullRequest(self):
- (patch, comment) = find_content(self.project, self.mail)
+ patch, comment, _ = find_content(self.project, self.mail)
self.assertTrue(patch is not None)
self.assertTrue(patch.pull_url is not None)
self.assertTrue(patch.content is None)
mail_file = '0003-git-pull-request-with-diff.mbox'
def testGitPullWithDiff(self):
- (patch, comment) = find_content(self.project, self.mail)
+ patch, comment, _ = find_content(self.project, self.mail)
self.assertTrue(patch is not None)
self.assertEqual('git://git.kernel.org/pub/scm/linux/kernel/git/tip/'
'linux-2.6-tip.git x86-fixes-for-linus',
mail_file = '0008-git-rename.mbox'
def testGitRename(self):
- (patch, comment) = find_content(self.project, self.mail)
+ patch, comment, _ = find_content(self.project, self.mail)
self.assertTrue(patch is not None)
self.assertTrue(comment is not None)
self.assertEqual(patch.content.count("\nrename from "), 2)
mail_file = '0009-git-rename-with-diff.mbox'
def testGitRename(self):
- (patch, comment) = find_content(self.project, self.mail)
+ patch, comment, _ = find_content(self.project, self.mail)
self.assertTrue(patch is not None)
self.assertTrue(comment is not None)
self.assertEqual(patch.content.count("\nrename from "), 2)
mail_file = '0007-cvs-format-diff.mbox'
def testPatch(self):
- (patch, comment) = find_content(self.project, self.mail)
+ patch, comment, _ = find_content(self.project, self.mail)
self.assertTrue(patch is not None)
self.assertTrue(comment is not None)
self.assertTrue(patch.content.startswith('Index'))
mail_file = '0010-invalid-charset.mbox'
def testPatch(self):
- (patch, comment) = find_content(self.project, self.mail)
+ patch, comment, _ = find_content(self.project, self.mail)
self.assertTrue(patch is not None)
self.assertTrue(comment is not None)
mail_file = '0011-no-newline-at-end-of-file.mbox'
def testPatch(self):
- (patch, comment) = find_content(self.project, self.mail)
+ patch, comment, _ = find_content(self.project, self.mail)
self.assertTrue(patch is not None)
self.assertTrue(comment is not None)
self.assertTrue(patch.content.startswith(