1
import errno, re, webbrowser
12
from bzrlib.plugins.launchpad import lp_api
14
class NoLaunchpadLib(errors.BzrCommandError):
16
_fmt = "LaunchpadLib must be installed for this operation."
20
from launchpadlib import (
25
raise NoLaunchpadLib()
27
from lazr.restfulclient import errors as restful_errors
30
class Submitter(object):
32
def __init__(self, tree, manager, target_branch, message, reviews,
35
self.manager = manager
37
service_root = launchpad.STAGING_SERVICE_ROOT
39
service_root = launchpad.EDGE_SERVICE_ROOT
40
self.launchpad = lp_api.login(service_root)
41
self.source_branch = lp_api.LaunchpadBranch.from_bzr(
42
self.manager.storage.branch, self.launchpad)
43
if target_branch is None:
44
self.target_branch = self.source_branch.get_dev_focus()
46
self.target_branch = lp_api.LaunchpadBranch.from_bzr(
47
target_branch, self.launchpad)
48
self.commit_message = message
50
target_reviewer = self.target_branch.lp.reviewer
51
if target_reviewer is None:
52
raise errors.BzrCommandError('No reviewer specified')
53
self.reviews = [(target_reviewer, '')]
55
self.reviews = [(self.launchpad.people[reviewer], review_type)
56
for reviewer, review_type in
59
def get_comment(self, prerequisite_branch):
60
info = ["Source: %s\n" % self.source_branch.lp.bzr_identity]
61
info.append("Target: %s\n" % self.target_branch.lp.bzr_identity)
62
if prerequisite_branch is not None:
63
info.append("Prereq: %s\n" % prerequisite_branch.lp.bzr_identity)
64
for rdata in self.reviews:
65
uniquename = "%s (%s)" % (rdata[0].display_name, rdata[0].name)
66
info.append('Reviewer: %s, type "%s"\n' % (uniquename, rdata[1]))
67
self.source_branch.bzr.lock_read()
69
self.target_branch.bzr.lock_read()
71
body = self.try_get_body()
73
self.target_branch.bzr.unlock()
75
self.source_branch.bzr.unlock()
76
initial_comment = msgeditor.edit_commit_message(''.join(info),
78
return initial_comment.strip().encode('utf-8')
80
def try_get_body(self):
82
from bzrlib.plugins.lpreview_body.body_callback import (
88
def list_modified_files():
89
lca_tree = self.source_branch.find_lca_tree(
91
source_tree = self.source_branch.bzr.basis_tree()
92
files = modified_files(lca_tree, source_tree)
94
target_loc = ('bzr+ssh://bazaar.launchpad.net/%s' %
95
self.target_branch.lp.unique_name)
96
return get_body(self.tree, target_loc, list_modified_files, '')
98
def check_submission(self):
99
if self.source_branch.lp.self_link == self.target_branch.lp.self_link:
100
raise errors.BzrCommandError(
101
'Source and target branches must be different.')
102
for mp in self.source_branch.lp.landing_targets:
103
if mp.queue_status in ('Merged', 'Rejected'):
105
if mp.target_branch.self_link == self.target_branch.lp.self_link:
106
raise errors.BzrCommandError(
107
'There is already a branch merge proposal: %s' %
111
prev_pipe = self.manager.get_prev_pipe()
112
if prev_pipe is not None:
113
prerequisite_branch = lp_api.LaunchpadBranch.from_bzr(self.launchpad, prev_pipe)
115
prerequisite_branch = None
116
self.source_branch.update_lp()
117
if prerequisite_branch is not None:
118
prerequisite_branch.update_lp()
119
if prerequisite_branch is None:
122
prereq = prerequisite_branch.lp
125
for reviewer, review_type in self.reviews:
126
review_types.append(review_type)
127
reviewers.append(reviewer.self_link)
128
initial_comment = self.get_comment(prerequisite_branch)
130
mp = self.source_branch.lp.createMergeProposal(
131
target_branch=self.target_branch.lp,
132
prerequisite_branch=prereq, initial_comment=initial_comment,
133
commit_message=self.commit_message, reviewers=reviewers,
134
review_types=review_types)
135
except restful_errors.HTTPError, e:
136
for line in e.content.splitlines():
137
if line.startswith('Traceback (most recent call last):'):
141
webbrowser.open(canonical_url(mp))
143
def canonical_url(object):
144
url = object.self_link.replace('https://api.', 'https://code.')
145
return url.replace('/beta/', '/')