/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/plugins/gitlab/hoster.py

  • Committer: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2020-11-19 19:46:23 UTC
  • mfrom: (7524.2.5 merge-3.1)
  • Revision ID: breezy.the.bot@gmail.com-20201119194623-5tfi4z6ktdzo0z3y
Merge lp:brz/3.1.

Merged from https://code.launchpad.net/~jelmer/brz/merge-3.1/+merge/394038

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
import json
20
20
import os
 
21
import re
21
22
import time
22
23
 
23
24
from ... import (
122
123
        self.project = project
123
124
 
124
125
 
125
 
class MergeRequestExists(Exception):
126
 
    """Raised when a merge requests already exists."""
 
126
class MergeRequestConflict(Exception):
 
127
    """Raised when a merge requests conflicts."""
 
128
 
 
129
    def __init__(self, reason):
 
130
        self.reason = reason
 
131
 
 
132
 
 
133
class ProjectCreationTimeout(errors.BzrError):
 
134
 
 
135
    _fmt = ("Timeout (%(timeout)ds) while waiting for project "
 
136
            "%(project)s to be created.")
 
137
 
 
138
    def __init__(self, project, timeout):
 
139
        self.project = project
 
140
        self.timeout = timeout
127
141
 
128
142
 
129
143
def default_config_path():
338
352
    def base_hostname(self):
339
353
        return urlutils.parse_url(self.base_url)[3]
340
354
 
 
355
    def _find_correct_project_name(self, path):
 
356
        try:
 
357
            resp = self.transport.request(
 
358
                'GET', urlutils.join(self.base_url, path),
 
359
                headers=self.headers)
 
360
        except errors.RedirectRequested as e:
 
361
            return urlutils.parse_url(e.target)[-1].strip('/')
 
362
        if resp.status != 200:
 
363
            _unexpected_status(path, resp)
 
364
        return None
 
365
 
341
366
    def _api_request(self, method, path, fields=None, body=None):
342
367
        return self.transport.request(
343
368
            method, urlutils.join(self.base_url, 'api', 'v4', path),
369
394
            return ret[0]
370
395
        _unexpected_status(path, response)
371
396
 
372
 
    def _get_project(self, project_name):
 
397
    def _get_project(self, project_name, _redirect_checked=False):
373
398
        path = 'projects/%s' % urlutils.quote(str(project_name), '')
374
399
        response = self._api_request('GET', path)
375
400
        if response.status == 404:
 
401
            if not _redirect_checked:
 
402
                project_name = self._find_correct_project_name(project_name)
 
403
                if project_name is not None:
 
404
                    return self._get_project(project_name, _redirect_checked=True)
376
405
            raise NoSuchProject(project_name)
377
406
        if response.status == 200:
378
407
            return json.loads(response.data)
399
428
        while project['import_status'] not in ('finished', 'none'):
400
429
            mutter('import status is %s', project['import_status'])
401
430
            if time.time() > deadline:
402
 
                raise Exception('timeout waiting for project to become available')
 
431
                raise ProjectCreationTimeout(
 
432
                    project['path_with_namespace'], timeout)
403
433
            time.sleep(interval)
404
434
            project = self._get_project(project['path_with_namespace'])
405
435
        return project
431
461
            for entry in json.loads(response.data):
432
462
                yield entry
433
463
 
434
 
    def _list_merge_requests(self, owner=None, project=None, state=None):
 
464
    def _list_merge_requests(self, author=None, project=None, state=None):
435
465
        if project is not None:
436
466
            path = 'projects/%s/merge_requests' % urlutils.quote(str(project), '')
437
467
        else:
439
469
        parameters = {}
440
470
        if state:
441
471
            parameters['state'] = state
442
 
        if owner:
443
 
            parameters['owner_id'] = urlutils.quote(owner, '')
 
472
        if author:
 
473
            parameters['author_username'] = urlutils.quote(author, '')
444
474
        return self._list_paged(path, parameters, per_page=DEFAULT_PAGE_SIZE)
445
475
 
446
476
    def _get_merge_request(self, project, merge_id):
497
527
        if response.status == 403:
498
528
            raise errors.PermissionDenied(response.text)
499
529
        if response.status == 409:
500
 
            raise MergeRequestExists()
 
530
            raise MergeRequestConflict(json.loads(response.data))
501
531
        if response.status == 422:
502
532
            data = json.loads(response.data)
503
533
            raise GitLabUnprocessable(data['error'])
514
544
    def publish_derived(self, local_branch, base_branch, name, project=None,
515
545
                        owner=None, revision_id=None, overwrite=False,
516
546
                        allow_lossy=True, tag_selector=None):
517
 
        (host, base_project, base_branch_name) = parse_gitlab_branch_url(base_branch)
 
547
        (host, base_project_name, base_branch_name) = parse_gitlab_branch_url(base_branch)
 
548
        if owner is None:
 
549
            owner = base_branch.get_config_stack().get('fork-namespace')
518
550
        if owner is None:
519
551
            owner = self.get_current_user()
 
552
        base_project = self._get_project(base_project_name)
520
553
        if project is None:
521
 
            project = self._get_project(base_project)['path']
 
554
            project = base_project['path']
522
555
        try:
523
556
            target_project = self._get_project('%s/%s' % (owner, project))
524
557
        except NoSuchProject:
525
 
            target_project = self._fork_project(base_project, owner=owner)
 
558
            target_project = self._fork_project(
 
559
                base_project['path_with_namespace'], owner=owner)
526
560
        remote_repo_url = git_url_to_bzr_url(target_project['ssh_url_to_repo'])
527
561
        remote_dir = controldir.ControlDir.open(remote_repo_url)
528
562
        try:
615
649
                get_transport(credentials['url']),
616
650
                private_token=credentials.get('private_token'))
617
651
 
618
 
    def iter_my_proposals(self, status='open'):
 
652
    def iter_my_proposals(self, status='open', author=None):
 
653
        if author is None:
 
654
            author = self.get_current_user()
619
655
        state = mp_status_to_status(status)
620
 
        for mp in self._list_merge_requests(
621
 
                owner=self.get_current_user(), state=state):
 
656
        for mp in self._list_merge_requests(author=author, state=state):
622
657
            yield GitLabMergeProposal(self, mp)
623
658
 
624
 
    def iter_my_forks(self):
625
 
        for project in self._list_projects(owner=self.get_current_user()):
 
659
    def iter_my_forks(self, owner=None):
 
660
        if owner is not None:
 
661
            owner = self.get_current_user()
 
662
        for project in self._list_projects(owner=owner):
626
663
            base_project = project.get('forked_from_project')
627
664
            if not base_project:
628
665
                continue
717
754
                kwargs['assignee_ids'].append(user['id'])
718
755
        try:
719
756
            merge_request = self.gl._create_mergerequest(**kwargs)
720
 
        except MergeRequestExists:
721
 
            raise MergeProposalExists(self.source_branch.user_url)
 
757
        except MergeRequestConflict as e:
 
758
            m = re.fullmatch(
 
759
                r'Another open merge request already exists for '
 
760
                r'this source branch: \!([0-9]+)',
 
761
                e.reason['message'][0])
 
762
            if m:
 
763
                merge_id = int(m.group(1))
 
764
                mr = self.gl._get_merge_request(
 
765
                    target_project['path_with_namespace'], merge_id)
 
766
                raise MergeProposalExists(
 
767
                    self.source_branch.user_url, GitLabMergeProposal(self.gl, mr))
 
768
            raise Exception('conflict: %r' % e.reason)
722
769
        except GitLabUnprocessable as e:
723
770
            if e.error == [
724
771
                    "Source project is not a fork of the target project"]: