Skip to content

Commit 8e1b647

Browse files
committed
Merge branch fix/request-create-2 into devel
* updates bitbucket branch to new request create algorithm * updates tests for bitbucket * minor fixes Signed-off-by: Guyzmo <[email protected]>
2 parents 4629220 + 9f38561 commit 8e1b647

20 files changed

+424
-196
lines changed

.travis.yml

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
language: python
22
# Don't use the Travis Container-Based Infrastructure
3-
sudo: true
3+
sudo: required
4+
dist: trusty
45
matrix:
56
include:
67
- os: linux
@@ -43,4 +44,4 @@ install:
4344
- "pip install --upgrade pip" # upgrade to latest pip (needed on py3.4)
4445
- "pip install -r requirements-test.txt"
4546
# command to run tests
46-
script: "py.test --cov=git_repo --cov-report term-missing --capture=sys tests"
47+
script: "py.test --cov=git_repo --cov-report term-missing tests"

git_repo/repo.py

+16-32
Original file line numberDiff line numberDiff line change
@@ -154,28 +154,6 @@ def init(self): # pragma: no cover
154154
if 'GIT_WORK_TREE' in os.environ.keys() or 'GIT_DIR' in os.environ.keys():
155155
del os.environ['GIT_WORK_TREE']
156156

157-
def _guess_repo_slug(self, repository, service, resolve_targets=None):
158-
config = repository.config_reader()
159-
if resolve_targets:
160-
targets = [target.format(service=service.name) for target in resolve_targets]
161-
else:
162-
targets = (service.name, 'upstream', 'origin')
163-
for remote in repository.remotes:
164-
if remote.name in targets:
165-
for url in remote.urls:
166-
if url.endswith('.git'):
167-
url = url[:-4]
168-
# strip http://, https:// and ssh://
169-
if '://' in url:
170-
*_, user, name = url.split('/')
171-
self.set_repo_slug('/'.join([user, name]))
172-
return
173-
# scp-style URL
174-
elif '@' in url and ':' in url:
175-
_, repo_slug = url.split(':')
176-
self.set_repo_slug(repo_slug)
177-
return
178-
179157
def get_service(self, lookup_repository=True, resolve_targets=None):
180158
if not lookup_repository:
181159
service = RepositoryService.get_service(None, self.target)
@@ -191,7 +169,11 @@ def get_service(self, lookup_repository=True, resolve_targets=None):
191169
raise FileNotFoundError('Cannot find path to the repository.')
192170
service = RepositoryService.get_service(repository, self.target)
193171
if not self.repo_name:
194-
self._guess_repo_slug(repository, service, resolve_targets)
172+
repo_slug = RepositoryService.guess_repo_slug(
173+
repository, service, resolve_targets
174+
)
175+
if repo_slug:
176+
self.set_repo_slug(repo_slug, auto=True)
195177
return service
196178

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

225207
@store_parameter('<user>/<repo>')
226-
def set_repo_slug(self, repo_slug):
208+
def set_repo_slug(self, repo_slug, auto=False):
227209
self.repo_slug = EXTRACT_URL_RE.sub('', repo_slug) if repo_slug else repo_slug
210+
self._auto_slug = auto
228211
if not self.repo_slug:
229212
self.user_name = None
230213
self.repo_name = None
@@ -393,13 +376,13 @@ def do_request_list(self):
393376

394377
@register_action('request', 'create')
395378
def do_request_create(self):
396-
def request_edition(repository, from_branch):
379+
def request_edition(repository, from_branch, onto_target):
397380
try:
398381
commit = repository.commit(from_branch)
399382
title, *body = commit.message.split('\n')
400383
except BadName:
401384
log.error('Couldn\'t find local source branch {}'.format(from_branch))
402-
return None
385+
return None, None
403386
from tempfile import NamedTemporaryFile
404387
from subprocess import call
405388
with NamedTemporaryFile(
@@ -416,9 +399,13 @@ def request_edition(repository, from_branch):
416399
'## Filled with commit:\n'
417400
'## {}\n'
418401
'####################################################\n'
402+
'## To be applied:\n'
403+
'## from branch: {}\n'
404+
'## onto project: {}\n'
405+
'####################################################\n'
419406
'## * All lines starting with # will be ignored.\n'
420407
'## * First non-ignored line is the title of the request.\n'
421-
).format(title, '\n'.join(body), commit.name_rev).encode('utf-8'))
408+
).format(title, '\n'.join(body), commit.name_rev, from_branch, onto_target).encode('utf-8'))
422409
request_file.flush()
423410
rv = call("{} {}".format(os.environ['EDITOR'], request_file.name), shell=True)
424411
if rv != 0:
@@ -443,12 +430,9 @@ def request_edition(repository, from_branch):
443430
self.remote_branch,
444431
self.title,
445432
self.message,
446-
self.repo_slug != None,
433+
self._auto_slug,
447434
request_edition)
448-
log.info('Successfully created request of `{local}` onto `{}:{remote}`, with id `{ref}`!'.format(
449-
'/'.join([self.user_name, self.repo_name]),
450-
**new_request)
451-
)
435+
log.info('Successfully created request of `{local}` onto `{project}:{remote}`, with id `{ref}`!'.format(**new_request))
452436
if 'url' in new_request:
453437
log.info('available at: {url}'.format(**new_request))
454438
return 0

git_repo/services/ext/bitbucket.py

+54-19
Original file line numberDiff line numberDiff line change
@@ -240,50 +240,85 @@ def gist_delete(self, gist_id):
240240
raise ResourceNotFoundError("Could not find snippet {}.".format(gist_id)) from err
241241
raise ResourceError("Couldn't delete snippet: {}".format(err)) from err
242242

243-
def request_create(self, user, repo, local_branch, remote_branch, title=None, description=None, edit=None):
243+
def request_create(self, onto_user, onto_repo, from_branch, onto_branch, title=None, description=None, auto_slug=False, edit=None):
244244
try:
245-
repository = next(self.bb.repositoryByOwnerAndRepositoryName(owner=user, repository_name=repo))
246-
if not repository:
247-
raise ResourceNotFoundError('Could not find repository `{}/{}`!'.format(user, repo))
248-
if not remote_branch:
245+
onto_project = self.get_repository(onto_user, onto_repo)
246+
247+
from_reposlug = self.guess_repo_slug(self.repository, self)
248+
if from_reposlug:
249+
from_user, from_repo = from_reposlug.split('/')
250+
if (onto_user, onto_repo) == (from_user, from_repo):
251+
from_project = onto_project
252+
else:
253+
from_project = self.get_repository(from_user, from_repo)
254+
else:
255+
from_project = None
256+
257+
# when no repo slug has been given to `git-repo X request create`
258+
# then chances are current project is a fork of the target
259+
# project we want to push to
260+
if auto_slug and onto_project.fork:
261+
onto_user = onto_project.parent.owner.login
262+
onto_repo = onto_project.parent.name
263+
onto_project = self.repository(onto_user, onto_repo)
264+
265+
# if no onto branch has been defined, take the default one
266+
# with a fallback on master
267+
if not from_branch:
268+
from_branch = self.repository.active_branch.name
269+
270+
# if no from branch has been defined, chances are we want to push
271+
# the branch we're currently working on
272+
if not onto_branch:
249273
try:
250-
remote_branch = next(repository.branches()).name
274+
onto_branch = next(onto_project.branches()).name
251275
except StopIteration:
252-
remote_branch = 'master'
253-
if not local_branch:
254-
local_branch = self.repository.active_branch.name
276+
onto_branch = 'master'
277+
278+
from_target = '{}:{}'.format(from_user, from_branch)
279+
onto_target = '{}/{}:{}'.format(onto_user, onto_project, onto_branch)
280+
281+
# translate from github username to git remote name
255282
if not title and not description and edit:
256-
title, description = edit(self.repository, from_branch)
283+
title, description = edit(self.repository, from_branch, onto_target)
257284
if not title and not description:
258285
raise ArgumentError('Missing message for request creation')
286+
259287
request = PullRequest.create(
260288
PullRequestPayload(
261289
payload=dict(
262290
title=title,
263291
description=description or '',
264292
destination=dict(
265-
branch=dict(name=remote_branch)
293+
branch=dict(name=onto_branch)
266294
),
267295
source=dict(
268-
repository=dict(full_name='/'.join([self.user, repo])),
269-
branch=dict(name=local_branch)
296+
repository=dict(full_name='/'.join([from_user, from_repo])),
297+
branch=dict(name=from_branch)
270298
)
271299
)
272300
),
273-
repository_name=repo,
274-
owner=user,
301+
repository_name=onto_repo,
302+
owner=onto_user,
275303
client=self.bb.client
276304
)
305+
306+
return {
307+
'local': from_branch,
308+
'remote': onto_branch,
309+
'ref': request.id,
310+
'project': '/'.join([onto_user, onto_repo]),
311+
'url': request.links['html']['href']
312+
}
313+
277314
except HTTPError as err:
278315
status_code = hasattr(err, 'code') and err.code or err.response.status_code
279316
if 404 == status_code:
280-
raise ResourceNotFoundError("Couldn't create request, project not found: {}".format(repo)) from err
317+
raise ResourceNotFoundError("Couldn't create request, project not found: {}".format(onto_repo)) from err
281318
elif 400 == status_code and 'branch not found' in err.format_message():
282-
raise ResourceNotFoundError("Couldn't create request, branch not found: {}".format(local_branch)) from err
319+
raise ResourceNotFoundError("Couldn't create request, branch not found: {}".format(from_branch)) from err
283320
raise ResourceError("Couldn't create request: {}".format(err)) from err
284321

285-
return {'local': local_branch, 'remote': remote_branch, 'ref': str(request.id)}
286-
287322
def request_list(self, user, repo):
288323
requests = set(
289324
(

git_repo/services/ext/github.py

+48-21
Original file line numberDiff line numberDiff line change
@@ -231,37 +231,66 @@ def gist_delete(self, gist_id):
231231
raise ResourceNotFoundError('Could not find gist')
232232
gist.delete()
233233

234-
def request_create(self, user, repo, from_branch, onto_branch, title=None, description=None, auto_slug=False, edit=None):
235-
repository = self.gh.repository(user, repo)
236-
if not repository:
237-
raise ResourceNotFoundError('Could not find repository `{}/{}`!'.format(user, repo))
234+
def request_create(self, onto_user, onto_repo, from_branch, onto_branch, title=None, description=None, auto_slug=False, edit=None):
235+
onto_project = self.gh.repository(onto_user, onto_repo)
236+
237+
if not onto_project:
238+
raise ResourceNotFoundError('Could not find project `{}/{}`!'.format(onto_user, onto_repo))
239+
240+
from_reposlug = self.guess_repo_slug(self.repository, self)
241+
if from_reposlug:
242+
from_user, from_repo = from_reposlug.split('/')
243+
if (onto_user, onto_repo) == (from_user, from_repo):
244+
from_project = onto_project
245+
else:
246+
from_project = self.gh.repository(from_user, from_repo)
247+
else:
248+
from_project = None
249+
250+
if not from_project:
251+
raise ResourceNotFoundError('Could not find project `{}`!'.format(from_user, from_repo))
252+
238253
# when no repo slug has been given to `git-repo X request create`
239-
if auto_slug:
240-
# then chances are current repository is a fork of the target
241-
# repository we want to push to
242-
if repository.fork:
243-
user = repository.parent.owner.login
244-
repo = repository.parent.name
245-
from_branch = from_branch or repository.parent.default_branch
254+
# then chances are current project is a fork of the target
255+
# project we want to push to
256+
if auto_slug and onto_project.fork:
257+
onto_user = onto_project.parent.owner.login
258+
onto_repo = onto_project.parent.name
259+
onto_project = self.gh.repository(onto_user, onto_repo)
260+
246261
# if no onto branch has been defined, take the default one
247262
# with a fallback on master
248263
if not from_branch:
249264
from_branch = self.repository.active_branch.name
265+
250266
# if no from branch has been defined, chances are we want to push
251267
# the branch we're currently working on
252268
if not onto_branch:
253-
onto_branch = repository.default_branch or 'master'
254-
if self.username != repository.owner.login:
255-
from_branch = ':'.join([self.username, from_branch])
269+
onto_branch = onto_project.default_branch or 'master'
270+
271+
from_target = '{}:{}'.format(from_user, from_branch)
272+
onto_target = '{}/{}:{}'.format(onto_user, onto_project, onto_branch)
273+
274+
# translate from github username to git remote name
256275
if not title and not description and edit:
257-
title, description = edit(self.repository, from_branch)
276+
title, description = edit(self.repository, from_branch, onto_target)
258277
if not title and not description:
259278
raise ArgumentError('Missing message for request creation')
279+
260280
try:
261-
request = repository.create_pull(title,
281+
request = onto_project.create_pull(title,
282+
head=from_target,
262283
base=onto_branch,
263-
head=from_branch,
264284
body=description)
285+
286+
return {
287+
'local': from_branch,
288+
'project': '/'.join([onto_user, onto_repo]),
289+
'remote': onto_branch,
290+
'ref': request.number,
291+
'url': request.html_url
292+
}
293+
265294
except github3.models.GitHubError as err:
266295
if err.code == 422:
267296
if err.message == 'Validation Failed':
@@ -278,9 +307,6 @@ def request_create(self, user, repo, from_branch, onto_branch, title=None, descr
278307
raise ResourceError("Unhandled formatting error: {}".format(err.errors))
279308
raise ResourceError(err.message)
280309

281-
return {'local': from_branch, 'remote': onto_branch, 'ref': request.number,
282-
'url': request.html_url}
283-
284310
def request_list(self, user, repo):
285311
repository = self.gh.repository(user, repo)
286312
yield "{}\t{:<60}\t{}"
@@ -292,8 +318,9 @@ def request_fetch(self, user, repo, request, pull=False, force=False):
292318
if pull:
293319
raise NotImplementedError('Pull operation on requests for merge are not yet supported')
294320
try:
321+
remote_names = list(self._convert_user_into_remote(user))
295322
for remote in self.repository.remotes:
296-
if remote.name == self.name:
323+
if remote.name in remote_names:
297324
local_branch_name = 'requests/{}/{}'.format(self.name,request)
298325
self.fetch(
299326
remote,

0 commit comments

Comments
 (0)