~ursinha/lp-qa-tools/bzr-tarmacland

39 by John Arbash Meinel
Update copyright and version information.
1
# Copyright (C) 2005, 2006, 2007 by Canonical Ltd
24 by John Arbash Meinel
Add GPL copyright
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
2 by John Arbash Meinel
Adding basic work for a test suite.
16
"""Submit an email to a Patch Queue Manager"""
17
18.2.1 by Aaron Bentley
Better diagnostics when out-of-sync
18
from bzrlib import (
37.1.3 by James Henstridge
Try and share more configuration from merge directive code:
19
    config as _mod_config,
18.2.1 by Aaron Bentley
Better diagnostics when out-of-sync
20
    errors,
37.1.3 by James Henstridge
Try and share more configuration from merge directive code:
21
    gpg,
22
    osutils,
23
    urlutils,
18.2.1 by Aaron Bentley
Better diagnostics when out-of-sync
24
    )
11 by John Arbash Meinel
[patch] Aaron Bentley: Check the public branch has the expected revision.
25
from bzrlib.branch import Branch
37.1.2 by James Henstridge
Kill the custom smtplib code, and use bzr's email+smtp infrastructure.
26
from bzrlib.email_message import EmailMessage
27
from bzrlib.smtp_connection import SMTPConnection
37.1.3 by James Henstridge
Try and share more configuration from merge directive code:
28
from bzrlib.trace import note, warning
2 by John Arbash Meinel
Adding basic work for a test suite.
29
30
34 by Robert Collins
Fix the test_suite method to actually return the correct tests and add a test for commit messages with newlines, fixing bug #110137. (Robert Collins)
31
class BadCommitMessage(errors.BzrError):
39 by John Arbash Meinel
Update copyright and version information.
32
34 by Robert Collins
Fix the test_suite method to actually return the correct tests and add a test for commit messages with newlines, fixing bug #110137. (Robert Collins)
33
    _fmt = "The commit message %(msg)r cannot be used by pqm."
34
35
    def __init__(self, message):
36
        errors.BzrError.__init__(self)
37
        self.msg = message
38
39
37.1.4 by James Henstridge
* Move the PQM submission logic into a PQMSubmission object.
40
class PQMSubmission(object):
41
    """A request to perform a PQM merge into a branch."""
42
37.1.5 by James Henstridge
Simplify PQMSubmission object, fixing up locations in the constructor.
43
    def __init__(self, source_branch, public_location=None,
44
                 submit_location=None, message=None):
37.1.4 by James Henstridge
* Move the PQM submission logic into a PQMSubmission object.
45
        """Create a PQMSubmission object.
46
47
        :param source_branch: the source branch for the merge
37.1.5 by James Henstridge
Simplify PQMSubmission object, fixing up locations in the constructor.
48
        :param public_location: the public location of the source branch
49
        :param submit_location: the location of the target branch
37.1.4 by James Henstridge
* Move the PQM submission logic into a PQMSubmission object.
50
        :param message: The message to use when committing this merge
37.1.5 by James Henstridge
Simplify PQMSubmission object, fixing up locations in the constructor.
51
52
        If any of public_location, submit_location or message are
53
        omitted, they will be calculated from source_branch.
37.1.4 by James Henstridge
* Move the PQM submission logic into a PQMSubmission object.
54
        """
37.1.5 by James Henstridge
Simplify PQMSubmission object, fixing up locations in the constructor.
55
        if source_branch is None:
56
            raise errors.NoMergeSource()
37.1.4 by James Henstridge
* Move the PQM submission logic into a PQMSubmission object.
57
        self.source_branch = source_branch
37.1.5 by James Henstridge
Simplify PQMSubmission object, fixing up locations in the constructor.
58
59
        if public_location is None:
60
            public_location = self.source_branch.get_public_branch()
61
            # Fall back to the old public_repository hack.
62
            if public_location is None:
63
                src_loc = source_branch.bzrdir.root_transport.local_abspath('.')
64
                repository = source_branch.repository
65
                repo_loc = repository.bzrdir.root_transport.local_abspath('.')
66
                repo_config = _mod_config.LocationConfig(repo_loc)
67
                public_repo = repo_config.get_user_option("public_repository")
68
                if public_repo is not None:
69
                    warning("Please use public_branch, not public_repository, "
70
                            "to set the public location of branches.")
71
                    branch_relpath = osutils.relpath(repo_loc, src_loc)
72
                    public_location = urlutils.join(public_repo, branch_relpath)
73
74
            if public_location is None:
75
                raise errors.BzrCommandError(
76
                    'No public branch location given.  Please specify with '
77
                    '--public-location or see "bzr help pqm-submit" to see how '
78
                    'to set it in ~/.bazaar/locations.conf')
79
        self.public_location = public_location
80
81
        if submit_location is None:
82
            config = self.source_branch.get_config()
83
            # First check the deprecated pqm_branch config key:
84
            submit_location = config.get_user_option('pqm_branch')
85
            if submit_location is not None:
86
                warning("Please use submit_branch, not pqm_branch to set "
87
                        "the PQM merge target branch.")
88
            else:
89
                # Otherwise, use the standard config key:
90
                submit_location = self.source_branch.get_submit_branch()
91
92
            if submit_location is None:
93
                raise errors.NoSubmitBranch(self.source_branch)
94
        self.submit_location = submit_location
37.1.4 by James Henstridge
* Move the PQM submission logic into a PQMSubmission object.
95
96
        # Check that the message is okay to pass to PQM
97
        if message is None:
98
            repository = self.source_branch.repository
99
            rev = repository.get_revision(self.source_branch.last_revision())
100
            message = rev.message
101
        self.message = message.encode('utf8')
102
        if '\n' in self.message:
103
            raise BadCommitMessage(self.message)
104
105
    def check_public_branch(self):
106
        """Check that the public branch is up to date with the local copy."""
107
        note('Checking that the public branch is up to date ...')
108
        local_revision = self.source_branch.last_revision()
37.1.5 by James Henstridge
Simplify PQMSubmission object, fixing up locations in the constructor.
109
        public_revision = Branch.open(self.public_location).last_revision()
37.1.4 by James Henstridge
* Move the PQM submission logic into a PQMSubmission object.
110
        if local_revision != public_revision:
111
            raise errors.PublicBranchOutOfDate(
37.1.5 by James Henstridge
Simplify PQMSubmission object, fixing up locations in the constructor.
112
                self.public_location, local_revision)
37.1.4 by James Henstridge
* Move the PQM submission logic into a PQMSubmission object.
113
114
    def to_lines(self):
115
        """Serialise as a list of lines."""
37.1.5 by James Henstridge
Simplify PQMSubmission object, fixing up locations in the constructor.
116
        return ['star-merge %s %s\n' % (self.public_location, self.submit_location)]
37.1.4 by James Henstridge
* Move the PQM submission logic into a PQMSubmission object.
117
118
    def to_signed(self):
119
        """Serialize as a signed string."""
120
        unsigned_text = ''.join(self.to_lines())
121
        unsigned_text = unsigned_text.encode('ascii') #URLs should be ascii
122
123
        strategy = gpg.GPGStrategy(self.source_branch.get_config())
124
        return strategy.sign(unsigned_text)
125
126
    def to_email(self, mail_from, mail_to, sign=True):
127
        """Serialize as an email message.
128
129
        :param mail_from: The from address for the message
130
        :param mail_to: The address to send the message to
131
        :param sign: If True, gpg-sign the email
132
        :return: an email message
133
        """
134
        if sign:
135
            body = self.to_signed()
136
        else:
137
            body = ''.join(self.to_lines())
138
        message = EmailMessage(mail_from, mail_to, self.message, body)
139
        return message
37.1.3 by James Henstridge
Try and share more configuration from merge directive code:
140
141
13 by John Arbash Meinel
Adding a --public-location which lets you force the public location for the pqm.
142
def submit(branch, message, dry_run=False, public_location=None):
2 by John Arbash Meinel
Adding basic work for a test suite.
143
    """Submit the given branch to the pqm."""
19 by John Arbash Meinel
[null-merge] ignore 0.8 compatibility updates
144
    config = branch.get_config()
2 by John Arbash Meinel
Adding basic work for a test suite.
145
37.1.4 by James Henstridge
* Move the PQM submission logic into a PQMSubmission object.
146
    submission = PQMSubmission(
37.1.5 by James Henstridge
Simplify PQMSubmission object, fixing up locations in the constructor.
147
        source_branch=branch, public_location=public_location, message=message)
3 by John Arbash Meinel
Everything is hooked up.
148
37.1.4 by James Henstridge
* Move the PQM submission logic into a PQMSubmission object.
149
    mail_from = config.get_user_option('pqm_user_email')
150
    if not mail_from:
151
        mail_from = config.username()
152
    mail_from = mail_from.encode('utf8') # Make sure this isn't unicode
153
    mail_to = config.get_user_option('pqm_email')
154
    if not mail_to:
32 by John Arbash Meinel
Use 'errors.BzrCommandError'
155
        raise errors.BzrCommandError('No PQM submission address specified '
156
                                     'in configuration')
37.1.4 by James Henstridge
* Move the PQM submission logic into a PQMSubmission object.
157
    mail_to = mail_to.encode('utf8') # same here
158
159
    submission.check_public_branch()
160
161
    message = submission.to_email(mail_from, mail_to)
3 by John Arbash Meinel
Everything is hooked up.
162
10 by John Arbash Meinel
[patch] Aaron Bentley: add --dry-run
163
    if dry_run:
37.1.4 by James Henstridge
* Move the PQM submission logic into a PQMSubmission object.
164
        print message.as_string()
37.1.2 by James Henstridge
Kill the custom smtplib code, and use bzr's email+smtp infrastructure.
165
        return
166
37.1.4 by James Henstridge
* Move the PQM submission logic into a PQMSubmission object.
167
    SMTPConnection(config).send_email(message)