From 583734fec36e2782babc646905ab1a900ba8166d Mon Sep 17 00:00:00 2001 From: Guyzmo Date: Fri, 3 Feb 2017 01:29:03 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A7=20Improved=20displaying=20of=20lis?= =?UTF-8?q?ts=20items?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit added a generator logic for displaying lists, that's following this algorithm: - yield the format - yield the header (as tuple matching the format) - yield content line by line (as tuple matching the format) and do not display the header when not sending to a tty and do not display the "cursor display" character voodoo when not sending to a tty. fixes #114 Signed-off-by: Guyzmo --- git_repo/repo.py | 46 ++++------------------ git_repo/services/ext/github.py | 52 +++++++++++-------------- git_repo/services/ext/gitlab.py | 43 +++++++-------------- git_repo/services/ext/gogs.py | 31 +++++---------- git_repo/tools.py | 56 +++++++++++++++++++++++++++ tests/helpers.py | 28 ++++++++------ tests/integration/test_github.py | 65 +++++++++++++++++--------------- tests/integration/test_gitlab.py | 20 ++++++---- tests/integration/test_main.py | 38 ++++++++----------- 9 files changed, 185 insertions(+), 194 deletions(-) create mode 100644 git_repo/tools.py diff --git a/git_repo/repo.py b/git_repo/repo.py index dcfde22..64e03b8 100644 --- a/git_repo/repo.py +++ b/git_repo/repo.py @@ -137,6 +137,7 @@ from .exceptions import ArgumentError, ResourceNotFoundError from .services.service import RepositoryService +from .tools import print_tty, print_iter, loop_input, confirm from .kwargparse import KeywordArgumentParser, store_parameter, register_action from git import Repo, Git @@ -146,28 +147,6 @@ 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. - "what" and "where" are used to better define the message. - ''' - ans = input('Are you sure you want to delete the ' - '{} {} from the service?\n[yN]> '.format(what, where)) - if 'y' in ans: - ans = loop_input('Are you really sure? there\'s no coming back!\n' - '[type \'burn!\' to proceed]> ') - if 'burn!' != ans: - return False - else: - return False - return True - class GitRepoRunner(KeywordArgumentParser): @@ -289,8 +268,7 @@ def store_gitconfig(self, val): @register_action('ls') @register_action('list') def do_list(self): - service = self.get_service(False) - service.list(self.user, self.long) + print_iter(self.get_service(False).list(self.user, self.long)) return 0 @register_action('add') @@ -409,10 +387,8 @@ def do_open(self): @register_action('request', 'list') def do_request_list(self): service = self.get_service(lookup_repository=self.repo_slug == None) - log.info('List of open requests to merge:') - log.info(" {}\t{}\t{}".format('id', 'title'.ljust(60), 'URL')) - for pr in service.request_list(self.user_name, self.repo_name): - print("{}\t{}\t{}".format(pr[0].rjust(3), pr[1][:60].ljust(60), pr[2])) + print_tty('List of open requests to merge:') + print_iter(service.request_list(self.user_name, self.repo_name)) return 0 @register_action('request', 'create') @@ -494,16 +470,7 @@ def do_request_fetch(self): @register_action('snippet', 'list') def do_gist_list(self): service = self.get_service(lookup_repository=False) - if 'github' == service.name and self.gist_ref: - log.info("{:15}\t{:>7}\t{}".format('language', 'size', 'name')) - else: - log.info("{:56}\t{}".format('id', 'title'.ljust(60))) - if self.gist_ref: - for gist_file in service.gist_list(self.gist_ref): - print("{:15}\t{:7}\t{}".format(*gist_file)) - else: - for gist in service.gist_list(): - print( "{:56}\t{}".format(gist[0], gist[1])) + print_iter(service.gist_list(self.gist_ref or None)) return 0 @register_action('gist', 'clone') @@ -638,7 +605,8 @@ def cli(): #pragma: no cover sys.exit(main(docopt(__doc__.format(self=sys.argv[0].split('/')[-1], version=__version__)))) finally: # Whatever happens, make sure that the cursor reappears with some ANSI voodoo - sys.stdout.write('\033[?25h') + if sys.stdout.isatty(): + sys.stdout.write('\033[?25h') if __name__ == '__main__': #pragma: no cover cli() diff --git a/git_repo/services/ext/github.py b/git_repo/services/ext/github.py index b5840c1..329a565 100644 --- a/git_repo/services/ext/github.py +++ b/git_repo/services/ext/github.py @@ -5,11 +5,14 @@ from ..service import register_target, RepositoryService, os from ...exceptions import ResourceError, ResourceExistsError, ResourceNotFoundError, ArgumentError +from ...tools import columnize import github3 from git.exc import GitCommandError +from datetime import datetime + @register_target('hub', 'github') class GithubService(RepositoryService): fqdn = 'github.com' @@ -75,37 +78,18 @@ def delete(self, repo, user=None): raise ResourceError('Unhandled exception: {}'.format(err)) from err def list(self, user, _long=False): - import shutil, sys - from datetime import datetime - term_width = shutil.get_terminal_size((80, 20)).columns - def col_print(lines, indent=0, pad=2): - # prints a list of items in a fashion similar to the dir command - # borrowed from https://gist.github.com/critiqjo/2ca84db26daaeb1715e1 - n_lines = len(lines) - if n_lines == 0: - return - col_width = max(len(line) for line in lines) - n_cols = int((term_width + pad - indent)/(col_width + pad)) - n_cols = min(n_lines, max(1, n_cols)) - col_len = int(n_lines/n_cols) + (0 if n_lines % n_cols == 0 else 1) - if (n_cols - 1) * col_len >= n_lines: - n_cols -= 1 - cols = [lines[i*col_len : i*col_len + col_len] for i in range(n_cols)] - rows = list(zip(*cols)) - rows_missed = zip(*[col[len(rows):] for col in cols[:-1]]) - rows.extend(rows_missed) - for row in rows: - print(" "*indent + (" "*pad).join(line.ljust(col_width) for line in row)) - if not self.gh.user(user): raise ResourceNotFoundError("User {} does not exists.".format(user)) repositories = self.gh.iter_user_repos(user) if not _long: - repositories = list(repositories) - col_print(["/".join([user, repo.name]) for repo in repositories]) + repositories = list(["/".join([user, repo.name]) for repo in repositories]) + yield "{}" + yield "Total repositories: {}".format(len(repositories)) + yield from columnize(repositories) else: - print('Status\tCommits\tReqs\tIssues\tForks\tCoders\tWatch\tLikes\tLang\tModif\t\tName', file=sys.stderr) + yield "{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t\t{}" + yield ['Status', 'Commits', 'Reqs', 'Issues', 'Forks', 'Coders', 'Watch', 'Likes', 'Lang', 'Modif', 'Name'] for repo in repositories: try: if repo.updated_at.year < datetime.now().year: @@ -119,7 +103,7 @@ def col_print(lines, indent=0, pad=2): ]) nb_pulls = len(list(repo.iter_pulls())) nb_issues = len(list(repo.iter_issues())) - nb_pulls - print('\t'.join([ + yield [ # status status, # stats @@ -134,10 +118,10 @@ def col_print(lines, indent=0, pad=2): repo.language or '?', # language repo.updated_at.strftime(date_fmt), # date '/'.join([user, repo.name]), # name - ])) + ] except Exception as err: if 'Git Repository is empty.' == err.args[0].json()['message']: - print('\t'.join([ + yield [ # status 'E', # stats @@ -152,7 +136,7 @@ def col_print(lines, indent=0, pad=2): '?', # language repo.updated_at.strftime(date_fmt), # date '/'.join([user, repo.name]), # name - ])) + ] else: print("Cannot show repository {}: {}".format('/'.join([user, repo.name]), err)) @@ -167,12 +151,16 @@ def _format_gist(self, gist): def gist_list(self, gist=None): if not gist: + yield "{:45.45} {}" + yield 'title', 'url' for gist in self.gh.iter_gists(self.gh.user().login): - yield (gist.html_url, gist.description) + yield gist.description, gist.html_url else: gist = self.gh.gist(self._format_gist(gist)) if gist is None: raise ResourceNotFoundError('Gist does not exists.') + yield "{:15}\t{:7}\t{}" + yield 'language', 'size', 'name' for gist_file in gist.iter_files(): yield (gist_file.language if gist_file.language else 'Raw text', gist_file.size, @@ -285,8 +273,10 @@ def request_create(self, user, repo, from_branch, onto_branch, title=None, descr def request_list(self, user, repo): repository = self.gh.repository(user, repo) + yield "{}\t{:<60}\t{}" + yield 'id', 'title', 'URL' for pull in repository.iter_pulls(): - yield ( str(pull.number), pull.title, pull.links['html'] ) + yield str(pull.number), pull.title, pull.links['html'] def request_fetch(self, user, repo, request, pull=False, force=False): if pull: diff --git a/git_repo/services/ext/gitlab.py b/git_repo/services/ext/gitlab.py index 74d7e37..6e52aab 100644 --- a/git_repo/services/ext/gitlab.py +++ b/git_repo/services/ext/gitlab.py @@ -5,6 +5,7 @@ from ..service import register_target, RepositoryService from ...exceptions import ArgumentError, ResourceError, ResourceExistsError, ResourceNotFoundError +from ...tools import columnize import gitlab from gitlab.exceptions import GitlabListError, GitlabCreateError, GitlabGetError @@ -74,37 +75,17 @@ def delete(self, repo, user=None): raise ResourceError("Unhandled exception: {}".format(err)) from err def list(self, user, _long=False): - import shutil, sys - from datetime import datetime - term_width = shutil.get_terminal_size((80, 20)).columns - def col_print(lines, indent=0, pad=2): - # prints a list of items in a fashion similar to the dir command - # borrowed from https://gist.github.com/critiqjo/2ca84db26daaeb1715e1 - n_lines = len(lines) - if n_lines == 0: - return - col_width = max(len(line) for line in lines) - n_cols = int((term_width + pad - indent)/(col_width + pad)) - n_cols = min(n_lines, max(1, n_cols)) - col_len = int(n_lines/n_cols) + (0 if n_lines % n_cols == 0 else 1) - if (n_cols - 1) * col_len >= n_lines: - n_cols -= 1 - cols = [lines[i*col_len : i*col_len + col_len] for i in range(n_cols)] - rows = list(zip(*cols)) - rows_missed = zip(*[col[len(rows):] for col in cols[:-1]]) - rows.extend(rows_missed) - for row in rows: - print(" "*indent + (" "*pad).join(line.ljust(col_width) for line in row)) - if not self.gl.users.search(user): raise ResourceNotFoundError("User {} does not exists.".format(user)) repositories = self.gl.projects.list(author=user) if not _long: - repositories = list(repositories) - col_print([repo.path_with_namespace for repo in repositories]) + repositories = list([repo.path_with_namespace for repo in repositories]) + yield "{}" + yield "Total repositories: {}".format(len(repositories)) + yield from columnize(repositories) else: - print('Status\tCommits\tReqs\tIssues\tForks\tCoders\tWatch\tLikes\tLang\tModif\t\tName', file=sys.stderr) + yield ['Status', 'Commits', 'Reqs', 'Issues', 'Forks', 'Coders', 'Watch', 'Likes', 'Lang', 'Modif\t', 'Name'] for repo in repositories: time.sleep(0.5) # if repo.last_activity_at.year < datetime.now().year: @@ -116,7 +97,7 @@ def col_print(lines, indent=0, pad=2): 'F' if False else ' ', # is a fork? 'P' if repo.visibility_level == 0 else ' ', # is private? ]) - print('\t'.join([ + yield [ # status status, # stats @@ -131,7 +112,7 @@ def col_print(lines, indent=0, pad=2): 'N.A.', # language repo.last_activity_at, # date repo.name_with_namespace, # name - ])) + ] def get_repository(self, user, repo): try: @@ -163,10 +144,12 @@ def _deconstruct_snippet_uri(self, uri): return (user, project_name, snippet_id) def gist_list(self, project=None): + yield "{:45.45} {}" + yield 'title', 'url' if not project: try: for snippet in self.gl.snippets.list(): - yield (snippet.web_url, snippet.title) + yield snippet.title, snippet.web_url except GitlabListError as err: if err.response_code == 404: raise ResourceNotFoundError('Feature not available, please upgrade your gitlab instance.') from err @@ -177,7 +160,7 @@ def gist_list(self, project=None): try: project = self.gl.projects.get(project) for snippet in project.snippets.list(): - yield (snippet.web_url, 0, snippet.title) + yield (snippet.web_url, snippet.title) except GitlabGetError as err: raise ResourceNotFoundError('Could not retrieve project "{}".'.format(project)) from err @@ -303,6 +286,8 @@ def request_create(self, user, repo, local_branch, remote_branch, title, descrip def request_list(self, user, repo): project = self.gl.projects.get('/'.join([user, repo])) + yield "{:>3}\t{:<60}\t{:2}" + yield ('id', 'title', 'URL') for mr in self.gl.project_mergerequests.list(project_id=project.id): yield ( str(mr.iid), mr.title, diff --git a/git_repo/services/ext/gogs.py b/git_repo/services/ext/gogs.py index e275bf4..975d417 100644 --- a/git_repo/services/ext/gogs.py +++ b/git_repo/services/ext/gogs.py @@ -5,10 +5,12 @@ from ..service import register_target, RepositoryService, os from ...exceptions import ResourceError, ResourceExistsError, ResourceNotFoundError +from ...tools import columnize from gogs_client import GogsApi, GogsRepo, Token, UsernamePassword, ApiFailure from requests import Session, HTTPError from urllib.parse import urlparse, urlunparse +from datetime import datetime import functools from git import config as git_config @@ -152,32 +154,17 @@ def list(self, user, _long=False): import shutil, sys from datetime import datetime term_width = shutil.get_terminal_size((80, 20)).columns - def col_print(lines, indent=0, pad=2): - # prints a list of items in a fashion similar to the dir command - # borrowed from https://gist.github.com/critiqjo/2ca84db26daaeb1715e1 - n_lines = len(lines) - if n_lines == 0: - return - col_width = max(len(line) for line in lines) - n_cols = int((term_width + pad - indent)/(col_width + pad)) - n_cols = min(n_lines, max(1, n_cols)) - col_len = int(n_lines/n_cols) + (0 if n_lines % n_cols == 0 else 1) - if (n_cols - 1) * col_len >= n_lines: - n_cols -= 1 - cols = [lines[i*col_len : i*col_len + col_len] for i in range(n_cols)] - rows = list(zip(*cols)) - rows_missed = zip(*[col[len(rows):] for col in cols[:-1]]) - rows.extend(rows_missed) - for row in rows: - print(" "*indent + (" "*pad).join(line.ljust(col_width) for line in row)) repositories = self.gg.repositories(user) if user != self.username and not repositories and user not in self.orgs: raise ResourceNotFoundError("Unable to list namespace {} - only authenticated user and orgs available for listing.".format(user)) if not _long: - col_print([repo['full_name'] for repo in repositories]) + repositories = list([repo['full_name'] for repo in repositories]) + yield "{}" + yield "Total repositories: {}".format(len(repositories)) + yield from columnize(repositories) else: - print('Status\tCommits\tReqs\tIssues\tForks\tCoders\tWatch\tLikes\tLang\tModif\t\t\t\tName', file=sys.stderr) + yield ['Status', 'Commits', 'Reqs', 'Issues', 'Forks', 'Coders', 'Watch', 'Likes', 'Lang', 'Modif\t', 'Name'] for repo in repositories: status = ''.join([ 'F' if repo['fork'] else ' ', # is a fork? @@ -187,7 +174,7 @@ def col_print(lines, indent=0, pad=2): issues = self.gg._check_ok(self.gg._get('/repos/{}/issues'.format(repo['full_name']), auth=self.auth)).json() except Exception: issues = [] - print('\t'.join([ + yield [ # status status, # stats @@ -202,7 +189,7 @@ def col_print(lines, indent=0, pad=2): repo.get('language') or '?', # language repo['updated_at'], # date repo['full_name'], # name - ])) + ] def get_repository(self, user, repo): try: diff --git a/git_repo/tools.py b/git_repo/tools.py new file mode 100644 index 0000000..ef021ee --- /dev/null +++ b/git_repo/tools.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python + +import sys +import shutil + +def print_tty(*args, **kwarg): + if sys.stdout.isatty(): + print(*args, **kwarg) + +def print_iter(generator): + fmt = next(generator) + print_tty(fmt.format(*next(generator))) + for item in generator: + print(fmt.format(*item)) + +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. + "what" and "where" are used to better define the message. + ''' + ans = input('Are you sure you want to delete the ' + '{} {} from the service?\n[yN]> '.format(what, where)) + if 'y' in ans: + ans = loop_input('Are you really sure? there\'s no coming back!\n' + '[type \'burn!\' to proceed]> ') + if 'burn!' != ans: + return False + else: + return False + return True + +def columnize(lines, indent=0, pad=2): + term_width = shutil.get_terminal_size((80, 20)).columns + # prints a list of items in a fashion similar to the dir command + # borrowed from https://gist.github.com/critiqjo/2ca84db26daaeb1715e1 + n_lines = len(lines) + if n_lines == 0: + return + col_width = max(len(line) for line in lines) + n_cols = int((term_width + pad - indent)/(col_width + pad)) + n_cols = min(n_lines, max(1, n_cols)) + col_len = int(n_lines/n_cols) + (0 if n_lines % n_cols == 0 else 1) + if (n_cols - 1) * col_len >= n_lines: + n_cols -= 1 + cols = [lines[i*col_len : i*col_len + col_len] for i in range(n_cols)] + rows = list(zip(*cols)) + rows_missed = zip(*[col[len(rows):] for col in cols[:-1]]) + rows.extend(rows_missed) + for row in rows: + yield [" "*indent + (" "*pad).join(line.ljust(col_width) for line in row)] diff --git a/tests/helpers.py b/tests/helpers.py index d43fe92..648231c 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -93,17 +93,21 @@ def fork(self, *args, **kwarg): def gist_list(self, *args, **kwarg): self._did_gist_list = (args, kwarg) - if len(args) == 0: - return [('id1', 'value1'), - ('id2', 'value2'), - ('id3', 'value3')] + if len(args) == 0 or not args[0]: + yield '{} {}' + yield 'title', 'url' + yield 'id1', 'value1' + yield 'id2', 'value2' + yield 'id3', 'value3' elif len(args) == 1: if args[0] == 'bad': raise Exception('bad gist!') else: - return [('lang1', 'size1', 'name1'), - ('lang2', 'size2', 'name2'), - ('lang3', 'size3', 'name3')] + yield '{} {} {}' + yield 'language', 'size', 'name' + yield 'lang1', 'size1', 'name1' + yield 'lang2', 'size2', 'name2' + yield 'lang3', 'size3', 'name3' def gist_fetch(self, *args, **kwarg): self._did_gist_fetch = (args, kwarg) @@ -132,9 +136,11 @@ def gist_delete(self, *args, **kwarg): def request_list(self, *args, **kwarg): self._did_request_list = (args, kwarg) - return [('1', 'desc1', 'http://request/1'), - ('2', 'desc2', 'http://request/2'), - ('3', 'desc3', 'http://request/3')] + yield '{} {} {}' + yield ('id', 'description', 'URL') + yield ('1', 'desc1', 'http://request/1') + yield ('2', 'desc2', 'http://request/2') + yield ('3', 'desc3', 'http://request/3') def request_fetch(self, *args, **kwarg): self._did_request_fetch = (args, kwarg) @@ -610,7 +616,7 @@ def action_add(self, namespace, repository, alone=False, name=None, tracking='ma def action_list(self, namespace, _long=False): with self.recorder.use_cassette(self._make_cassette_name()): self.service.connect() - self.service.list(namespace, _long=_long) + return list(self.service.list(namespace, _long=_long)) def action_request_list(self, namespace, repository, rq_list_data=[]): with self.recorder.use_cassette(self._make_cassette_name()): diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index 0cf90cc..0aa4688 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -116,28 +116,30 @@ def test_12_add__alone_default_name(self): def test_13_gist_list(self): g_list = [ - ("https://gist.github.com/a7ce4fddba7744ddf335", "unicode combined class for better character counting and indexing"), - ("https://gist.github.com/7e5a12bc158a79966020", "avr-gcc derivation build"), - ("https://gist.github.com/dd9ab22c8f22a5a8f3d1", "avr-gcc derivation"), - ("https://gist.github.com/893fbc98bf1c9cf6212a", "`brew cask install mplabx` fixed"), - ("https://gist.github.com/9baed8712a16a29c2e90", "`brew cask install mplabx` issue with target in /usr/local/mplabx"), - ("https://gist.github.com/1c03ddfdc8f57fa7919a", "cask formula for mplabx (stripped down)"), - ("https://gist.github.com/21949a3fa5f981a869bf", "`brew cask install mplabx` issue removing the caskroom dir!"), - ("https://gist.github.com/588deedefc1675998bbe", "cask formula for mplabx"), - ("https://gist.github.com/281502e4ae6fce01db92", "TaskJuggler example"), - ("https://gist.github.com/06c5b0da8d10c514166f", "redmine to taskjuggler recursive func"), - ("https://gist.github.com/603ccdd0f504c63cd0df", "Simple example of Flask/Presst with Login and Principals (not working!)"), - ("https://gist.github.com/2482962b153ebd5cfa6b", "radial colour picker crash"), - ("https://gist.github.com/fc46896f3e604269ff93", "Platform levelling GCode file"), - ("https://gist.github.com/3b18193d6bea07bac37c", "Code to download movies from pluzz"), - ("https://gist.github.com/c01613d0453df275622a", ""), - ("https://gist.github.com/10118958", "I2C scanner code for SL030"), - ("https://gist.github.com/5b79437ddd3f49491ce3", ""), - ("https://gist.github.com/5730750", "An enhanced implementation of authenticating to stackoverflow using python."), - ("https://gist.github.com/4308707", "Patch to be applied for homebrew's strigi.rb Formula."), - ("https://gist.github.com/4170462", "Patch for strnlen support in freevpn (for OSX 10.6)"), - ("https://gist.github.com/3666086", "z.sh patch for multiline quotes"), - ("https://gist.github.com/2788003", "A Tornado-based library that enables Event Source support !"), + '{:45.45} {}', + ("title", "url"), + ("unicode combined class for better character counting and indexing", "https://gist.github.com/a7ce4fddba7744ddf335" ) , + ("avr-gcc derivation build", "https://gist.github.com/7e5a12bc158a79966020" ) , + ("avr-gcc derivation", "https://gist.github.com/dd9ab22c8f22a5a8f3d1" ) , + ("`brew cask install mplabx` fixed", "https://gist.github.com/893fbc98bf1c9cf6212a" ) , + ("`brew cask install mplabx` issue with target in /usr/local/mplabx", "https://gist.github.com/9baed8712a16a29c2e90" ) , + ("cask formula for mplabx (stripped down)", "https://gist.github.com/1c03ddfdc8f57fa7919a" ) , + ("`brew cask install mplabx` issue removing the caskroom dir!", "https://gist.github.com/21949a3fa5f981a869bf" ) , + ("cask formula for mplabx", "https://gist.github.com/588deedefc1675998bbe" ) , + ("TaskJuggler example", "https://gist.github.com/281502e4ae6fce01db92" ) , + ("redmine to taskjuggler recursive func", "https://gist.github.com/06c5b0da8d10c514166f" ) , + ("Simple example of Flask/Presst with Login and Principals (not working!)", "https://gist.github.com/603ccdd0f504c63cd0df" ) , + ("radial colour picker crash", "https://gist.github.com/2482962b153ebd5cfa6b" ) , + ("Platform levelling GCode file", "https://gist.github.com/fc46896f3e604269ff93" ) , + ("Code to download movies from pluzz", "https://gist.github.com/3b18193d6bea07bac37c" ) , + ("", "https://gist.github.com/c01613d0453df275622a" ) , + ("I2C scanner code for SL030", "https://gist.github.com/10118958" ) , + ("", "https://gist.github.com/5b79437ddd3f49491ce3" ) , + ("An enhanced implementation of authenticating to stackoverflow using python.", "https://gist.github.com/5730750" ) , + ("Patch to be applied for homebrew's strigi.rb Formula.", "https://gist.github.com/4308707" ) , + ("Patch for strnlen support in freevpn (for OSX 10.6)", "https://gist.github.com/4170462" ) , + ("z.sh patch for multiline quotes", "https://gist.github.com/3666086" ) , + ("A Tornado-based library that enables Event Source support !", "https://gist.github.com/2788003" ) , ] self.action_gist_list(gist_list_data=g_list) @@ -284,6 +286,8 @@ def test_30_request_list(self): namespace='guyzmo', repository='git-repo', rq_list_data=[ + '{}\t{:<60}\t{}', + ('id', 'title', 'URL'), ('3', 'docs for fqdn > url', 'https://github.com/guyzmo/git-repo/pull/3'), ('2', 'prefer gitrepo..token > privatekey, docs', 'https://github.com/guyzmo/git-repo/pull/2'), ]) @@ -348,17 +352,16 @@ def test_33_open(self): self.action_open(namespace='guyzmo', repository='git-repo') - def test_34_list__short(self, capsys, caplog): - self.action_list(namespace='git-repo-test') - out, err = capsys.readouterr() - assert out == 'git-repo-test/git-repo\n' + def test_34_list__short(self, caplog): + projects = self.action_list(namespace='git-repo-test') + assert projects == ['{}', 'Total repositories: 1', ['git-repo-test/git-repo']] assert 'GET https://api.github.com/users/git-repo-test/repos' in caplog.text - def test_34_list__long(self, capsys, caplog): - self.action_list(namespace='git-repo-test', _long=True) - out, err = capsys.readouterr() - assert err.replace('\t', ' ') == "Status Commits Reqs Issues Forks Coders Watch Likes Lang Modif Name\n" - assert out.replace('\t', ' ') == "F 92 0 0 0 1 0 0 Python Mar 30 2016 git-repo-test/git-repo\n" + def test_34_list__long(self, caplog): + projects = self.action_list(namespace='git-repo-test', _long=True) + assert projects == ['{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t\t{}', + ['Status', 'Commits', 'Reqs', 'Issues', 'Forks', 'Coders', 'Watch', 'Likes', 'Lang', 'Modif', 'Name'], + ['F ', '92', '0', '0', '0', '1', '0', '0', 'Python', 'Mar 30 2016', 'git-repo-test/git-repo']] assert 'GET https://api.github.com/users/git-repo-test/repos' in caplog.text diff --git a/tests/integration/test_gitlab.py b/tests/integration/test_gitlab.py index 698cd8d..42370c4 100644 --- a/tests/integration/test_gitlab.py +++ b/tests/integration/test_gitlab.py @@ -115,14 +115,16 @@ def test_12_add__alone_default_name(self): def test_13_snippet_list_alone(self): namespace = os.environ.get('GITLAB_NAMESPACE', 'bogus') s_list = [ - ('https://gitlab.com/snippets/34124', 'this is a secret test.'), - ('https://gitlab.com/snippets/34121', 'this is a test.'), - ('https://gitlab.com/{}/git-repo/snippets/32318'.format(namespace), 'this is a test.'), - ('https://gitlab.com/{}/git-repo/snippets/32317'.format(namespace), 'this is a secret test.'), - ('https://gitlab.com/{}/git-repo/snippets/32316'.format(namespace), 'this is a test.'), - ('https://gitlab.com/{}/git-repo/snippets/32303'.format(namespace), 'requirements.txt'), - ('https://gitlab.com/{}/git-repo/snippets/26173'.format(namespace), 'test'), - ('https://gitlab.com/snippets/20696', 'test') + '{:45.45} {}', + ("title", "url"), + ('this is a secret test.', 'https://gitlab.com/snippets/34124', ) , + ('this is a test.', 'https://gitlab.com/snippets/34121', ) , + ('this is a test.', 'https://gitlab.com/{}/git-repo/snippets/32318'.format(namespace), ) , + ('this is a secret test.', 'https://gitlab.com/{}/git-repo/snippets/32317'.format(namespace), ) , + ('this is a test.', 'https://gitlab.com/{}/git-repo/snippets/32316'.format(namespace), ) , + ('requirements.txt', 'https://gitlab.com/{}/git-repo/snippets/32303'.format(namespace), ) , + ('test', 'https://gitlab.com/{}/git-repo/snippets/26173'.format(namespace), ) , + ('test', 'https://gitlab.com/snippets/20696', ) ] self.action_gist_list(gist_list_data=s_list) @@ -230,6 +232,8 @@ def test_18_request_list(self): namespace='git-repo-test', repository='git-repo', rq_list_data=[ + '{:>3}\t{:<60}\t{:2}', + ('id', 'title', 'URL'), ('1', 'Adding gitlab gists and requests feature', 'https://gitlab.com/git-repo-test/git-repo/merge_requests/1'), ]) diff --git a/tests/integration/test_main.py b/tests/integration/test_main.py index 4afd9d4..b50784a 100644 --- a/tests/integration/test_main.py +++ b/tests/integration/test_main.py @@ -173,40 +173,36 @@ def test_fork__branch_clone(self): def test_gist_list(self, capsys, caplog): did_list = self.main_gist_list(0, args={}) out, err = capsys.readouterr() - assert did_list == ((), {}) - assert 'id' in caplog.text and 'title' in caplog.text + assert did_list == ((None,), {}) assert out == ''.join([ - 'id1 \tvalue1\n', - 'id2 \tvalue2\n', - 'id3 \tvalue3\n' + 'id1 value1\n', + 'id2 value2\n', + 'id3 value3\n' ]) def test_gist_ls(self, capsys, caplog): did_list = self.main_gist_ls(0, args={}) out, err = capsys.readouterr() - assert did_list == ((), {}) - assert 'id' in caplog.text and 'title' in caplog.text + assert did_list == ((None,), {}) assert out == ''.join([ - 'id1 \tvalue1\n', - 'id2 \tvalue2\n', - 'id3 \tvalue3\n' + 'id1 value1\n', + 'id2 value2\n', + 'id3 value3\n' ]) def test_gist_list__with_gist(self, capsys, caplog): did_list = self.main_gist_list(0, args={'': 'foobar'}) out, err = capsys.readouterr() assert did_list == (('foobar',), {}) - assert 'language' in caplog.text and 'size' in caplog.text and 'name' in caplog.text assert out == ''.join([ - 'lang1 \tsize1 \tname1\n', - 'lang2 \tsize2 \tname2\n', - 'lang3 \tsize3 \tname3\n' + 'lang1 size1 name1\n', + 'lang2 size2 name2\n', + 'lang3 size3 name3\n' ]) def test_gist_list__with_bad_gist(self, caplog): did_list = self.main_gist_list(2, args={'': 'bad', '--verbose': 0}) assert did_list == (('bad',), {}) - assert 'language \t size\tname' in caplog.text assert 'Fatal error: bad gist!' in caplog.text def test_gist_clone__with_gist(self, caplog): @@ -303,14 +299,12 @@ def test_request_list(self, capsys, caplog): call(['git', 'init', '-q', self.tempdir.name]) repo_slug, seen_args = self.main_request_list('guyzmo/git-repo', 0, args={}) out, err = capsys.readouterr() - assert out == ' 1\tdesc1 \thttp://request/1\n 2\tdesc2 \thttp://request/2\n 3\tdesc3 \thttp://request/3\n' - assert 'id' in caplog.text and 'title' in caplog.text and 'URL' in caplog.text + assert out == '1 desc1 http://request/1\n2 desc2 http://request/2\n3 desc3 http://request/3\n' def test_request_list__with_repo_slug__no_repo(self, capsys, caplog): repo_slug, seen_args = self.main_request_list('guyzmo/git-repo', 0, args={}) out, err = capsys.readouterr() - assert out == ' 1\tdesc1 \thttp://request/1\n 2\tdesc2 \thttp://request/2\n 3\tdesc3 \thttp://request/3\n' - assert 'id' in caplog.text and 'title' in caplog.text and 'URL' in caplog.text + assert out == '1 desc1 http://request/1\n2 desc2 http://request/2\n3 desc3 http://request/3\n' # Commented out because this does not work on travis CI # def test_request_list__no_repo_slug__git(self, capsys, caplog): @@ -332,8 +326,7 @@ def test_request_list__no_repo_slug__https(self, capsys, caplog): assert ('guyzmo', 'git-repo') == repo_slug assert dict() == seen_args out, err = capsys.readouterr() - assert out == ' 1\tdesc1 \thttp://request/1\n 2\tdesc2 \thttp://request/2\n 3\tdesc3 \thttp://request/3\n' - assert 'id' in caplog.text and 'title' in caplog.text and 'URL' in caplog.text + assert out == '1 desc1 http://request/1\n2 desc2 http://request/2\n3 desc3 http://request/3\n' def test_request_list__no_repo_slug__https_dot_git_fix__issue55(self): from subprocess import call @@ -551,8 +544,7 @@ def test_request_list__no_repo_slug(self, capsys, caplog): self._create_repository(ro=True) repo_slug, seen_args = self.main_request_list(rc=0, args={}) out, err = capsys.readouterr() - assert out == ' 1\tdesc1 \thttp://request/1\n 2\tdesc2 \thttp://request/2\n 3\tdesc3 \thttp://request/3\n' - assert 'id' in caplog.text and 'title' in caplog.text and 'URL' in caplog.text + assert out == '1 desc1 http://request/1\n2 desc2 http://request/2\n3 desc3 http://request/3\n' def test_request_fetch__no_repo_slug(self, capsys, caplog): self._create_repository(ro=True)