diff --git a/.gitli/.issues b/.gitli/.issues index e6a2f64..419101c 100644 --- a/.gitli/.issues +++ b/.gitli/.issues @@ -15,9 +15,9 @@ add edit command 1 0.1 5 -add post-commit/publish hook when initializing the script to parse commit and automatically close issues... would be cool! +add post-commit hook? 1 -0.2 +0.3 6 more intelligent init... 1 @@ -30,3 +30,11 @@ add documentation add a .gitli directory 1 0.1 +9 +add tests +1 +0.3 +10 +add colorized output +1 +0.2 diff --git a/.gitli/.issues-current b/.gitli/.issues-current index ceab6e1..2f45361 100644 --- a/.gitli/.issues-current +++ b/.gitli/.issues-current @@ -1 +1 @@ -0.1 \ No newline at end of file +0.2 \ No newline at end of file diff --git a/.gitli/.issues-last b/.gitli/.issues-last index 301160a..9a03714 100644 --- a/.gitli/.issues-last +++ b/.gitli/.issues-last @@ -1 +1 @@ -8 \ No newline at end of file +10 \ No newline at end of file diff --git a/.gitli/.issues-open b/.gitli/.issues-open index 7ed6ff8..57877db 100644 --- a/.gitli/.issues-open +++ b/.gitli/.issues-open @@ -1 +1,2 @@ 5 +9 diff --git a/README.rst b/README.rst index 35f6be9..9f788fe 100644 --- a/README.rst +++ b/README.rst @@ -3,7 +3,7 @@ gitli - Git Lightweight Issue Tracking System :Authors: Barthelemy Dagenais -:Version: 0.1 +:Version: 0.2 gitli is a simple git extension to manage issues in single-developer projects. @@ -19,11 +19,17 @@ Don't hesitate to create issues in the github bug tracker if you have a feature request or encounter a bug though. +Requirements +------------ + +This script has been tested on Python 2.6, 2.7, 3.1, and 3.2. + + Installation ------------ -#. Make the git-li script executable (e.g., `chmod a+x git-li`). -#. Add the git-li script to your path (e.g., `export PATH=$PATH:/path/to/git-li`) +#. Make the git-li script executable (e.g., ``chmod a+x git-li``). +#. Add the git-li script to your path (e.g., ``export PATH=$PATH:/path/to/git-li``) #. You are done. Usage @@ -59,7 +65,7 @@ values: Task type: 1-Task, 2-Bug, 3-Enhancement [1]: 2 Milestone: [0.1]: testgitli $ git li -v new 'My Third Issue' - Task type: 1-Task, 2-Bug, 3-Enhancement [1]: 3 + Task type: 1-Task, 2-Bug, 3-Enhancement [1]: 1 Milestone: [0.1]: 0.2 testgitli $ git li new 'My Fourth Issue' @@ -68,10 +74,12 @@ The list command: :: testgitli $ git li list - #1 My First Issue [Task] [0.1] - open - #2 My Second Issue [Bug] [0.1] - open - #3 My Third Issue [Enhancement] [0.2] - open - #4 My Fourth Issue [Task] [0.1] - open + #1 My First Issue [Task] [0.1] - open + #2 My Second Issue [Bug] [0.1] - open + #3 My Third Issue [Task] [0.2] - open + #4 My Fourth Issue [Task] [0.1] - open + +To colorize the output, just enter: ``git config --global add gitli.color auto`` The close command: @@ -79,32 +87,37 @@ The close command: testgitli $ git li close 4 testgitli $ git li list - #1 My First Issue [Task] [0.1] - open - #2 My Second Issue [Bug] [0.1] - open - #3 My Third Issue [Enhancement] [0.2] - open - #4 My Fourth Issue [Task] [0.1] - closed + #1 My First Issue [Task] [0.1] - open + #2 My Second Issue [Bug] [0.1] - open + #3 My Third Issue [Task] [0.2] - open + #4 My Fourth Issue [Task] [0.1] - closed The list command with filters: :: testgitli $ git li list open - #1 My First Issue [Task] [0.1] - open - #2 My Second Issue [Bug] [0.1] - open - #3 My Third Issue [Enhancement] [0.2] - open + #1 My First Issue [Task] [0.1] - open + #2 My Second Issue [Bug] [0.1] - open + #3 My Third Issue [Task] [0.2] - open testgitli $ git li list close - #4 My Fourth Issue [Task] [0.1] - closed + #4 My Fourth Issue [Task] [0.1] - closed testgitli $ git li open bug testgitli $ git li list open bug - #2 My Second Issue [Bug] [0.1] - open + #2 My Second Issue [Bug] [0.1] - open testgitli $ git li list open bug 0.1 - #2 My Second Issue [Bug] [0.1] - open + #2 My Second Issue [Bug] [0.1] - open + +The reopen command: + +:: + testgitli $ git li reopen 4 testgitli $ git li list - #1 My First Issue [Task] [0.1] - open - #2 My Second Issue [Bug] [0.1] - open - #3 My Third Issue [Enhancement] [0.2] - open - #4 My Fourth Issue [Task] [0.1] - open + #1 My First Issue [Task] [0.1] - open + #2 My Second Issue [Bug] [0.1] - open + #3 My Third Issue [Task] [0.2] - open + #4 My Fourth Issue [Task] [0.1] - open Edit an issue (notice the use of default values): @@ -115,10 +128,10 @@ Edit an issue (notice the use of default values): Task type: 1-Task, 2-Bug, 3-Enhancement [3]: 1 Milestone: [0.2]: 0.1 testgitli $ git li list - #1 My First Issue [Task] [0.1] - open - #2 My Second Issue [Bug] [0.1] - open - #3 My Third Issue [Task] [0.1] - open - #4 My Fourth Issue [Task] [0.1] - open + #1 My First Issue [Task] [0.1] - open + #2 My Second Issue [Bug] [0.1] - open + #3 My Third Issue [Task] [0.1] - open + #4 My Fourth Issue [Task] [0.1] - open Update the default milestone: @@ -127,13 +140,18 @@ Update the default milestone: testgitli $ git li milestone 0.2 testgitli $ git li new 'My Fifth Issue' testgitli $ git li list - #1 My First Issue [Task] [0.1] - open - #2 My Second Issue [Bug] [0.1] - open - #3 My Third Issue [Task] [0.1] - open - #4 My Fourth Issue [Task] [0.1] - open - #5 My Fifth Issue [Task] [0.2] - open + #1 My First Issue [Task] [0.1] - open + #2 My Second Issue [Bug] [0.1] - open + #3 My Third Issue [Task] [0.1] - open + #4 My Fourth Issue [Task] [0.1] - open + #5 My Fifth Issue [Task] [0.2] - open + +The show command: + +:: + testgitli $ git li show 5 - #5 My Fifth Issue [Task] [0.2] - open + #5 My Fifth Issue [Task] [0.2] - open License diff --git a/git-li b/git-li index c040868..55c1db8 100755 --- a/git-li +++ b/git-li @@ -1,11 +1,20 @@ #!/usr/bin/env python # coding: utf-8 + +# For python 2 compatibility +from __future__ import unicode_literals import optparse import sys from os.path import split, join, exists from os import getcwd, mkdir +from subprocess import check_output +if sys.version_info[0] < 3: + rinput = raw_input +else: + rinput = input +COLOR = ['git', 'config', '--get', 'gitli.color'] GITLIDIR = '.gitli' ISSUES = '.issues' OPEN = '.issues-open' @@ -18,11 +27,36 @@ OSEPARATOR = '\n' TTYPES = ['Task', 'Bug', 'Enhancement'] +class BColors: + BLUE = '\033[1;34m' + GREEN = '\033[1;32m' + YELLOW = '\033[1;33m' + CYAN = '\033[1;36m' + WHITE = '\033[1;37m' + ENDC = '\033[0m' + + def disable(self): + self.BLUE = '' + self.GREEN = '' + self.YELLOW = '' + self.CYAN = '' + self.WHITE = '' + self.ENDC = '' + + +def is_colored_output(): + try: + value = check_output(COLOR).strip().lower().decode('utf-8') + return value in {'auto', 'on', 'true'} + except Exception: + return False + + def ask_type(verbose=False, default=1): if not verbose: return 1 - ttype = input('Task type: 1-Task, 2-Bug, 3-Enhancement [{0}]: '\ + ttype = rinput('Task type: 1-Task, 2-Bug, 3-Enhancement [{0}]: '\ .format(default)) ttype = ttype.strip().lower() @@ -49,7 +83,7 @@ def ask_milestone(path, verbose=False, default=None): if not verbose: return current_value - milestone = input('Milestone: [{0}]: '.format(current_value)).strip() + milestone = rinput('Milestone: [{0}]: '.format(current_value)).strip() if not milestone: milestone = current_value @@ -142,15 +176,21 @@ def get_issues(path, filters, open_issues, milestones, tasks): return issues -def print_issues(issues, open_issues): +def print_issues(issues, open_issues, bcolor): for (number, title, task_id, milestone) in issues: if number in open_issues: open_text = 'open' + color = bcolor.YELLOW else: open_text = 'closed' + color = bcolor.GREEN - print('#{0} {1} [{2}] [{3}] - {4}'.format(number, title, - TTYPES[task_id - 1], milestone, open_text)) + milestone_text = '[' + milestone + ']' + task_text = '[' + TTYPES[task_id - 1] + ']' + + print('{5}#{0:<4}{9} {6}{1:<48}{9} {7}{2:<6} {3:<7}{9} - {8}{4}{9}' + .format(number, title, task_text, milestone_text, open_text, + bcolor.CYAN, bcolor.WHITE, bcolor.BLUE, color, bcolor.ENDC)) def init(path): @@ -206,7 +246,7 @@ def close_issue(path, issue_number): remove_open(path, issue_number) -def list_issues(path, filters=None): +def list_issues(path, filters=None, bcolor=BColors()): if filters is None: filters = [] else: @@ -222,7 +262,7 @@ def list_issues(path, filters=None): issues = get_issues(path, filters, open_issues, milestones, tasks) - print_issues(issues, open_issues) + print_issues(issues, open_issues, bcolor) def reopen_issue(path, issue_number): @@ -231,11 +271,11 @@ def reopen_issue(path, issue_number): add_open(path, issue_number) -def show_issue(path, issue_number): +def show_issue(path, issue_number, bcolor=BColors()): issue = get_issue(path, issue_number) if issue is not None: open_issues = get_open_issues(path) - print_issues([issue], open_issues) + print_issues([issue], open_issues, bcolor) else: print('Issue #{0} not found'.format(issue_number)) @@ -253,7 +293,7 @@ def edit_issue(path, issue_number): print('Issue #{0} unknown'.format(issue_number)) return else: - title = input('Enter a new title (enter nothing to keep the same): ') + title = rinput('Enter a new title (enter nothing to keep the same): ') if not title.strip(): title = issue[1] ttype = ask_type(True, issue[2]) @@ -302,6 +342,10 @@ if __name__ == '__main__': (options, args) = parser.parse_args() + bcolor = BColors() + if not is_colored_output(): + bcolor.disable() + if len(args) == 0: parser.print_help() sys.exit(1) @@ -315,7 +359,6 @@ if __name__ == '__main__': print("Unable to find a git repository. ") sys.exit(1) - path = join(path, GITLIDIR) if command == 'init': init(path) @@ -324,11 +367,11 @@ if __name__ == '__main__': elif command == 'close': close_issue(path, args[0].strip()) elif command == 'list': - list_issues(path, args) + list_issues(path, args, bcolor) elif command == 'reopen': reopen_issue(path, args[0].strip()) elif command == 'show': - show_issue(path, args[0].strip()) + show_issue(path, args[0].strip(), bcolor) elif command == 'edit': edit_issue(path, args[0].strip()) elif command == 'milestone':