|
1 # Copyright 2020 Joerg Sonnenberger <joerg@bec.de> |
|
2 # |
|
3 # This software may be used and distributed according to the terms of the |
|
4 # GNU General Public License version 2 or any later version. |
|
5 """changeset_published is a hook to send a mail when an |
|
6 existing draft changeset is moved to the public phase. |
|
7 |
|
8 Correct message threading requires the same messageidseed to be used for both |
|
9 the original notification and the new mail. |
|
10 |
|
11 Usage: |
|
12 [notify] |
|
13 messageidseed = myseed |
|
14 |
|
15 [hooks] |
|
16 txnclose-phase.changeset_published = \ |
|
17 python:hgext.hooklib.changeset_published.hook |
|
18 """ |
|
19 |
|
20 from __future__ import absolute_import |
|
21 |
|
22 import email.errors as emailerrors |
|
23 import email.utils as emailutils |
|
24 |
|
25 from mercurial.i18n import _ |
|
26 from mercurial import ( |
|
27 encoding, |
|
28 error, |
|
29 logcmdutil, |
|
30 mail, |
|
31 pycompat, |
|
32 registrar, |
|
33 ) |
|
34 from mercurial.utils import dateutil |
|
35 from .. import notify |
|
36 |
|
37 configtable = {} |
|
38 configitem = registrar.configitem(configtable) |
|
39 |
|
40 configitem( |
|
41 b'notify_published', b'domain', default=None, |
|
42 ) |
|
43 configitem( |
|
44 b'notify_published', b'messageidseed', default=None, |
|
45 ) |
|
46 configitem( |
|
47 b'notify_published', |
|
48 b'template', |
|
49 default=b'''Subject: changeset published |
|
50 |
|
51 This changeset has been published. |
|
52 ''', |
|
53 ) |
|
54 |
|
55 |
|
56 def _report_commit(ui, repo, ctx): |
|
57 domain = ui.config(b'notify_published', b'domain') or ui.config( |
|
58 b'notify', b'domain' |
|
59 ) |
|
60 messageidseed = ui.config( |
|
61 b'notify_published', b'messageidseed' |
|
62 ) or ui.config(b'notify', b'messageidseed') |
|
63 template = ui.config(b'notify_published', b'template') |
|
64 spec = logcmdutil.templatespec(template, None) |
|
65 templater = logcmdutil.changesettemplater(ui, repo, spec) |
|
66 ui.pushbuffer() |
|
67 n = notify.notifier(ui, repo, b'incoming') |
|
68 |
|
69 subs = set() |
|
70 for sub, spec in n.subs: |
|
71 if spec is None: |
|
72 subs.add(sub) |
|
73 continue |
|
74 revs = repo.revs(b'%r and %d:', spec, ctx.rev()) |
|
75 if len(revs): |
|
76 subs.add(sub) |
|
77 continue |
|
78 if len(subs) == 0: |
|
79 ui.debug( |
|
80 b'notify_published: no subscribers to selected repo and revset\n' |
|
81 ) |
|
82 return |
|
83 |
|
84 templater.show( |
|
85 ctx, |
|
86 changes=ctx.changeset(), |
|
87 baseurl=ui.config(b'web', b'baseurl'), |
|
88 root=repo.root, |
|
89 webroot=n.root, |
|
90 ) |
|
91 data = ui.popbuffer() |
|
92 |
|
93 try: |
|
94 msg = mail.parsebytes(data) |
|
95 except emailerrors.MessageParseError as inst: |
|
96 raise error.Abort(inst) |
|
97 |
|
98 msg['In-reply-to'] = notify.messageid(ctx, domain, messageidseed) |
|
99 msg['Message-Id'] = notify.messageid( |
|
100 ctx, domain, messageidseed + b'-published' |
|
101 ) |
|
102 msg['Date'] = encoding.strfromlocal( |
|
103 dateutil.datestr(format=b"%a, %d %b %Y %H:%M:%S %1%2") |
|
104 ) |
|
105 if not msg['From']: |
|
106 sender = ui.config(b'email', b'from') or ui.username() |
|
107 if b'@' not in sender or b'@localhost' in sender: |
|
108 sender = n.fixmail(sender) |
|
109 msg['From'] = mail.addressencode(ui, sender, n.charsets, n.test) |
|
110 msg['To'] = ', '.join(sorted(subs)) |
|
111 |
|
112 msgtext = msg.as_bytes() if pycompat.ispy3 else msg.as_string() |
|
113 if ui.configbool(b'notify', b'test'): |
|
114 ui.write(msgtext) |
|
115 if not msgtext.endswith(b'\n'): |
|
116 ui.write(b'\n') |
|
117 else: |
|
118 ui.status(_(b'notify_published: sending mail for %d\n') % ctx.rev()) |
|
119 mail.sendmail( |
|
120 ui, emailutils.parseaddr(msg['From'])[1], subs, msgtext, mbox=n.mbox |
|
121 ) |
|
122 |
|
123 |
|
124 def hook(ui, repo, hooktype, node=None, **kwargs): |
|
125 if hooktype != b"txnclose-phase": |
|
126 raise error.Abort( |
|
127 _(b'Unsupported hook type %r') % pycompat.bytestr(hooktype) |
|
128 ) |
|
129 ctx = repo.unfiltered()[node] |
|
130 if kwargs['oldphase'] == b'draft' and kwargs['phase'] == b'public': |
|
131 _report_commit(ui, repo, ctx) |