Skip to content

Commit

Permalink
Merge branch fix/request-create-2 into devel
Browse files Browse the repository at this point in the history
* updates bitbucket branch to new request create algorithm
* updates tests for bitbucket
* minor fixes

Signed-off-by: Guyzmo <[email protected]>
  • Loading branch information
guyzmo committed May 2, 2017
2 parents 4629220 + 9f38561 commit b21c023
Show file tree
Hide file tree
Showing 20 changed files with 437 additions and 209 deletions.
31 changes: 16 additions & 15 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
language: python
# Don't use the Travis Container-Based Infrastructure
sudo: true
sudo: required
dist: trusty
matrix:
include:
- os: linux
python: "3.4"
- os: linux
python: "3.5"
# - os: linux
# python: "3.4"
# - os: linux
# python: "3.5"
- os: linux
python: "3.6"
- os: linux
python: "3.6-dev"
- os: linux
python: "nightly"
- os: linux
python: "pypy3"
# - os: linux
# python: "3.6-dev"
# - os: linux
# python: "nightly"
# - os: linux
# python: "pypy3"

- os: osx
sudo: required
language: generic
# - os: osx
# sudo: required
# language: generic

allow_failures:
- python: "3.6-dev"
Expand All @@ -43,4 +44,4 @@ install:
- "pip install --upgrade pip" # upgrade to latest pip (needed on py3.4)
- "pip install -r requirements-test.txt"
# command to run tests
script: "py.test --cov=git_repo --cov-report term-missing --capture=sys tests"
script: "py.test --cov=git_repo --cov-report term-missing tests"
48 changes: 16 additions & 32 deletions git_repo/repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,28 +154,6 @@ def init(self): # pragma: no cover
if 'GIT_WORK_TREE' in os.environ.keys() or 'GIT_DIR' in os.environ.keys():
del os.environ['GIT_WORK_TREE']

def _guess_repo_slug(self, repository, service, resolve_targets=None):
config = repository.config_reader()
if resolve_targets:
targets = [target.format(service=service.name) for target in resolve_targets]
else:
targets = (service.name, 'upstream', 'origin')
for remote in repository.remotes:
if remote.name in targets:
for url in remote.urls:
if url.endswith('.git'):
url = url[:-4]
# strip http://, https:// and ssh://
if '://' in url:
*_, user, name = url.split('/')
self.set_repo_slug('/'.join([user, name]))
return
# scp-style URL
elif '@' in url and ':' in url:
_, repo_slug = url.split(':')
self.set_repo_slug(repo_slug)
return

def get_service(self, lookup_repository=True, resolve_targets=None):
if not lookup_repository:
service = RepositoryService.get_service(None, self.target)
Expand All @@ -191,7 +169,11 @@ def get_service(self, lookup_repository=True, resolve_targets=None):
raise FileNotFoundError('Cannot find path to the repository.')
service = RepositoryService.get_service(repository, self.target)
if not self.repo_name:
self._guess_repo_slug(repository, service, resolve_targets)
repo_slug = RepositoryService.guess_repo_slug(
repository, service, resolve_targets
)
if repo_slug:
self.set_repo_slug(repo_slug, auto=True)
return service

'''Argument storage'''
Expand Down Expand Up @@ -223,8 +205,9 @@ def set_verbosity(self, verbose): # pragma: no cover
log.addHandler(logging.StreamHandler())

@store_parameter('<user>/<repo>')
def set_repo_slug(self, repo_slug):
def set_repo_slug(self, repo_slug, auto=False):
self.repo_slug = EXTRACT_URL_RE.sub('', repo_slug) if repo_slug else repo_slug
self._auto_slug = auto
if not self.repo_slug:
self.user_name = None
self.repo_name = None
Expand Down Expand Up @@ -393,13 +376,13 @@ def do_request_list(self):

@register_action('request', 'create')
def do_request_create(self):
def request_edition(repository, from_branch):
def request_edition(repository, from_branch, onto_target):
try:
commit = repository.commit(from_branch)
title, *body = commit.message.split('\n')
except BadName:
log.error('Couldn\'t find local source branch {}'.format(from_branch))
return None
return None, None
from tempfile import NamedTemporaryFile
from subprocess import call
with NamedTemporaryFile(
Expand All @@ -416,9 +399,13 @@ def request_edition(repository, from_branch):
'## Filled with commit:\n'
'## {}\n'
'####################################################\n'
'## To be applied:\n'
'## from branch: {}\n'
'## onto project: {}\n'
'####################################################\n'
'## * All lines starting with # will be ignored.\n'
'## * First non-ignored line is the title of the request.\n'
).format(title, '\n'.join(body), commit.name_rev).encode('utf-8'))
).format(title, '\n'.join(body), commit.name_rev, from_branch, onto_target).encode('utf-8'))
request_file.flush()
rv = call("{} {}".format(os.environ['EDITOR'], request_file.name), shell=True)
if rv != 0:
Expand All @@ -443,12 +430,9 @@ def request_edition(repository, from_branch):
self.remote_branch,
self.title,
self.message,
self.repo_slug != None,
self._auto_slug,
request_edition)
log.info('Successfully created request of `{local}` onto `{}:{remote}`, with id `{ref}`!'.format(
'/'.join([self.user_name, self.repo_name]),
**new_request)
)
log.info('Successfully created request of `{local}` onto `{project}:{remote}`, with id `{ref}`!'.format(**new_request))
if 'url' in new_request:
log.info('available at: {url}'.format(**new_request))
return 0
Expand Down
73 changes: 54 additions & 19 deletions git_repo/services/ext/bitbucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,50 +240,85 @@ def gist_delete(self, gist_id):
raise ResourceNotFoundError("Could not find snippet {}.".format(gist_id)) from err
raise ResourceError("Couldn't delete snippet: {}".format(err)) from err

def request_create(self, user, repo, local_branch, remote_branch, title=None, description=None, edit=None):
def request_create(self, onto_user, onto_repo, from_branch, onto_branch, title=None, description=None, auto_slug=False, edit=None):
try:
repository = next(self.bb.repositoryByOwnerAndRepositoryName(owner=user, repository_name=repo))
if not repository:
raise ResourceNotFoundError('Could not find repository `{}/{}`!'.format(user, repo))
if not remote_branch:
onto_project = self.get_repository(onto_user, onto_repo)

from_reposlug = self.guess_repo_slug(self.repository, self)
if from_reposlug:
from_user, from_repo = from_reposlug.split('/')
if (onto_user, onto_repo) == (from_user, from_repo):
from_project = onto_project
else:
from_project = self.get_repository(from_user, from_repo)
else:
from_project = None

# when no repo slug has been given to `git-repo X request create`
# then chances are current project is a fork of the target
# project we want to push to
if auto_slug and onto_project.fork:
onto_user = onto_project.parent.owner.login
onto_repo = onto_project.parent.name
onto_project = self.repository(onto_user, onto_repo)

# if no onto branch has been defined, take the default one
# with a fallback on master
if not from_branch:
from_branch = self.repository.active_branch.name

# if no from branch has been defined, chances are we want to push
# the branch we're currently working on
if not onto_branch:
try:
remote_branch = next(repository.branches()).name
onto_branch = next(onto_project.branches()).name
except StopIteration:
remote_branch = 'master'
if not local_branch:
local_branch = self.repository.active_branch.name
onto_branch = 'master'

from_target = '{}:{}'.format(from_user, from_branch)
onto_target = '{}/{}:{}'.format(onto_user, onto_project, onto_branch)

# translate from github username to git remote name
if not title and not description and edit:
title, description = edit(self.repository, from_branch)
title, description = edit(self.repository, from_branch, onto_target)
if not title and not description:
raise ArgumentError('Missing message for request creation')

request = PullRequest.create(
PullRequestPayload(
payload=dict(
title=title,
description=description or '',
destination=dict(
branch=dict(name=remote_branch)
branch=dict(name=onto_branch)
),
source=dict(
repository=dict(full_name='/'.join([self.user, repo])),
branch=dict(name=local_branch)
repository=dict(full_name='/'.join([from_user, from_repo])),
branch=dict(name=from_branch)
)
)
),
repository_name=repo,
owner=user,
repository_name=onto_repo,
owner=onto_user,
client=self.bb.client
)

return {
'local': from_branch,
'remote': onto_branch,
'ref': request.id,
'project': '/'.join([onto_user, onto_repo]),
'url': request.links['html']['href']
}

except HTTPError as err:
status_code = hasattr(err, 'code') and err.code or err.response.status_code
if 404 == status_code:
raise ResourceNotFoundError("Couldn't create request, project not found: {}".format(repo)) from err
raise ResourceNotFoundError("Couldn't create request, project not found: {}".format(onto_repo)) from err
elif 400 == status_code and 'branch not found' in err.format_message():
raise ResourceNotFoundError("Couldn't create request, branch not found: {}".format(local_branch)) from err
raise ResourceNotFoundError("Couldn't create request, branch not found: {}".format(from_branch)) from err
raise ResourceError("Couldn't create request: {}".format(err)) from err

return {'local': local_branch, 'remote': remote_branch, 'ref': str(request.id)}

def request_list(self, user, repo):
requests = set(
(
Expand Down
69 changes: 48 additions & 21 deletions git_repo/services/ext/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,37 +231,66 @@ def gist_delete(self, gist_id):
raise ResourceNotFoundError('Could not find gist')
gist.delete()

def request_create(self, user, repo, from_branch, onto_branch, title=None, description=None, auto_slug=False, edit=None):
repository = self.gh.repository(user, repo)
if not repository:
raise ResourceNotFoundError('Could not find repository `{}/{}`!'.format(user, repo))
def request_create(self, onto_user, onto_repo, from_branch, onto_branch, title=None, description=None, auto_slug=False, edit=None):
onto_project = self.gh.repository(onto_user, onto_repo)

if not onto_project:
raise ResourceNotFoundError('Could not find project `{}/{}`!'.format(onto_user, onto_repo))

from_reposlug = self.guess_repo_slug(self.repository, self)
if from_reposlug:
from_user, from_repo = from_reposlug.split('/')
if (onto_user, onto_repo) == (from_user, from_repo):
from_project = onto_project
else:
from_project = self.gh.repository(from_user, from_repo)
else:
from_project = None

if not from_project:
raise ResourceNotFoundError('Could not find project `{}`!'.format(from_user, from_repo))

# when no repo slug has been given to `git-repo X request create`
if auto_slug:
# then chances are current repository is a fork of the target
# repository we want to push to
if repository.fork:
user = repository.parent.owner.login
repo = repository.parent.name
from_branch = from_branch or repository.parent.default_branch
# then chances are current project is a fork of the target
# project we want to push to
if auto_slug and onto_project.fork:
onto_user = onto_project.parent.owner.login
onto_repo = onto_project.parent.name
onto_project = self.gh.repository(onto_user, onto_repo)

# if no onto branch has been defined, take the default one
# with a fallback on master
if not from_branch:
from_branch = self.repository.active_branch.name

# if no from branch has been defined, chances are we want to push
# the branch we're currently working on
if not onto_branch:
onto_branch = repository.default_branch or 'master'
if self.username != repository.owner.login:
from_branch = ':'.join([self.username, from_branch])
onto_branch = onto_project.default_branch or 'master'

from_target = '{}:{}'.format(from_user, from_branch)
onto_target = '{}/{}:{}'.format(onto_user, onto_project, onto_branch)

# translate from github username to git remote name
if not title and not description and edit:
title, description = edit(self.repository, from_branch)
title, description = edit(self.repository, from_branch, onto_target)
if not title and not description:
raise ArgumentError('Missing message for request creation')

try:
request = repository.create_pull(title,
request = onto_project.create_pull(title,
head=from_target,
base=onto_branch,
head=from_branch,
body=description)

return {
'local': from_branch,
'project': '/'.join([onto_user, onto_repo]),
'remote': onto_branch,
'ref': request.number,
'url': request.html_url
}

except github3.models.GitHubError as err:
if err.code == 422:
if err.message == 'Validation Failed':
Expand All @@ -278,9 +307,6 @@ def request_create(self, user, repo, from_branch, onto_branch, title=None, descr
raise ResourceError("Unhandled formatting error: {}".format(err.errors))
raise ResourceError(err.message)

return {'local': from_branch, 'remote': onto_branch, 'ref': request.number,
'url': request.html_url}

def request_list(self, user, repo):
repository = self.gh.repository(user, repo)
yield "{}\t{:<60}\t{}"
Expand All @@ -292,8 +318,9 @@ def request_fetch(self, user, repo, request, pull=False, force=False):
if pull:
raise NotImplementedError('Pull operation on requests for merge are not yet supported')
try:
remote_names = list(self._convert_user_into_remote(user))
for remote in self.repository.remotes:
if remote.name == self.name:
if remote.name in remote_names:
local_branch_name = 'requests/{}/{}'.format(self.name,request)
self.fetch(
remote,
Expand Down
Loading

0 comments on commit b21c023

Please sign in to comment.