/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
1
# Copyright (C) 2018 Breezy Developers
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
0.434.1 by Jelmer Vernooij
Use absolute_import.
17
"""Support for GitHub."""
18
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
19
from __future__ import absolute_import
20
7359.1.3 by Jelmer Vernooij
Fix GitHub API interaction.
21
import json
0.431.49 by Jelmer Vernooij
Store GitHub tokens in a magic file, for now.
22
import os
23
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
24
from .propose import (
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
25
    Hoster,
7268.8.2 by Jelmer Vernooij
Handle GitHub errors.
26
    HosterLoginRequired,
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
27
    MergeProposal,
0.432.2 by Jelmer Vernooij
Publish command sort of works.
28
    MergeProposalBuilder,
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
29
    MergeProposalExists,
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
30
    NoSuchProject,
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
31
    PrerequisiteBranchUnsupported,
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
32
    UnsupportedHoster,
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
33
    )
34
35
from ... import (
7340.1.1 by Martin
Fix use of config_dir in propose plugin
36
    bedding,
0.431.33 by Jelmer Vernooij
Fix URLs from gitlab.
37
    branch as _mod_branch,
0.432.3 by Jelmer Vernooij
Publish command works for github.
38
    controldir,
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
39
    errors,
40
    hooks,
41
    urlutils,
0.432.3 by Jelmer Vernooij
Publish command works for github.
42
    version_string as breezy_version,
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
43
    )
7340.1.1 by Martin
Fix use of config_dir in propose plugin
44
from ...config import AuthenticationConfig, GlobalStack
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
45
from ...errors import InvalidHttpResponse
0.431.32 by Jelmer Vernooij
Properly resolve git+ssh URLs.
46
from ...git.urls import git_url_to_bzr_url
0.432.3 by Jelmer Vernooij
Publish command works for github.
47
from ...i18n import gettext
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
48
from ...sixish import PY3
0.432.3 by Jelmer Vernooij
Publish command works for github.
49
from ...trace import note
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
50
from ...transport import get_transport
7296.10.5 by Jelmer Vernooij
use default_user_agent function.
51
from ...transport.http import default_user_agent
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
52
53
54
GITHUB_HOST = 'github.com'
55
WEB_GITHUB_URL = 'https://github.com'
56
API_GITHUB_URL = 'https://api.github.com'
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
57
58
0.431.49 by Jelmer Vernooij
Store GitHub tokens in a magic file, for now.
59
def store_github_token(scheme, host, token):
7340.1.1 by Martin
Fix use of config_dir in propose plugin
60
    with open(os.path.join(bedding.config_dir(), 'github.conf'), 'w') as f:
0.431.49 by Jelmer Vernooij
Store GitHub tokens in a magic file, for now.
61
        f.write(token)
62
63
64
def retrieve_github_token(scheme, host):
7340.1.1 by Martin
Fix use of config_dir in propose plugin
65
    path = os.path.join(bedding.config_dir(), 'github.conf')
0.431.49 by Jelmer Vernooij
Store GitHub tokens in a magic file, for now.
66
    if not os.path.exists(path):
67
        return None
0.435.1 by Jelmer Vernooij
Fix reading github credentials.
68
    with open(path, 'r') as f:
0.431.49 by Jelmer Vernooij
Store GitHub tokens in a magic file, for now.
69
        return f.read().strip()
70
71
0.431.44 by Jelmer Vernooij
Support get/set description.
72
def determine_title(description):
73
    return description.splitlines()[0]
74
75
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
76
class NotGitHubUrl(errors.BzrError):
77
78
    _fmt = "Not a GitHub URL: %(url)s"
79
80
    def __init__(self, url):
81
        errors.BzrError.__init__(self)
82
        self.url = url
83
84
7268.8.2 by Jelmer Vernooij
Handle GitHub errors.
85
class GitHubLoginRequired(HosterLoginRequired):
86
87
    _fmt = "Action requires GitHub login."
88
89
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
90
def connect_github():
7211.13.7 by Jelmer Vernooij
Fix formatting.
91
    """Connect to GitHub.
92
    """
7296.10.5 by Jelmer Vernooij
use default_user_agent function.
93
    user_agent = default_user_agent()
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
94
    auth = AuthenticationConfig()
95
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
96
    credentials = auth.get_credentials('https', GITHUB_HOST)
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
97
    if credentials is not None:
0.432.3 by Jelmer Vernooij
Publish command works for github.
98
        return Github(credentials['user'], credentials['password'],
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
99
                      user_agent=user_agent)
100
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
101
    # TODO(jelmer): token = auth.get_token('https', GITHUB_HOST)
0.431.49 by Jelmer Vernooij
Store GitHub tokens in a magic file, for now.
102
    if token is not None:
0.431.61 by Jelmer Vernooij
Fix token login.
103
        return Github(token, user_agent=user_agent)
0.431.49 by Jelmer Vernooij
Store GitHub tokens in a magic file, for now.
104
    else:
105
        note('Accessing GitHub anonymously. To log in, run \'brz gh-login\'.')
106
        return Github(user_agent=user_agent)
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
107
108
0.431.44 by Jelmer Vernooij
Support get/set description.
109
class GitHubMergeProposal(MergeProposal):
110
7371.4.2 by Jelmer Vernooij
More fixes.
111
    def __init__(self, gh, pr):
112
        self._gh = gh
0.431.44 by Jelmer Vernooij
Support get/set description.
113
        self._pr = pr
114
115
    @property
116
    def url(self):
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
117
        return self._pr['html_url']
0.431.44 by Jelmer Vernooij
Support get/set description.
118
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
119
    def _branch_from_part(self, part):
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
120
        return github_url_to_bzr_url(part['repo']['html_url'], part['ref'])
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
121
122
    def get_source_branch_url(self):
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
123
        return self._branch_from_part(self._pr['head'])
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
124
125
    def get_target_branch_url(self):
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
126
        return self._branch_from_part(self._pr['base'])
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
127
0.431.44 by Jelmer Vernooij
Support get/set description.
128
    def get_description(self):
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
129
        return self._pr['body']
0.431.44 by Jelmer Vernooij
Support get/set description.
130
7296.8.2 by Jelmer Vernooij
Add feature flag for commit message.
131
    def get_commit_message(self):
132
        return None
133
7371.4.2 by Jelmer Vernooij
More fixes.
134
    def set_commit_message(self, message):
135
        self._patch({'title': message})
136
137
    def _patch(self, data):
138
        response = self._gh._api_request(
139
            'PATCH', self._pr['url'], body=json.dumps(data).encode('utf-8'))
140
        if response != 200:
141
            raise InvalidHttpResponse(self._pr['url'], response.text)
142
        self._pr = json.loads(response.text)
143
0.431.44 by Jelmer Vernooij
Support get/set description.
144
    def set_description(self, description):
7371.4.2 by Jelmer Vernooij
More fixes.
145
        self._patch({
146
            'body': description,
147
            'title': determine_title(description),
148
            })
0.431.44 by Jelmer Vernooij
Support get/set description.
149
0.431.46 by Jelmer Vernooij
Add MergeProposal.is_merged.
150
    def is_merged(self):
7371.4.1 by Jelmer Vernooij
Fix iter_proposals for GitHub.
151
        return self._pr['state'] == 'merged'
0.431.46 by Jelmer Vernooij
Add MergeProposal.is_merged.
152
7260.2.1 by Jelmer Vernooij
Implement .close on merge proposals.
153
    def close(self):
7371.4.2 by Jelmer Vernooij
More fixes.
154
        self._patch({'state': 'closed'})
7260.2.1 by Jelmer Vernooij
Implement .close on merge proposals.
155
7296.9.1 by Jelmer Vernooij
Add 'brz land' subcommand.
156
    def merge(self, commit_message=None):
157
        # https://developer.github.com/v3/pulls/#merge-a-pull-request-merge-button
158
        self._pr.merge(commit_message=commit_message)
159
0.431.44 by Jelmer Vernooij
Support get/set description.
160
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
161
def parse_github_url(url):
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
162
    (scheme, user, password, host, port, path) = urlutils.parse_url(
163
        url)
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
164
    if host != GITHUB_HOST:
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
165
        raise NotGitHubUrl(url)
166
    (owner, repo_name) = path.strip('/').split('/')
0.432.12 by Jelmer Vernooij
Fix .git ends.
167
    if repo_name.endswith('.git'):
168
        repo_name = repo_name[:-4]
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
169
    return owner, repo_name
170
171
172
def parse_github_branch_url(branch):
173
    url = urlutils.split_segment_parameters(branch.user_url)[0]
174
    owner, repo_name = parse_github_url(url)
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
175
    return owner, repo_name, branch.name
176
177
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
178
def github_url_to_bzr_url(url, branch_name):
179
    if not PY3:
180
        branch_name = branch_name.encode('utf-8')
181
    return urlutils.join_segment_parameters(
7211.13.7 by Jelmer Vernooij
Fix formatting.
182
        git_url_to_bzr_url(url), {"branch": branch_name})
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
183
184
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
185
class GitHub(Hoster):
186
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
187
    name = 'github'
188
0.431.13 by Jelmer Vernooij
Add support for labels on merge proposals.
189
    supports_merge_proposal_labels = True
7296.8.2 by Jelmer Vernooij
Add feature flag for commit message.
190
    supports_merge_proposal_commit_message = False
0.431.13 by Jelmer Vernooij
Add support for labels on merge proposals.
191
0.433.1 by Jelmer Vernooij
Add Hoster.hosts.
192
    def __repr__(self):
193
        return "GitHub()"
194
7371.4.2 by Jelmer Vernooij
More fixes.
195
    def _api_request(self, method, path, body=None):
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
196
        headers = {
197
            'Accept': 'application/vnd.github.v3+json'}
198
        if self._token:
199
            headers['Authorization'] = 'token %s' % self._token
200
        response = self.transport.request(
201
            method, urlutils.join(self.transport.base, path),
7371.4.2 by Jelmer Vernooij
More fixes.
202
            headers=headers, body=body)
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
203
        if response.status == 401:
204
            raise GitHubLoginRequired(self)
205
        return response
206
207
    def _get_repo(self, path):
208
        path = 'repos/' + path
209
        response = self._api_request('GET', path)
210
        if response.status == 404:
211
            raise NoSuchProject(path)
212
        if response.status == 200:
7359.1.3 by Jelmer Vernooij
Fix GitHub API interaction.
213
            return json.loads(response.text)
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
214
        raise InvalidHttpResponse(path, response.text)
215
7371.4.1 by Jelmer Vernooij
Fix iter_proposals for GitHub.
216
    def _get_repo_pulls(self, path, head=None, state=None):
217
        path = 'repos/' + path + '/pulls?'
218
        params = {}
219
        if head is not None:
220
            params['head'] = head
221
        if state is not None:
222
            params['state'] = state
223
        path += ';'.join(['%s=%s' % (k, urlutils.quote(v))
224
                         for k, v in params.items()])
225
        response = self._api_request('GET', path)
226
        if response.status == 404:
227
            raise NoSuchProject(path)
228
        if response.status == 200:
229
            return json.loads(response.text)
230
        raise InvalidHttpResponse(path, response.text)
231
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
232
    def _get_user(self, username=None):
233
        if username:
234
            path = 'users/:%s' % username
235
        else:
236
            path = 'user'
237
        response = self._api_request('GET', path)
238
        if response.status != 200:
239
            raise InvalidHttpResponse(path, response.text)
7359.1.3 by Jelmer Vernooij
Fix GitHub API interaction.
240
        return json.loads(response.text)
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
241
242
    def _get_organization(self, name):
243
        path = 'orgs/:%s' % name
244
        response = self._api_request('GET', path)
245
        if response.status != 200:
246
            raise InvalidHttpResponse(path, response.text)
7359.1.3 by Jelmer Vernooij
Fix GitHub API interaction.
247
        return json.loads(response.text)
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
248
249
    def _search_issues(self, query):
250
        path = 'search/issues'
251
        response = self._api_request(
252
            'GET', path + '?q=' + urlutils.quote(query))
253
        if response.status != 200:
254
            raise InvalidHttpResponse(path, response.text)
7359.1.3 by Jelmer Vernooij
Fix GitHub API interaction.
255
        return json.loads(response.text)
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
256
257
    def _create_fork(self, repo, owner=None):
258
        (orig_owner, orig_repo) = repo.split('/')
259
        path = '/repos/:%s/:%s/forks' % (orig_owner, orig_repo)
260
        if owner:
261
            path += '?organization=%s' % owner
262
        response = self._api_request('POST', path)
263
        if response != 202:
264
            raise InvalidHttpResponse(path, response.text)
7359.1.3 by Jelmer Vernooij
Fix GitHub API interaction.
265
        return json.loads(response.text)
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
266
7260.1.1 by Jelmer Vernooij
Add .base_url property to Hoster.
267
    @property
268
    def base_url(self):
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
269
        return WEB_GITHUB_URL
270
271
    def __init__(self, transport):
272
        self._token = retrieve_github_token('https', GITHUB_HOST)
273
        self.transport = transport
274
        self._current_user = self._get_user()
275
0.431.20 by Jelmer Vernooij
publish -> publish_derived.
276
    def publish_derived(self, local_branch, base_branch, name, project=None,
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
277
                        owner=None, revision_id=None, overwrite=False,
278
                        allow_lossy=True):
0.432.12 by Jelmer Vernooij
Fix .git ends.
279
        import github
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
280
        base_owner, base_project, base_branch_name = parse_github_branch_url(base_branch)
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
281
        base_repo = self._get_repo('%s/%s' % (base_owner, base_project))
0.432.3 by Jelmer Vernooij
Publish command works for github.
282
        if owner is None:
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
283
            owner = self._current_user['login']
0.432.3 by Jelmer Vernooij
Publish command works for github.
284
        if project is None:
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
285
            project = base_repo['name']
0.432.3 by Jelmer Vernooij
Publish command works for github.
286
        try:
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
287
            remote_repo = self._get_repo('%s/%s' % (owner, project))
0.432.12 by Jelmer Vernooij
Fix .git ends.
288
        except github.UnknownObjectException:
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
289
            base_repo = self._get_repo('%s/%s' % (base_owner, base_project))
290
            remote_repo = self._create_fork(base_repo, owner)
0.432.3 by Jelmer Vernooij
Publish command works for github.
291
            note(gettext('Forking new repository %s from %s') %
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
292
                 (remote_repo['html_url'], base_repo['html_url']))
0.432.3 by Jelmer Vernooij
Publish command works for github.
293
        else:
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
294
            note(gettext('Reusing existing repository %s') % remote_repo['html_url'])
295
        remote_dir = controldir.ControlDir.open(git_url_to_bzr_url(remote_repo['ssh_url']))
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
296
        try:
7211.13.7 by Jelmer Vernooij
Fix formatting.
297
            push_result = remote_dir.push_branch(
298
                local_branch, revision_id=revision_id, overwrite=overwrite,
299
                name=name)
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
300
        except errors.NoRoundtrippingSupport:
301
            if not allow_lossy:
302
                raise
7211.13.7 by Jelmer Vernooij
Fix formatting.
303
            push_result = remote_dir.push_branch(
304
                local_branch, revision_id=revision_id,
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
305
                overwrite=overwrite, name=name, lossy=True)
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
306
        return push_result.target_branch, github_url_to_bzr_url(
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
307
            remote_repo['html_url'], name)
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
308
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
309
    def get_push_url(self, branch):
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
310
        owner, project, branch_name = parse_github_branch_url(branch)
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
311
        repo = self._get_repo('%s/%s' % (owner, project))
312
        return github_url_to_bzr_url(repo['ssh_url'], branch_name)
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
313
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
314
    def get_derived_branch(self, base_branch, name, project=None, owner=None):
315
        import github
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
316
        base_owner, base_project, base_branch_name = parse_github_branch_url(base_branch)
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
317
        base_repo = self._get_repo('%s/%s' % (base_owner, base_project))
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
318
        if owner is None:
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
319
            owner = self._current_user['login']
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
320
        if project is None:
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
321
            project = base_repo['name']
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
322
        try:
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
323
            remote_repo = self._get_repo('%s/%s' % (owner, project))
324
            full_url = github_url_to_bzr_url(remote_repo['ssh_url'], name)
0.431.33 by Jelmer Vernooij
Fix URLs from gitlab.
325
            return _mod_branch.Branch.open(full_url)
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
326
        except github.UnknownObjectException:
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
327
            raise errors.NotBranchError('%s/%s/%s' % (WEB_GITHUB_URL, owner, project))
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
328
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
329
    def get_proposer(self, source_branch, target_branch):
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
330
        return GitHubMergeProposalBuilder(self, source_branch, target_branch)
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
331
0.431.68 by Jelmer Vernooij
Add status to other Hosters.
332
    def iter_proposals(self, source_branch, target_branch, status='open'):
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
333
        (source_owner, source_repo_name, source_branch_name) = (
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
334
            parse_github_branch_url(source_branch))
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
335
        (target_owner, target_repo_name, target_branch_name) = (
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
336
            parse_github_branch_url(target_branch))
7371.4.1 by Jelmer Vernooij
Fix iter_proposals for GitHub.
337
        target_repo_path = "%s/%s" % (target_owner, target_repo_name)
338
        target_repo = self._get_repo(target_repo_path)
0.431.68 by Jelmer Vernooij
Add status to other Hosters.
339
        state = {
340
            'open': 'open',
341
            'merged': 'closed',
342
            'closed': 'closed',
343
            'all': 'all'}
7371.4.1 by Jelmer Vernooij
Fix iter_proposals for GitHub.
344
        pulls = self._get_repo_pulls(
345
            target_repo_path,
346
            head=target_branch_name,
347
            state=state[status])
348
        for pull in pulls:
349
            if (status == 'closed' and pull['merged'] or
350
                    status == 'merged' and not pull['merged']):
351
                continue
352
            if pull['head']['ref'] != source_branch_name:
353
                continue
354
            if pull['head']['repo'] is None:
7268.4.1 by Jelmer Vernooij
Don't attempt to resolve None when repo has gone away.
355
                # Repo has gone the way of the dodo
356
                continue
7371.4.1 by Jelmer Vernooij
Fix iter_proposals for GitHub.
357
            if (pull['head']['repo']['owner']['login'] != source_owner or
358
                    pull['head']['repo']['name'] != source_repo_name):
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
359
                continue
7371.4.2 by Jelmer Vernooij
More fixes.
360
            yield GitHubMergeProposal(self, pull)
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
361
0.433.1 by Jelmer Vernooij
Add Hoster.hosts.
362
    def hosts(self, branch):
363
        try:
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
364
            parse_github_branch_url(branch)
0.433.1 by Jelmer Vernooij
Add Hoster.hosts.
365
        except NotGitHubUrl:
366
            return False
367
        else:
368
            return True
369
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
370
    @classmethod
7296.10.1 by Jelmer Vernooij
Initial work making gitlab just directly use ReST.
371
    def probe_from_url(cls, url, possible_transports=None):
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
372
        try:
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
373
            parse_github_url(url)
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
374
        except NotGitHubUrl:
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
375
            raise UnsupportedHoster(url)
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
376
        transport = get_transport(
377
            API_GITHUB_URL, possible_transports=possible_transports)
378
        return cls(transport)
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
379
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
380
    @classmethod
381
    def iter_instances(cls):
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
382
        yield cls(get_transport(API_GITHUB_URL))
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
383
0.431.66 by Jelmer Vernooij
Add support for status argument.
384
    def iter_my_proposals(self, status='open'):
385
        query = ['is:pr']
386
        if status == 'open':
387
            query.append('is:open')
388
        elif status == 'closed':
389
            query.append('is:unmerged')
7268.2.1 by Jelmer Vernooij
Don't include open unmerged pull requests in 'closed'.
390
            # Also use "is:closed" otherwise unmerged open pull requests are
391
            # also included.
392
            query.append('is:closed')
0.431.66 by Jelmer Vernooij
Add support for status argument.
393
        elif status == 'merged':
394
            query.append('is:merged')
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
395
        query.append('author:%s' % self._current_user['login'])
396
        for issue in self._search_issues(query=' '.join(query))['items']:
7360.1.5 by Jelmer Vernooij
Use authenticated request when requesting pull requests from GitHub; authenticated connections have a much lower rate limit.
397
            url = issue['pull_request']['url']
398
            response = self._api_request('GET', url)
399
            if response.status != 200:
400
                raise InvalidHttpResponse(url, response.text)
7371.4.2 by Jelmer Vernooij
More fixes.
401
            yield GitHubMergeProposal(self, json.loads(response.text))
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
402
7296.9.1 by Jelmer Vernooij
Add 'brz land' subcommand.
403
    def get_proposal_by_url(self, url):
404
        raise UnsupportedHoster(url)
405
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
406
0.432.2 by Jelmer Vernooij
Publish command sort of works.
407
class GitHubMergeProposalBuilder(MergeProposalBuilder):
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
408
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
409
    def __init__(self, gh, source_branch, target_branch):
410
        self.gh = gh
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
411
        self.source_branch = source_branch
412
        self.target_branch = target_branch
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
413
        (self.target_owner, self.target_repo_name, self.target_branch_name) = (
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
414
            parse_github_branch_url(self.target_branch))
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
415
        (self.source_owner, self.source_repo_name, self.source_branch_name) = (
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
416
            parse_github_branch_url(self.source_branch))
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
417
418
    def get_infotext(self):
419
        """Determine the initial comment for the merge proposal."""
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
420
        info = []
421
        info.append("Merge %s into %s:%s\n" % (
422
            self.source_branch_name, self.target_owner,
423
            self.target_branch_name))
424
        info.append("Source: %s\n" % self.source_branch.user_url)
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
425
        info.append("Target: %s\n" % self.target_branch.user_url)
426
        return ''.join(info)
427
428
    def get_initial_body(self):
429
        """Get a body for the proposal for the user to modify.
430
431
        :return: a str or None.
432
        """
433
        return None
434
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
435
    def create_proposal(self, description, reviewers=None, labels=None,
7296.8.1 by Jelmer Vernooij
Add commit-message option to 'brz propose'.
436
                        prerequisite_branch=None, commit_message=None):
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
437
        """Perform the submission."""
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
438
        if prerequisite_branch is not None:
439
            raise PrerequisiteBranchUnsupported(self)
7296.8.1 by Jelmer Vernooij
Add commit-message option to 'brz propose'.
440
        # Note that commit_message is ignored, since github doesn't support it.
0.432.10 by Jelmer Vernooij
More test fixes.
441
        import github
0.432.7 by Jelmer Vernooij
propose works \o/
442
        # TODO(jelmer): Probe for right repo name
0.432.12 by Jelmer Vernooij
Fix .git ends.
443
        if self.target_repo_name.endswith('.git'):
444
            self.target_repo_name = self.target_repo_name[:-4]
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
445
        target_repo = self.gh._get_repo("%s/%s" % (self.target_owner, self.target_repo_name))
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
446
        # TODO(jelmer): Allow setting title explicitly?
0.431.44 by Jelmer Vernooij
Support get/set description.
447
        title = determine_title(description)
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
448
        # TOOD(jelmer): Set maintainers_can_modify?
0.432.10 by Jelmer Vernooij
More test fixes.
449
        try:
450
            pull_request = target_repo.create_pull(
451
                title=title, body=description,
452
                head="%s:%s" % (self.source_owner, self.source_branch_name),
453
                base=self.target_branch_name)
454
        except github.GithubException as e:
455
            if e.status == 422:
456
                raise MergeProposalExists(self.source_branch.user_url)
457
            raise
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
458
        if reviewers:
459
            for reviewer in reviewers:
460
                pull_request.assignees.append(
7296.11.1 by Jelmer Vernooij
Initial work migrating GitHub away from library.
461
                    self.gh._get_user(reviewer)['login'])
0.431.13 by Jelmer Vernooij
Add support for labels on merge proposals.
462
        if labels:
463
            for label in labels:
464
                pull_request.issue.labels.append(label)
7371.4.2 by Jelmer Vernooij
More fixes.
465
        return GitHubMergeProposal(self.gh, pull_request)