git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 1/3] git-multimail: Add an option to filter on branches

From
Dave Boutcher <daveboutcher@gmail.com>
Date
Apr 21, 2015, 23:04 UTC
Message-ID
<1429657487-10809-1-git-send-email-daveboutcher@gmail.com>

Add a branches option to the config. Only changes pushed to specified branches will generate emails. Changes to tags will continue to generate emails.

Signed-off-by: Dave Boutcher <daveboutcher@gmail.com>
---
 git-multimail/README           |  7 +++++++
 git-multimail/git_multimail.py | 44 ++++++++++++++++++++++++++++++++++--------
 2 files changed, 43 insertions(+), 8 deletions(-)
diff --git a/git-multimail/README b/git-multimail/README
index 51add52..a40847a 100644
--- a/git-multimail/README
+++ b/git-multimail/README
@@ -170,6 +170,13 @@ multimailhook.repoName
     for gitolite repositories, or otherwise to derive this value from
     the repository path name.
 
+multimailhook.branches
+
+    A comma separated list of branches to monitor. If not set,
+    notifications will be sent for updates to any branch.  Branch
+    names can contain regular expressions, and this configuration
+    option can be multivalued.
+
 multimailhook.mailingList
 
     The list of email addresses to which notification emails should be
diff --git a/git-multimail/git_multimail.py b/git-multimail/git_multimail.py
index 4374907..5ed253f 100755
--- a/git-multimail/git_multimail.py
+++ b/git-multimail/git_multimail.py
@@ -1548,6 +1548,12 @@ class Environment(object):
             get_reply_to_commit() is used for individual commit
             emails.
 
+        get_branches()
+
+            Return a list of branches to be handled as a list of regex
+            patterns.  If empty list, all branches are handled.  Branches
+            can contain regular expressions (such as foo/.*)
+
     They should also define the following attributes:
 
         announce_show_shortlog (bool)
@@ -1619,6 +1625,9 @@ class Environment(object):
     def get_pusher_email(self):
         return None
 
+    def get_branches(self):
+        return []
+
     def get_administrator(self):
         return 'the administrator of this repository'
 
@@ -1809,6 +1818,10 @@ class ConfigOptionsEnvironmentMixin(ConfigEnvironmentMixin):
             else:
                 return self.get_sender()
 
+    def get_branches(self):
+        branches = self.config.get_all('branches',[])
+        return [re.compile('refs/heads/'+b.strip()) for bs in branches for b in bs.split(',')]
+
     def get_reply_to_refchange(self, refchange):
         if self.__reply_to_refchange is None:
             return super(ConfigOptionsEnvironmentMixin, self).get_reply_to_refchange(refchange)
@@ -2220,8 +2233,9 @@ class Push(object):
             ])
         )
 
-    def __init__(self, changes):
+    def __init__(self, changes, environment):
         self.changes = sorted(changes, key=self._sort_key)
+        self.environment = environment
 
         # The SHA-1s of commits referred to by references unaffected
         # by this push:
@@ -2246,6 +2260,12 @@ class Push(object):
     def _sort_key(klass, change):
         return (klass.SORT_ORDER[change.__class__, change.change_type], change.refname,)
 
+    def branches_match(self, branch):
+        branches = self.environment.get_branches()
+        if not branches:
+            return [True]
+        return [x for x in [r.match(branch) for r in branches] if x]
+
     def _compute_other_ref_sha1s(self):
         """Return the GitObjects referred to by references unaffected by this push."""
 
@@ -2264,6 +2284,10 @@ class Push(object):
             )
         for line in read_git_lines(['for-each-ref', '--format=%s' % (fmt,)]):
             (sha1, type, name) = line.split(' ', 2)
+            # If we are using a branch filter, skip other branches
+            if type == 'commit' and not self.branches_match(name):
+                continue
+
             if sha1 and type == 'commit' and name not in updated_refs:
                 sha1s.add(sha1)
 
@@ -2334,6 +2358,16 @@ class Push(object):
         unhandled_sha1s = set(self.get_new_commits())
         send_date = IncrementalDateTime()
         for change in self.changes:
+            sha1s = []
+            for sha1 in reversed(list(self.get_new_commits(change))):
+                if sha1 in unhandled_sha1s:
+                    sha1s.append(sha1)
+                    unhandled_sha1s.remove(sha1)
+
+            # if we are filtering on branches, skip branches we don't care about
+            if change.refname_type == 'branch' and not self.branches_match(change.refname):
+                continue
+
             # Check if we've got anyone to send to
             if not change.recipients:
                 sys.stderr.write(
@@ -2349,12 +2383,6 @@ class Push(object):
                     change.recipients,
                     )
 
-            sha1s = []
-            for sha1 in reversed(list(self.get_new_commits(change))):
-                if sha1 in unhandled_sha1s:
-                    sha1s.append(sha1)
-                    unhandled_sha1s.remove(sha1)
-
             max_emails = change.environment.maxcommitemails
             if max_emails and len(sha1s) > max_emails:
                 sys.stderr.write(
@@ -2389,7 +2417,7 @@ def run_as_post_receive_hook(environment, mailer):
         changes.append(
             ReferenceChange.create(environment, oldrev, newrev, refname)
             )
-    push = Push(changes)
+    push = Push(changes, environment)
     push.send_emails(mailer, body_filter=environment.filter_body)
 
 
-- 
2.3.0
Next: Dave Boutcher
Message 1 of 7 in “git-multimail: Add an option to filter on branches”
  1. 1/3 git-multimail: Add an option to filter on branchesDave Boutcher, Apr 21, 2015
  2. 2/3 git-multimail: Add a quiet option to prevent outputting email addresses from hookDave Boutcher, Apr 21, 2015
  3. 3/3 git-multimail: Add stdout option to configDave Boutcher, Apr 21, 2015
  4. Michael HaggertyApr 22, 2015
  5. Dave BoutcherApr 22, 2015
  6. Michael HaggertyApr 22, 2015
  7. Dave BoutcherApr 23, 2015

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.