[Patchew-devel] [PATCH 14/16] model: Add and populate Message.maintainers

Fam Zheng famz at redhat.com
Wed Nov 21 02:08:44 UTC 2018


This is a json field to store a list of str to represent concerned
maintainers by the changeset as per MAINTAINERS file in the project (to
be processed by appliers).

Collect and save maintainers info in applier: if a project has
'scripts/get_maintainer.pl' file, use it to get a list of names
associated with the touched files.  This is purely ad-hoc (for QEMU) but
the logic is standalone and local so it's fairly easy to extend and
maybe parameterize later (e.g. add a command in git per-project config).

Signed-off-by: Fam Zheng <famz at redhat.com>
---
 api/migrations/0043_message_maintainers.py | 22 +++++++++++++++
 api/models.py                              |  2 ++
 mods/git.py                                |  4 ++-
 patchew-cli                                | 31 +++++++++++++++++++---
 4 files changed, 54 insertions(+), 5 deletions(-)
 create mode 100644 api/migrations/0043_message_maintainers.py

diff --git a/api/migrations/0043_message_maintainers.py b/api/migrations/0043_message_maintainers.py
new file mode 100644
index 0000000..c3d61b2
--- /dev/null
+++ b/api/migrations/0043_message_maintainers.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.16 on 2018-11-20 11:53
+from __future__ import unicode_literals
+
+from django.db import migrations
+import jsonfield.encoder
+import jsonfield.fields
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('api', '0042_watchedquery'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='message',
+            name='maintainers',
+            field=jsonfield.fields.JSONField(blank=True, default=[], dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={}),
+        ),
+    ]
diff --git a/api/models.py b/api/models.py
index 55b129e..67bf0ea 100644
--- a/api/models.py
+++ b/api/models.py
@@ -490,6 +490,8 @@ class Message(models.Model):
 
     objects = MessageManager()
 
+    maintainers = jsonfield.JSONField(blank=True, default=[])
+
     def save_mbox(self, mbox_blob):
         save_blob(mbox_blob, self.message_id)
 
diff --git a/mods/git.py b/mods/git.py
index a37de57..a4290de 100644
--- a/mods/git.py
+++ b/mods/git.py
@@ -257,11 +257,13 @@ class ApplierReportView(APILoginRequiredView):
     allowed_groups = ["importers"]
 
     def handle(self, request, project, message_id, tag, url, base, repo,
-               failed, log):
+               failed, log, maintainers=[]):
         p = Project.objects.get(name=project)
         r = Message.objects.series_heads().get(project=p,
                                                message_id=message_id).git_result
         r.log = log
+        r.message.maintainers = maintainers
+        r.message.save()
         data = {}
         if failed:
             r.status = Result.FAILURE
diff --git a/patchew-cli b/patchew-cli
index b5d6ecb..154aadf 100755
--- a/patchew-cli
+++ b/patchew-cli
@@ -665,6 +665,20 @@ class ApplyCommand(SubCommand):
                             patch there. Implies --any, conflicts with -C, -b,
                             -B and -t.""")
 
+    def _get_maintainers(self, repo, fname):
+        script = os.path.join(repo, "scripts/get_maintainer.pl")
+        if not os.access(script, os.X_OK):
+            return []
+        try:
+            lines = subprocess.check_output([script, "--noroles", "--norolestats",
+                                           "--nogit", "--nogit-fallback", fname],
+                    cwd=repo).decode('utf-8').splitlines()
+            # Only return entries in the form of "First Last <email at address.com>",
+            # excluding list addresses
+            return [x for x in lines if '<' in x and '>' in x]
+        except:
+            return []
+
     def _apply(self, repo, s, branch, force_branch, tag, logf=None,
                signoff=False):
         msgid = s["message-id"]
@@ -679,15 +693,21 @@ class ApplyCommand(SubCommand):
             bn = bn.replace("%m", msgid)
             subprocess.check_call(["git", "checkout", bo, bn], cwd=repo,
                                   stdout=logf, stderr=logf)
+        maintainers = set()
+        apply_failed = False
         for p in s["patches"]:
             patchf = tempfile.NamedTemporaryFile()
             patchf.write(p["mbox"].encode('utf-8'))
             patchf.flush()
+            maintainers = maintainers.union(self._get_maintainers(repo, patchf.name))
+            if apply_failed:
+                continue
             if 0 != subprocess.call(["git", "am", "-m", "-3", patchf.name],
                                     cwd=repo, stdout=logf, stderr=logf):
                 logf.flush()
                 logf.write("Failed to apply patch:\n%s" % p["subject"])
-                raise ApplyFailedException()
+                apply_failed = True
+                continue
             filter_cmd = ""
             commit_message_lines = \
                     subprocess.check_output(["git", "log", "-n", "1",
@@ -711,10 +731,13 @@ class ApplyCommand(SubCommand):
                 subprocess.check_output(["git", "filter-branch", "-f",
                                          "--msg-filter", "cat; " + filter_cmd,
                                          "HEAD~1.."], cwd=repo)
-        if tag:
+        if apply_failed:
+            raise ApplyFailedException()
+        elif tag:
             subprocess.check_call(["git", "tag", "-f",
                                   tag.replace("%m", msgid)], cwd=repo,
                                   stdout=logf, stderr=logf)
+        return list(maintainers)
 
     def _push(self, repo, remote, tag, logf):
         subprocess.check_call(["git", "remote", "add", "push_to", remote],
@@ -749,7 +772,7 @@ class ApplyCommand(SubCommand):
             base = subprocess.check_output(["git", "rev-parse", "HEAD"],
                                            cwd=wd).decode('utf-8') \
                     .strip()
-            self._apply(wd, toapply, branch, force_branch, tag, logf)
+            maintainers = self._apply(wd, toapply, branch, force_branch, tag, logf)
             if push_repo:
                 self._push(wd, push_repo, tag, logf)
             url = toapply.get("git.url_template", "").replace("%t", tag)
@@ -777,7 +800,7 @@ class ApplyCommand(SubCommand):
                     project=toapply["project"],
                     message_id=toapply["message-id"],
                     tag=tag, url=url, base=base, repo=public_repo,
-                    failed=False, log=log)
+                    failed=False, log=log, maintainers=maintainers)
         return 0
 
     def do(self, args, argv):
-- 
2.17.2




More information about the Patchew-devel mailing list