Skip to content

Commit 244d189

Browse files
committed
🚧 request editor with latest commit's message as defaults
Signed-off-by: Guyzmo <[email protected]>
1 parent 9542185 commit 244d189

File tree

5 files changed

+87
-20
lines changed

5 files changed

+87
-20
lines changed

git_repo/repo.py

Lines changed: 62 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@
1616
{self} [--path=<path>] [-v...] <target> add <user>/<repo> [<name>] [--tracking=<branch>] [-a]
1717
{self} [--path=<path>] [-v...] <target> request (list|ls)
1818
{self} [--path=<path>] [-v...] <target> request fetch <request> [-f]
19-
{self} [--path=<path>] [-v...] <target> request create <title> [--message=<message>]
20-
{self} [--path=<path>] [-v...] <target> request create <local_branch> <title> [--message=<message>]
21-
{self} [--path=<path>] [-v...] <target> request create <remote_branch> <local_branch> <title> [--message=<message>]
19+
{self} [--path=<path>] [-v...] <target> request create [--title=<title>] [--message=<message>]
20+
{self} [--path=<path>] [-v...] <target> request create <local_branch> [--title=<title>] [--message=<message>]
21+
{self} [--path=<path>] [-v...] <target> request create <remote_branch> <local_branch> [--title=<title>] [--message=<message>]
2222
{self} [--path=<path>] [-v...] <target> request <user>/<repo> (list|ls)
2323
{self} [--path=<path>] [-v...] <target> request <user>/<repo> fetch <request> [-f]
24-
{self} [--path=<path>] [-v...] <target> request <user>/<repo> create <title> [--branch=<remote>] [--message=<message>]
25-
{self} [--path=<path>] [-v...] <target> request <user>/<repo> create <local_branch> <title> [--branch=<remote>] [--message=<message>]
26-
{self} [--path=<path>] [-v...] <target> request <user>/<repo> create <remote_branch> <local_branch> <title> [--branch=<remote>] [--message=<message>]
24+
{self} [--path=<path>] [-v...] <target> request <user>/<repo> create [--title=<title>] [--branch=<remote>] [--message=<message>]
25+
{self} [--path=<path>] [-v...] <target> request <user>/<repo> create <local_branch> [--title=<title>] [--branch=<remote>] [--message=<message>]
26+
{self} [--path=<path>] [-v...] <target> request <user>/<repo> create <remote_branch> <local_branch> [--title=<title>] [--branch=<remote>] [--message=<message>]
2727
{self} [--path=<path>] [-v...] <target> (gist|snippet) (list|ls) [<gist>]
2828
{self} [--path=<path>] [-v...] <target> (gist|snippet) clone <gist>
2929
{self} [--path=<path>] [-v...] <target> (gist|snippet) fetch <gist> [<gist_file>]
@@ -89,7 +89,7 @@
8989
--secret Do not publicize gist when pushing
9090
9191
Options for request:
92-
<title> Title to give to the request for merge
92+
-t,--title=<title> Title to give to the request for merge
9393
-m,--message=<message> Description for the request for merge
9494
9595
Configuration options:
@@ -140,12 +140,18 @@
140140
from .kwargparse import KeywordArgumentParser, store_parameter, register_action
141141

142142
from git import Repo, Git
143-
from git.exc import InvalidGitRepositoryError, NoSuchPathError
143+
from git.exc import InvalidGitRepositoryError, NoSuchPathError, BadName
144144

145145
import re
146146

147147
EXTRACT_URL_RE = re.compile('[^:]*(://|@)[^/]*/')
148148

149+
def loop_input(*args, method=input, **kwarg):
150+
out = ''
151+
while len(out) == 0:
152+
out = method(*args, **kwarg)
153+
return out
154+
149155
def confirm(what, where):
150156
'''
151157
Method to show a CLI based confirmation message, waiting for a yes/no answer.
@@ -154,7 +160,7 @@ def confirm(what, where):
154160
ans = input('Are you sure you want to delete the '
155161
'{} {} from the service?\n[yN]> '.format(what, where))
156162
if 'y' in ans:
157-
ans = input('Are you really sure? there\'s no coming back!\n'
163+
ans = loop_input('Are you really sure? there\'s no coming back!\n'
158164
'[type \'burn!\' to proceed]> ')
159165
if 'burn!' != ans:
160166
return False
@@ -411,18 +417,64 @@ def do_request_list(self):
411417

412418
@register_action('request', 'create')
413419
def do_request_create(self):
420+
def request_edition(repository, from_branch):
421+
try:
422+
commit = repository.commit(from_branch)
423+
title, *body = commit.message.split('\n')
424+
except BadName:
425+
log.error('Couldn\'t find local source branch {}'.format(from_branch))
426+
return None
427+
from tempfile import NamedTemporaryFile
428+
from subprocess import call
429+
with NamedTemporaryFile(
430+
prefix='git-repo-issue-',
431+
suffix='.md',
432+
mode='w+b') as request_file:
433+
request_file.write((
434+
'# Request for Merge Title ##########################\n'
435+
'{}\n'
436+
'\n'
437+
'# Request for Merge Body ###########################\n'
438+
'{}\n'
439+
'####################################################\n'
440+
'## Filled with commit:\n'
441+
'## {}\n'
442+
'####################################################\n'
443+
'## * All lines starting with # will be ignored.\n'
444+
'## * First non-ignored line is the title of the request.\n'
445+
).format(title, '\n'.join(body), commit.name_rev).encode('utf-8'))
446+
request_file.flush()
447+
rv = call("{} {}".format(os.environ['EDITOR'], request_file.name), shell=True)
448+
if rv != 0:
449+
raise ArgumentError("Aborting request, as editor exited abnormally.")
450+
request_file.seek(0)
451+
request_message = map(lambda l: l.decode('utf-8'),
452+
filter(lambda l: not l.strip().startswith(b'#'), request_file.readlines()))
453+
try:
454+
title = next(request_message)
455+
body = ''.join(request_message)
456+
except Exception:
457+
raise ResourceError("Format of the request message cannot be parsed.")
458+
459+
return title, body
460+
461+
414462
service = self.get_service(resolve_targets=('upstream', '{service}', 'origin'))
463+
415464
new_request = service.request_create(self.user_name,
416465
self.repo_name,
417466
self.local_branch,
418467
self.remote_branch,
419468
self.title,
420469
self.message,
421-
self.repo_slug != None)
470+
self.repo_slug != None,
471+
request_edition)
422472
log.info('Successfully created request of `{local}` onto `{}:{remote}`, with id `{ref}`!'.format(
423473
'/'.join([self.user_name, self.repo_name]),
424474
**new_request)
425475
)
476+
if 'url' in new_request:
477+
log.info('available at: {url}'.format(**new_request))
426478
return 0
427479

428480
@register_action('request', 'fetch')
@@ -496,12 +548,6 @@ def do_gist_delete(self):
496548
def do_config(self):
497549
from getpass import getpass
498550

499-
def loop_input(*args, method=input, **kwarg):
500-
out = ''
501-
while len(out) == 0:
502-
out = method(*args, **kwarg)
503-
return out
504-
505551
def setup_service(service):
506552
new_conf = dict(
507553
fqdn=None,

git_repo/services/ext/github.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
log = logging.getLogger('git_repo.github')
55

66
from ..service import register_target, RepositoryService, os
7-
from ...exceptions import ResourceError, ResourceExistsError, ResourceNotFoundError
7+
from ...exceptions import ResourceError, ResourceExistsError, ResourceNotFoundError, ArgumentError
88

99
import github3
1010

@@ -233,7 +233,7 @@ def gist_delete(self, gist_id):
233233
raise ResourceNotFoundError('Could not find gist')
234234
gist.delete()
235235

236-
def request_create(self, user, repo, from_branch, onto_branch, title, description=None, auto_slug=False):
236+
def request_create(self, user, repo, from_branch, onto_branch, title=None, description=None, auto_slug=False, edit=None):
237237
repository = self.gh.repository(user, repo)
238238
if not repository:
239239
raise ResourceNotFoundError('Could not find repository `{}/{}`!'.format(user, repo))
@@ -255,6 +255,10 @@ def request_create(self, user, repo, from_branch, onto_branch, title, descriptio
255255
onto_branch = repository.default_branch or 'master'
256256
if self.username != repository.owner.login:
257257
from_branch = ':'.join([self.username, from_branch])
258+
if not title and not description and edit:
259+
title, description = edit(self.repository, from_branch)
260+
if not title and not description:
261+
raise ArgumentError('Missing message for request creation')
258262
try:
259263
request = repository.create_pull(title,
260264
base=onto_branch,
@@ -276,7 +280,8 @@ def request_create(self, user, repo, from_branch, onto_branch, title, descriptio
276280
raise ResourceError("Unhandled formatting error: {}".format(err.errors))
277281
raise ResourceError(err.message)
278282

279-
return {'local': from_branch, 'remote': onto_branch, 'ref': request.number}
283+
return {'local': from_branch, 'remote': onto_branch, 'ref': request.number,
284+
'url': request.html_url}
280285

281286
def request_list(self, user, repo):
282287
repository = self.gh.repository(user, repo)

git_repo/services/ext/gitlab.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,10 @@ def request_create(self, user, repo, local_branch, remote_branch, title, descrip
275275
repository = self.gl.projects.get('/'.join([user, repo]))
276276
if not repository:
277277
raise ResourceNotFoundError('Could not find repository `{}/{}`!'.format(user, repo))
278+
if not title and not description and edit:
279+
title, description = edit(repository, from_branch)
280+
if not title and not description:
281+
raise ArgumentError('Missing message for request creation')
278282
if not local_branch:
279283
remote_branch = self.repository.active_branch.name or self.repository.active_branch.name
280284
if not remote_branch:

tests/integration/test_github.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,12 @@ def test_32_request_create(self):
311311
title='PR test',
312312
description='PR description',
313313
service='github')
314-
assert r == {'local': 'pr-test', 'ref': 1, 'remote': 'PR test'}
314+
assert r == {
315+
'local': 'pr-test',
316+
'ref': 1,
317+
'remote': 'PR test',
318+
'url': 'https://github.com/ayayayaya/test_create_requests/pull/1',
319+
}
315320

316321
def test_32_request_create__bad_branch(self):
317322
with pytest.raises(ResourceError):

tests/integration/test_main.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,7 @@ def test_request_create(self, capsys, caplog):
415415
'--message': 'This is a test'
416416
})
417417
out, err = capsys.readouterr()
418+
seen_args = seen_args[:-1] # remove the passed edition function
418419
assert ('guyzmo', 'test', 'pr-test', 'base-test', 'This is a test', 'This is a test', True) == seen_args
419420
assert {} == extra_args
420421
assert out == ''
@@ -430,6 +431,7 @@ def test_request_create__no_description(self, capsys, caplog):
430431
'<title>': 'This is a test',
431432
})
432433
out, err = capsys.readouterr()
434+
seen_args = seen_args[:-1] # remove the passed edition function
433435
assert ('guyzmo', 'test', 'pr-test', 'base-test', 'This is a test', None, True) == seen_args
434436
assert {} == extra_args
435437
assert out == ''
@@ -446,6 +448,7 @@ def test_request_create__bad_local_branch(self, capsys, caplog):
446448
'--message': 'This is a test'
447449
})
448450
out, err = capsys.readouterr()
451+
seen_args = seen_args[:-1] # remove the passed edition function
449452
assert ('guyzmo', 'test', 'bad', 'base-test', 'This is a test', 'This is a test', True) == seen_args
450453
assert {} == extra_args
451454
assert out == ''
@@ -462,6 +465,7 @@ def test_request_create__bad_remote_branch(self, capsys, caplog):
462465
'--message': 'This is a test'
463466
})
464467
out, err = capsys.readouterr()
468+
seen_args = seen_args[:-1] # remove the passed edition function
465469
assert ('guyzmo', 'test', 'pr-test', 'bad', 'This is a test', 'This is a test', True) == seen_args
466470
assert {} == extra_args
467471
assert out == ''
@@ -477,6 +481,7 @@ def test_request_create__no_local_branch(self, capsys, caplog):
477481
'--message': 'This is a test'
478482
})
479483
out, err = capsys.readouterr()
484+
seen_args = seen_args[:-1] # remove the passed edition function
480485
assert ('guyzmo', 'test', None, 'base-test', 'This is a test', 'This is a test', True) == seen_args
481486
assert {} == extra_args
482487
assert out == ''
@@ -492,6 +497,7 @@ def test_request_create__no_remote_branch(self, capsys, caplog):
492497
'--message': 'This is a test'
493498
})
494499
out, err = capsys.readouterr()
500+
seen_args = seen_args[:-1] # remove the passed edition function
495501
assert ('guyzmo', 'test', 'pr-test', None, 'This is a test', 'This is a test', True) == seen_args
496502
assert {} == extra_args
497503
assert out == ''
@@ -568,6 +574,7 @@ def test_request_create__no_repo_slug(self, capsys, caplog):
568574
'--message': 'This is a test'
569575
})
570576
out, err = capsys.readouterr()
577+
seen_args = seen_args[:-1] # remove the passed edition function
571578
assert ('guyzmo', 'git-repo', 'pr-test', 'base-test', 'This is a test', 'This is a test', True) == seen_args
572579
assert {} == extra_args
573580
assert out == ''

0 commit comments

Comments
 (0)