Skip to content

Commit

Permalink
🚧 request editor with latest commit's message as defaults
Browse files Browse the repository at this point in the history
Signed-off-by: Guyzmo <[email protected]>
  • Loading branch information
guyzmo committed Feb 2, 2017
1 parent 9542185 commit 244d189
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 20 deletions.
78 changes: 62 additions & 16 deletions git_repo/repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
{self} [--path=<path>] [-v...] <target> add <user>/<repo> [<name>] [--tracking=<branch>] [-a]
{self} [--path=<path>] [-v...] <target> request (list|ls)
{self} [--path=<path>] [-v...] <target> request fetch <request> [-f]
{self} [--path=<path>] [-v...] <target> request create <title> [--message=<message>]
{self} [--path=<path>] [-v...] <target> request create <local_branch> <title> [--message=<message>]
{self} [--path=<path>] [-v...] <target> request create <remote_branch> <local_branch> <title> [--message=<message>]
{self} [--path=<path>] [-v...] <target> request create [--title=<title>] [--message=<message>]
{self} [--path=<path>] [-v...] <target> request create <local_branch> [--title=<title>] [--message=<message>]
{self} [--path=<path>] [-v...] <target> request create <remote_branch> <local_branch> [--title=<title>] [--message=<message>]
{self} [--path=<path>] [-v...] <target> request <user>/<repo> (list|ls)
{self} [--path=<path>] [-v...] <target> request <user>/<repo> fetch <request> [-f]
{self} [--path=<path>] [-v...] <target> request <user>/<repo> create <title> [--branch=<remote>] [--message=<message>]
{self} [--path=<path>] [-v...] <target> request <user>/<repo> create <local_branch> <title> [--branch=<remote>] [--message=<message>]
{self} [--path=<path>] [-v...] <target> request <user>/<repo> create <remote_branch> <local_branch> <title> [--branch=<remote>] [--message=<message>]
{self} [--path=<path>] [-v...] <target> request <user>/<repo> create [--title=<title>] [--branch=<remote>] [--message=<message>]
{self} [--path=<path>] [-v...] <target> request <user>/<repo> create <local_branch> [--title=<title>] [--branch=<remote>] [--message=<message>]
{self} [--path=<path>] [-v...] <target> request <user>/<repo> create <remote_branch> <local_branch> [--title=<title>] [--branch=<remote>] [--message=<message>]
{self} [--path=<path>] [-v...] <target> (gist|snippet) (list|ls) [<gist>]
{self} [--path=<path>] [-v...] <target> (gist|snippet) clone <gist>
{self} [--path=<path>] [-v...] <target> (gist|snippet) fetch <gist> [<gist_file>]
Expand Down Expand Up @@ -89,7 +89,7 @@
--secret Do not publicize gist when pushing
Options for request:
<title> Title to give to the request for merge
-t,--title=<title> Title to give to the request for merge
-m,--message=<message> Description for the request for merge
Configuration options:
Expand Down Expand Up @@ -140,12 +140,18 @@
from .kwargparse import KeywordArgumentParser, store_parameter, register_action

from git import Repo, Git
from git.exc import InvalidGitRepositoryError, NoSuchPathError
from git.exc import InvalidGitRepositoryError, NoSuchPathError, BadName

import re

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

def loop_input(*args, method=input, **kwarg):
out = ''
while len(out) == 0:
out = method(*args, **kwarg)
return out

def confirm(what, where):
'''
Method to show a CLI based confirmation message, waiting for a yes/no answer.
Expand All @@ -154,7 +160,7 @@ def confirm(what, where):
ans = input('Are you sure you want to delete the '
'{} {} from the service?\n[yN]> '.format(what, where))
if 'y' in ans:
ans = input('Are you really sure? there\'s no coming back!\n'
ans = loop_input('Are you really sure? there\'s no coming back!\n'
'[type \'burn!\' to proceed]> ')
if 'burn!' != ans:
return False
Expand Down Expand Up @@ -411,18 +417,64 @@ def do_request_list(self):

@register_action('request', 'create')
def do_request_create(self):
def request_edition(repository, from_branch):
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
from tempfile import NamedTemporaryFile
from subprocess import call
with NamedTemporaryFile(
prefix='git-repo-issue-',
suffix='.md',
mode='w+b') as request_file:
request_file.write((
'# Request for Merge Title ##########################\n'
'{}\n'
'\n'
'# Request for Merge Body ###########################\n'
'{}\n'
'####################################################\n'
'## Filled with commit:\n'
'## {}\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'))
request_file.flush()
rv = call("{} {}".format(os.environ['EDITOR'], request_file.name), shell=True)
if rv != 0:
raise ArgumentError("Aborting request, as editor exited abnormally.")
request_file.seek(0)
request_message = map(lambda l: l.decode('utf-8'),
filter(lambda l: not l.strip().startswith(b'#'), request_file.readlines()))
try:
title = next(request_message)
body = ''.join(request_message)
except Exception:
raise ResourceError("Format of the request message cannot be parsed.")

return title, body


service = self.get_service(resolve_targets=('upstream', '{service}', 'origin'))

new_request = service.request_create(self.user_name,
self.repo_name,
self.local_branch,
self.remote_branch,
self.title,
self.message,
self.repo_slug != None)
self.repo_slug != None,
request_edition)
log.info('Successfully created request of `{local}` onto `{}:{remote}`, with id `{ref}`!'.format(
'/'.join([self.user_name, self.repo_name]),
**new_request)
)
if 'url' in new_request:
log.info('available at: {url}'.format(**new_request))
return 0

@register_action('request', 'fetch')
Expand Down Expand Up @@ -496,12 +548,6 @@ def do_gist_delete(self):
def do_config(self):
from getpass import getpass

def loop_input(*args, method=input, **kwarg):
out = ''
while len(out) == 0:
out = method(*args, **kwarg)
return out

def setup_service(service):
new_conf = dict(
fqdn=None,
Expand Down
11 changes: 8 additions & 3 deletions git_repo/services/ext/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
log = logging.getLogger('git_repo.github')

from ..service import register_target, RepositoryService, os
from ...exceptions import ResourceError, ResourceExistsError, ResourceNotFoundError
from ...exceptions import ResourceError, ResourceExistsError, ResourceNotFoundError, ArgumentError

import github3

Expand Down Expand Up @@ -233,7 +233,7 @@ 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, description=None, auto_slug=False):
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))
Expand All @@ -255,6 +255,10 @@ def request_create(self, user, repo, from_branch, onto_branch, title, descriptio
onto_branch = repository.default_branch or 'master'
if self.username != repository.owner.login:
from_branch = ':'.join([self.username, from_branch])
if not title and not description and edit:
title, description = edit(self.repository, from_branch)
if not title and not description:
raise ArgumentError('Missing message for request creation')
try:
request = repository.create_pull(title,
base=onto_branch,
Expand All @@ -276,7 +280,8 @@ def request_create(self, user, repo, from_branch, onto_branch, title, descriptio
raise ResourceError("Unhandled formatting error: {}".format(err.errors))
raise ResourceError(err.message)

return {'local': from_branch, 'remote': onto_branch, 'ref': request.number}
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)
Expand Down
4 changes: 4 additions & 0 deletions git_repo/services/ext/gitlab.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,10 @@ def request_create(self, user, repo, local_branch, remote_branch, title, descrip
repository = self.gl.projects.get('/'.join([user, repo]))
if not repository:
raise ResourceNotFoundError('Could not find repository `{}/{}`!'.format(user, repo))
if not title and not description and edit:
title, description = edit(repository, from_branch)
if not title and not description:
raise ArgumentError('Missing message for request creation')
if not local_branch:
remote_branch = self.repository.active_branch.name or self.repository.active_branch.name
if not remote_branch:
Expand Down
7 changes: 6 additions & 1 deletion tests/integration/test_github.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,12 @@ def test_32_request_create(self):
title='PR test',
description='PR description',
service='github')
assert r == {'local': 'pr-test', 'ref': 1, 'remote': 'PR test'}
assert r == {
'local': 'pr-test',
'ref': 1,
'remote': 'PR test',
'url': 'https://github.com/ayayayaya/test_create_requests/pull/1',
}

def test_32_request_create__bad_branch(self):
with pytest.raises(ResourceError):
Expand Down
7 changes: 7 additions & 0 deletions tests/integration/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,7 @@ def test_request_create(self, capsys, caplog):
'--message': 'This is a test'
})
out, err = capsys.readouterr()
seen_args = seen_args[:-1] # remove the passed edition function
assert ('guyzmo', 'test', 'pr-test', 'base-test', 'This is a test', 'This is a test', True) == seen_args
assert {} == extra_args
assert out == ''
Expand All @@ -430,6 +431,7 @@ def test_request_create__no_description(self, capsys, caplog):
'<title>': 'This is a test',
})
out, err = capsys.readouterr()
seen_args = seen_args[:-1] # remove the passed edition function
assert ('guyzmo', 'test', 'pr-test', 'base-test', 'This is a test', None, True) == seen_args
assert {} == extra_args
assert out == ''
Expand All @@ -446,6 +448,7 @@ def test_request_create__bad_local_branch(self, capsys, caplog):
'--message': 'This is a test'
})
out, err = capsys.readouterr()
seen_args = seen_args[:-1] # remove the passed edition function
assert ('guyzmo', 'test', 'bad', 'base-test', 'This is a test', 'This is a test', True) == seen_args
assert {} == extra_args
assert out == ''
Expand All @@ -462,6 +465,7 @@ def test_request_create__bad_remote_branch(self, capsys, caplog):
'--message': 'This is a test'
})
out, err = capsys.readouterr()
seen_args = seen_args[:-1] # remove the passed edition function
assert ('guyzmo', 'test', 'pr-test', 'bad', 'This is a test', 'This is a test', True) == seen_args
assert {} == extra_args
assert out == ''
Expand All @@ -477,6 +481,7 @@ def test_request_create__no_local_branch(self, capsys, caplog):
'--message': 'This is a test'
})
out, err = capsys.readouterr()
seen_args = seen_args[:-1] # remove the passed edition function
assert ('guyzmo', 'test', None, 'base-test', 'This is a test', 'This is a test', True) == seen_args
assert {} == extra_args
assert out == ''
Expand All @@ -492,6 +497,7 @@ def test_request_create__no_remote_branch(self, capsys, caplog):
'--message': 'This is a test'
})
out, err = capsys.readouterr()
seen_args = seen_args[:-1] # remove the passed edition function
assert ('guyzmo', 'test', 'pr-test', None, 'This is a test', 'This is a test', True) == seen_args
assert {} == extra_args
assert out == ''
Expand Down Expand Up @@ -568,6 +574,7 @@ def test_request_create__no_repo_slug(self, capsys, caplog):
'--message': 'This is a test'
})
out, err = capsys.readouterr()
seen_args = seen_args[:-1] # remove the passed edition function
assert ('guyzmo', 'git-repo', 'pr-test', 'base-test', 'This is a test', 'This is a test', True) == seen_args
assert {} == extra_args
assert out == ''
Expand Down

0 comments on commit 244d189

Please sign in to comment.