106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
1 |
#! /usr/bin/python3
|
62.1.15
by Robert Collins
Show the most recent comment on merge proposals. |
2 |
# vi: expandtab:sts=4
|
47
by Martin Pool
Start a script to feed pqm from bmps |
3 |
|
4 |
# Copyright (C) 2010 Martin Pool
|
|
5 |
||
6 |
"""Take approved merge proposals and ask pqm to merge them.
|
|
7 |
"""
|
|
8 |
||
9 |
||
10 |
# TODO: comment on an mp
|
|
11 |
#
|
|
12 |
# TODO: open in browser
|
|
13 |
#
|
|
14 |
# TODO: show all comments
|
|
15 |
#
|
|
48
by Martin Pool
Can now set message and send to pqm |
16 |
# TODO: some way to persistently say "not for me" and not be asked again
|
47
by Martin Pool
Start a script to feed pqm from bmps |
17 |
|
18 |
||
62.1.5
by Robert Collins
Allow anyone with LP API access to send to PQM without needing to futz with GPG by adding a cron mode that can run in batch to trigger submission emails. |
19 |
import optparse |
47
by Martin Pool
Start a script to feed pqm from bmps |
20 |
import sys |
21 |
||
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
22 |
from breezy import initialize as breezy_initialize |
23 |
import atexit |
|
24 |
def breezy_setup(): |
|
25 |
"""Call breezy.initialize and register cleanup to be run on exit"""
|
|
26 |
context = breezy_initialize() |
|
27 |
if context is not None: |
|
28 |
atexit.register(context.__enter__().__exit__, None, None, None) |
|
66.1.1
by Martin
Initialize the bzrlib ui so it can prompt for an email password |
29 |
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
30 |
from breezy.email_message import EmailMessage |
31 |
from breezy import ( |
|
101.1.1
by Jelmer Vernooij
Fix compatibility with bzr 2.5. |
32 |
config as _mod_config, |
33 |
gpg, |
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
34 |
version_info as breezy_version, |
101.1.1
by Jelmer Vernooij
Fix compatibility with bzr 2.5. |
35 |
)
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
36 |
from breezy.smtp_connection import SMTPConnection |
47
by Martin Pool
Start a script to feed pqm from bmps |
37 |
|
38 |
import hydrazine |
|
39 |
||
40 |
||
48
by Martin Pool
Can now set message and send to pqm |
41 |
PQM_ADDRESS = 'pqm@bazaar-vcs.org' |
42 |
# PQM_ADDRESS = 'mbp@sourcefrog.net'
|
|
43 |
||
44 |
||
47
by Martin Pool
Start a script to feed pqm from bmps |
45 |
def read_choice(): |
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
46 |
print('What now?', end='') |
47
by Martin Pool
Start a script to feed pqm from bmps |
47 |
return raw_input() |
48 |
||
49 |
||
50 |
def show_help(): |
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
51 |
print("""\ |
47
by Martin Pool
Start a script to feed pqm from bmps |
52 |
feed-pqm looks for approved merge proposals and sends them to pqm.
|
53 |
||
54 |
commands:
|
|
55 |
h help
|
|
48
by Martin Pool
Can now set message and send to pqm |
56 |
m set the proposed commit message for this proposal
|
47
by Martin Pool
Start a script to feed pqm from bmps |
57 |
n skip this, go to the next
|
48
by Martin Pool
Can now set message and send to pqm |
58 |
p previous
|
59 |
q quit
|
|
89
by Jonathan Riddell
remove unused submit option |
60 |
e send in an approved merge via email. Requires GPG and email setup
|
61 |
appropriately in bazaar.conf, and your key in the PQM keyring.
|
|
62 |
||
63 |
Please send feedback to mbp@canonical.com
|
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
64 |
""") |
89
by Jonathan Riddell
remove unused submit option |
65 |
|
66 |
#does not currently do anything useful
|
|
67 |
"""\
|
|
62.1.11
by Robert Collins
Remove --cron mode. |
68 |
s submit approved merges to the queue (PQM reads from the launchpad
|
69 |
queue) for already queued merges this toggles in and out of queued,
|
|
70 |
setting a new queuer and putting it at the back of the queue.
|
|
62.1.12
by Robert Collins
Add back manual email submission via 'e'. |
71 |
Requires membership in the review team for the target branch.
|
47
by Martin Pool
Start a script to feed pqm from bmps |
72 |
"""
|
73 |
||
74 |
def show_datetime(label, dt): |
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
75 |
print(" %12s: %s" % (label, dt) ) |
47
by Martin Pool
Start a script to feed pqm from bmps |
76 |
# TODO: show relative time
|
77 |
# (datetime.datetime.utcnow() - dt).days)
|
|
78 |
||
79 |
||
80 |
def show_mp(mp): |
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
81 |
print(mp.web_link) |
48
by Martin Pool
Can now set message and send to pqm |
82 |
# nb: .url is empty (except on mirrored branches?)
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
83 |
print(' %12s: %s' % ('message', mp.commit_message)) |
84 |
print(' %12s: %s' % ('source', mp.source_branch.bzr_identity)) |
|
85 |
print(' %12s: %s' % ('target', mp.target_branch.bzr_identity)) |
|
91.3.1
by Martin
Display prerequisite branches when showing merge proposals |
86 |
prereq_branch = mp.prerequisite_branch |
87 |
if prereq_branch is not None: |
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
88 |
print(' %12s: %s' % ('prereq', prereq_branch.bzr_identity)) |
89 |
print(' %12s: %s' % ('status', mp.queue_status)) |
|
47
by Martin Pool
Start a script to feed pqm from bmps |
90 |
show_datetime('created', mp.date_created) |
91 |
show_datetime('reviewed', mp.date_reviewed) |
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
92 |
print(' %12s: %s' % ('registrant', mp.registrant.name)) |
47
by Martin Pool
Start a script to feed pqm from bmps |
93 |
for vote in mp.votes_collection: |
48
by Martin Pool
Can now set message and send to pqm |
94 |
# XXX: would like to show the date but see bug 530475
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
95 |
print(" %12s: %30s %-12s" % ('vote', vote.reviewer.name, |
51
by Martin Pool
Cope nicely with mps that still have some merge requests |
96 |
(vote.comment and vote.comment.vote or 'Requested'), |
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
97 |
))
|
62.1.15
by Robert Collins
Show the most recent comment on merge proposals. |
98 |
# The last comment is usually enough to get a sense for things. Change if
|
99 |
# desired.
|
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
100 |
print("Recent comments:") |
62.1.16
by Robert Collins
Some comments about the code. |
101 |
comments = list(mp.all_comments) #XXX: See bug lp:583761 |
62.1.15
by Robert Collins
Show the most recent comment on merge proposals. |
102 |
for comment in comments[-1:]: |
77.2.1
by John Arbash Meinel
Work around bug #612641 by encoding to ascii if necessary. |
103 |
val = "%s: %s" % (comment.author.name, comment.message_body) |
104 |
try: |
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
105 |
print(val) |
77.2.1
by John Arbash Meinel
Work around bug #612641 by encoding to ascii if necessary. |
106 |
except UnicodeError: |
107 |
val = val.encode('ascii', 'replace') |
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
108 |
print(val) |
47
by Martin Pool
Start a script to feed pqm from bmps |
109 |
|
110 |
||
48
by Martin Pool
Can now set message and send to pqm |
111 |
def set_message(mp): |
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
112 |
print("old commit message: %s" % (mp.commit_message,)) |
113 |
print("new message> ", end='') |
|
88
by Martin
Require commit messages to be at least two characters long |
114 |
message = raw_input() |
115 |
if len(message) < 2: |
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
116 |
print("Too short to be a commit message?") |
88
by Martin
Require commit messages to be at least two characters long |
117 |
return
|
118 |
mp.commit_message = message |
|
48
by Martin Pool
Can now set message and send to pqm |
119 |
mp.lp_save() |
120 |
||
121 |
||
62.1.5
by Robert Collins
Allow anyone with LP API access to send to PQM without needing to futz with GPG by adding a cron mode that can run in batch to trigger submission emails. |
122 |
def queue_mp(launchpad, mp): |
48
by Martin Pool
Can now set message and send to pqm |
123 |
if not mp.commit_message: |
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
124 |
print("No message set? Use 'm'.") |
48
by Martin Pool
Can now set message and send to pqm |
125 |
return
|
62.1.5
by Robert Collins
Allow anyone with LP API access to send to PQM without needing to futz with GPG by adding a cron mode that can run in batch to trigger submission emails. |
126 |
if mp.queue_status == 'Queued': |
127 |
mp.setStatus(status='Approved') |
|
62.1.8
by Robert Collins
Set queued revision id when queuing. |
128 |
mp.setStatus(status='Queued', revid=mp.reviewed_revid) |
62.1.5
by Robert Collins
Allow anyone with LP API access to send to PQM without needing to futz with GPG by adding a cron mode that can run in batch to trigger submission emails. |
129 |
|
62.1.12
by Robert Collins
Add back manual email submission via 'e'. |
130 |
|
62.1.5
by Robert Collins
Allow anyone with LP API access to send to PQM without needing to futz with GPG by adding a cron mode that can run in batch to trigger submission emails. |
131 |
def send_mp(launchpad, mp, send_mail=True): |
132 |
if not mp.commit_message: |
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
133 |
print("No message set - %s queued badly? Set a message first." % mp) |
62.1.12
by Robert Collins
Add back manual email submission via 'e'. |
134 |
return False |
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
135 |
print("merge command to be signed:") |
59
by Martin Pool
Try to make mail subject match the one used by Launchpad |
136 |
raw_message = ( |
137 |
"star-merge %s %s\n" |
|
138 |
% (mp.source_branch.composePublicURL(scheme='http'), |
|
139 |
mp.target_branch.composePublicURL(scheme='http'))) |
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
140 |
print(raw_message) |
59
by Martin Pool
Try to make mail subject match the one used by Launchpad |
141 |
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
142 |
config = _mod_config.GlobalStack() |
143 |
my_email = config.get('email') |
|
144 |
print("Will send email from address <%s>" % (my_email,)) |
|
62.1.5
by Robert Collins
Allow anyone with LP API access to send to PQM without needing to futz with GPG by adding a cron mode that can run in batch to trigger submission emails. |
145 |
signer = gpg.GPGStrategy(config) |
146 |
signed_message = signer.sign(raw_message.encode('utf8')) |
|
62.1.6
by Robert Collins
Include the queuer as a prefix and the branch owner as a suffix on commit messages, to automate current practice. |
147 |
# TODO: put in bug numbers as well.
|
62.1.12
by Robert Collins
Add back manual email submission via 'e'. |
148 |
commit_message = u"(%s) %s (%s)" % (launchpad.me.name, mp.commit_message, |
62.1.7
by Robert Collins
Save the tabs, save the world. |
149 |
mp.source_branch.owner.display_name) |
62.1.12
by Robert Collins
Add back manual email submission via 'e'. |
150 |
message = EmailMessage(my_email, PQM_ADDRESS, commit_message, |
52.2.1
by Jelmer Vernooij
Use bzrlib's email message API to send messages off to PQM. |
151 |
signed_message) |
62.1.5
by Robert Collins
Allow anyone with LP API access to send to PQM without needing to futz with GPG by adding a cron mode that can run in batch to trigger submission emails. |
152 |
if send_mail: |
153 |
SMTPConnection(config).send_email(message) |
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
154 |
print("Sent!") |
62.1.5
by Robert Collins
Allow anyone with LP API access to send to PQM without needing to futz with GPG by adding a cron mode that can run in batch to trigger submission emails. |
155 |
else: |
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
156 |
print("Not sending email - disabled.") |
62.1.5
by Robert Collins
Allow anyone with LP API access to send to PQM without needing to futz with GPG by adding a cron mode that can run in batch to trigger submission emails. |
157 |
|
158 |
# suggested subject should match the last comment on the mp so that gmail
|
|
159 |
# doesn't see it as a separate thread;
|
|
160 |
# <https://bugs.edge.launchpad.net/hydrazine/+bug/541586>
|
|
161 |
subject = "Re: [Merge] %s into %s" % (mp.source_branch.bzr_identity, |
|
62.1.7
by Robert Collins
Save the tabs, save the world. |
162 |
mp.target_branch.bzr_identity) |
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
163 |
print("Recording that the proposal is submitted to PQM.") |
64
by Martin Pool
Add back email support |
164 |
fed_pqm = "sent to pqm by email\n" |
62.1.5
by Robert Collins
Allow anyone with LP API access to send to PQM without needing to futz with GPG by adding a cron mode that can run in batch to trigger submission emails. |
165 |
mp.createComment(content=fed_pqm, subject=subject) |
62.1.12
by Robert Collins
Add back manual email submission via 'e'. |
166 |
return True |
50
by Martin Pool
Post a comment when fed to pqm |
167 |
|
47
by Martin Pool
Start a script to feed pqm from bmps |
168 |
|
91.3.2
by Martin
Add iter_merge_proposals and include logic to hide approved mps with unmerged prerequisites |
169 |
def iter_mergable_proposals(project, include_queued=False): |
170 |
"""Iterate over merge proposals for `project` that are ready to be landed
|
|
171 |
||
172 |
If `show_queued` is set, proposals using launchpad queue tracking which
|
|
173 |
are already due to be landed are also shown. This doesn't matter for merge
|
|
174 |
commands sent by email instead.
|
|
175 |
||
176 |
Proposals that have unmerged prerequiste branches will not be offered for
|
|
177 |
merging to prevent accidentally landing unreviewed code.
|
|
178 |
"""
|
|
179 |
find_status = ['Approved'] |
|
180 |
if include_queued: |
|
181 |
find_status.append('Queued') |
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
182 |
print('Looking for %r mps in %s' % (find_status, project)) |
91.3.2
by Martin
Add iter_merge_proposals and include logic to hide approved mps with unmerged prerequisites |
183 |
for mp in project.getMergeProposals(status=find_status): |
184 |
prereq = mp.prerequisite_branch |
|
185 |
if not prereq or prereq.lifecycle_status == 'Merged': |
|
186 |
yield mp |
|
187 |
||
188 |
||
47
by Martin Pool
Start a script to feed pqm from bmps |
189 |
def main(argv): |
70.1.1
by John Arbash Meinel
Properly handle argument parsing. |
190 |
parser = optparse.OptionParser('%prog [options] PROJECT\n\n' |
191 |
' PROJECT is the launchpad project to inspect (eg bzr)') |
|
62.1.5
by Robert Collins
Allow anyone with LP API access to send to PQM without needing to futz with GPG by adding a cron mode that can run in batch to trigger submission emails. |
192 |
parser.add_option('--nomail', help="Do not send email commands", action="store_true", default=False) |
193 |
parser.add_option('--queued', help="Examine already queued proposals", action="store_true", default=False) |
|
194 |
opts, args = parser.parse_args() |
|
70.1.1
by John Arbash Meinel
Properly handle argument parsing. |
195 |
if len(args) != 1: |
196 |
parser.print_usage() |
|
197 |
return 1 |
|
198 |
project = args[0] |
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
199 |
breezy_setup() |
47
by Martin Pool
Start a script to feed pqm from bmps |
200 |
launchpad = hydrazine.create_session() |
70.1.1
by John Arbash Meinel
Properly handle argument parsing. |
201 |
project = launchpad.projects[project] |
48
by Martin Pool
Can now set message and send to pqm |
202 |
i = 0 |
91.3.2
by Martin
Add iter_merge_proposals and include logic to hide approved mps with unmerged prerequisites |
203 |
all_mps = list(iter_mergable_proposals(project, |
204 |
include_queued=opts.queued)) |
|
62.1.9
by Robert Collins
After sending merge proposals, remove them from the queue if they would not have been found originally. |
205 |
while len(all_mps): |
48
by Martin Pool
Can now set message and send to pqm |
206 |
mp = all_mps[i] |
207 |
show_mp(mp) |
|
208 |
||
209 |
while True: |
|
210 |
whatnow = read_choice() |
|
211 |
if whatnow == 'q': |
|
62.1.10
by Robert Collins
Handle submitting the last pending proposal. |
212 |
return 0 |
48
by Martin Pool
Can now set message and send to pqm |
213 |
elif whatnow in ('h', 'help', '?'): |
214 |
show_help() |
|
215 |
elif whatnow == 'n': |
|
216 |
i = (i + 1) % len(all_mps) |
|
217 |
break
|
|
218 |
elif whatnow == 'p': |
|
219 |
i -= 1 |
|
220 |
if i < 0: |
|
221 |
i = len(all_mps) - 1 |
|
222 |
break
|
|
223 |
elif whatnow == 'm': |
|
224 |
set_message(mp) |
|
225 |
elif whatnow == 's': |
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
226 |
print("Sorry, not currently implemented %r" % whatnow) |
89
by Jonathan Riddell
remove unused submit option |
227 |
"""
|
62.1.5
by Robert Collins
Allow anyone with LP API access to send to PQM without needing to futz with GPG by adding a cron mode that can run in batch to trigger submission emails. |
228 |
queue_mp(launchpad, mp)
|
62.1.9
by Robert Collins
After sending merge proposals, remove them from the queue if they would not have been found originally. |
229 |
if mp.queue_status not in find_status:
|
230 |
del all_mps[i]
|
|
231 |
if i == len(all_mps):
|
|
232 |
i -= 1
|
|
62.1.10
by Robert Collins
Handle submitting the last pending proposal. |
233 |
break
|
89
by Jonathan Riddell
remove unused submit option |
234 |
"""
|
62.1.12
by Robert Collins
Add back manual email submission via 'e'. |
235 |
elif whatnow == 'e': |
64
by Martin Pool
Add back email support |
236 |
if send_mp(launchpad, mp, send_mail=not opts.nomail): |
62.1.12
by Robert Collins
Add back manual email submission via 'e'. |
237 |
del all_mps[i] |
238 |
if i == len(all_mps): |
|
239 |
i -= 1 |
|
240 |
break
|
|
48
by Martin Pool
Can now set message and send to pqm |
241 |
elif whatnow == '': |
242 |
continue
|
|
243 |
else: |
|
106.1.1
by Jelmer Vernooij
Initial work on port to Python 3. |
244 |
print("Sorry, don't understand %r" % whatnow) |
245 |
print("No remaining merge proposals ready to be merged.") |
|
99.1.1
by Martin Packman
Don't refer to find_status when there are no pending mps |
246 |
return 0 |
47
by Martin Pool
Start a script to feed pqm from bmps |
247 |
|
248 |
if __name__ == '__main__': |
|
249 |
sys.exit(main(sys.argv)) |