vkaba...@redhat.com writes: > From: Veronika Kabatova <vkaba...@redhat.com> > > Sometimes, multiple projects reside at the same mailing list. So far, > Patchwork only allowed a single project per mailing list, which made it > impossible for these projects to use Patchwork (unless they did some > dirty hacks). > > Add a new property `subject_match` to projects and implement filtering > on (list_id, subject_match) match instead of solely list_id. Instance > admin can specify a regex on a per-project basis when the project is > created.
(I haven't thought a great deal about this, so don't take this as a nack) Two general thoughts: - netdev has several projects sharing a mailing list and they seem to get along fine... - I am pretty sure Snowpatch deals with this somehow - Snowpatch does CI on patchwork, so they need to know what project is used. Andrew, Russell - how do you deal with this there? I suppose to put a finer point on it - what is your usecase here? What are you trying to achieve, and can we help you do that in a way that requires smaller changes to Patchwork, and is less fragile? (For example this is going to break if someone mis-spells the keyword you're looking for in the subject_match.) Regards, Daniel > > Signed-off-by: Veronika Kabatova <vkaba...@redhat.com> > --- > docs/api.yaml | 3 +++ > docs/deployment/management.rst | 4 +-- > patchwork/api/project.py | 5 ++-- > .../0021_add_subject_match_to_project.py | 29 > ++++++++++++++++++++++ > patchwork/models.py | 9 ++++++- > patchwork/parser.py | 19 +++++++++++++- > .../notes/list-filtering-4643d98b4064367a.yaml | 10 ++++++++ > 7 files changed, 73 insertions(+), 6 deletions(-) > create mode 100644 patchwork/migrations/0021_add_subject_match_to_project.py > create mode 100644 releasenotes/notes/list-filtering-4643d98b4064367a.yaml > > diff --git a/docs/api.yaml b/docs/api.yaml > index 3e79f0b..3373226 100644 > --- a/docs/api.yaml > +++ b/docs/api.yaml > @@ -374,6 +374,9 @@ definitions: > list_id: > type: string > description: Mailing list identifier for project. > + subject_match: > + type: string > + description: Regex used for email filtering. > list_email: > type: string > description: Mailing list email address for project. > diff --git a/docs/deployment/management.rst b/docs/deployment/management.rst > index c50b7b6..870d7ee 100644 > --- a/docs/deployment/management.rst > +++ b/docs/deployment/management.rst > @@ -63,7 +63,7 @@ due to, for example, an outage. > .. option:: --list-id <list-id> > > mailing list ID. If not supplied, this will be extracted from the mail > - headers. > + headers. Don't use this option if you require filtering based on subjects. > > .. option:: infile > > @@ -88,7 +88,7 @@ the :ref:`deployment installation guide > <deployment-parsemail>`. > .. option:: --list-id <list-id> > > mailing list ID. If not supplied, this will be extracted from the mail > - headers. > + headers. Don't use this option if you require filtering based on subjects. > > .. option:: infile > > diff --git a/patchwork/api/project.py b/patchwork/api/project.py > index 446c473..597f605 100644 > --- a/patchwork/api/project.py > +++ b/patchwork/api/project.py > @@ -39,8 +39,9 @@ class ProjectSerializer(HyperlinkedModelSerializer): > class Meta: > model = Project > fields = ('id', 'url', 'name', 'link_name', 'list_id', 'list_email', > - 'web_url', 'scm_url', 'webscm_url', 'maintainers') > - read_only_fields = ('name', 'maintainers') > + 'web_url', 'scm_url', 'webscm_url', 'maintainers', > + 'subject_match') > + read_only_fields = ('name', 'maintainers', 'subject_match') > extra_kwargs = { > 'url': {'view_name': 'api-project-detail'}, > } > diff --git a/patchwork/migrations/0021_add_subject_match_to_project.py > b/patchwork/migrations/0021_add_subject_match_to_project.py > new file mode 100644 > index 0000000..6066266 > --- /dev/null > +++ b/patchwork/migrations/0021_add_subject_match_to_project.py > @@ -0,0 +1,29 @@ > +# -*- coding: utf-8 -*- > +# Generated by Django 1.10.8 on 2018-01-19 18:16 > +from __future__ import unicode_literals > + > +from django.db import migrations, models > + > + > +class Migration(migrations.Migration): > + > + dependencies = [ > + ('patchwork', '0020_tag_show_column'), > + ] > + > + operations = [ > + migrations.AddField( > + model_name='project', > + name='subject_match', > + field=models.CharField(blank=True, default=b'', > help_text=b'Regex to match the subject against if only part of emails sent to > the list belongs to this project. Will be used with IGNORECASE and MULTILINE > flags. If rules for more projects match the first one returned from DB is > chosen.', max_length=64), > + ), > + migrations.AlterField( > + model_name='project', > + name='listid', > + field=models.CharField(max_length=255), > + ), > + migrations.AlterUniqueTogether( > + name='project', > + unique_together=set([('listid', 'subject_match')]), > + ), > + ] > diff --git a/patchwork/models.py b/patchwork/models.py > index 11886f1..907707f 100644 > --- a/patchwork/models.py > +++ b/patchwork/models.py > @@ -71,8 +71,14 @@ class Project(models.Model): > > linkname = models.CharField(max_length=255, unique=True) > name = models.CharField(max_length=255, unique=True) > - listid = models.CharField(max_length=255, unique=True) > + listid = models.CharField(max_length=255) > listemail = models.CharField(max_length=200) > + subject_match = models.CharField( > + max_length=64, blank=True, default='', help_text='Regex to match the > ' > + 'subject against if only part of emails sent to the list belongs to ' > + 'this project. Will be used with IGNORECASE and MULTILINE flags. If ' > + 'rules for more projects match the first one returned from DB is ' > + 'chosen.') > > # url metadata > > @@ -100,6 +106,7 @@ class Project(models.Model): > return self.name > > class Meta: > + unique_together = (('listid', 'subject_match'),) > ordering = ['linkname'] > > > diff --git a/patchwork/parser.py b/patchwork/parser.py > index ac7dc5f..015f709 100644 > --- a/patchwork/parser.py > +++ b/patchwork/parser.py > @@ -157,9 +157,25 @@ def find_project_by_id(list_id): > project = Project.objects.get(listid=list_id) > except Project.DoesNotExist: > logger.debug("'%s' if not a valid project list-id", list_id) > + except Project.MultipleObjectsReturned: > + logger.debug("Multiple projects with list-id '%s' found", list_id) > return project > > > +def find_project_by_id_and_subject(list_id, subject): > + """Find a `project` object based on `list_id` and subject prefix > match.""" > + projects = Project.objects.filter(listid=list_id) > + for project in projects: > + if (not project.subject_match or > + re.search(project.subject_match, subject, > + re.MULTILINE | re.IGNORECASE)): > + return project > + > + logger.debug("No project to match email with list-id '%s', subject '%s' " > + "found", list_id, subject) > + return None > + > + > def find_project_by_header(mail): > project = None > listid_res = [re.compile(r'.*<([^>]+)>.*', re.S), > @@ -181,7 +197,8 @@ def find_project_by_header(mail): > > listid = match.group(1) > > - project = find_project_by_id(listid) > + project = find_project_by_id_and_subject(listid, > + mail.get('Subject')) > if project: > break > > diff --git a/releasenotes/notes/list-filtering-4643d98b4064367a.yaml > b/releasenotes/notes/list-filtering-4643d98b4064367a.yaml > new file mode 100644 > index 0000000..21c1680 > --- /dev/null > +++ b/releasenotes/notes/list-filtering-4643d98b4064367a.yaml > @@ -0,0 +1,10 @@ > +--- > +features: > + - | > + Allow list filtering into multiple projects (and email dropping) based on > + subject prefixes. Disabled by default, enable by specifying a regular > + expression which needs to be matched in the subject on a per-project > basis > + (field `subject_match`). > +api: > + - | > + Expose `subject_match` in REST API. > -- > 2.13.6 > > _______________________________________________ > Patchwork mailing list > Patchwork@lists.ozlabs.org > https://lists.ozlabs.org/listinfo/patchwork _______________________________________________ Patchwork mailing list Patchwork@lists.ozlabs.org https://lists.ozlabs.org/listinfo/patchwork