diff options
Diffstat (limited to 'client')
-rwxr-xr-x | client/bug.py | 58 | ||||
-rwxr-xr-x | client/bug_delete.py | 33 | ||||
-rwxr-xr-x | client/bug_edit.py | 51 | ||||
-rwxr-xr-x | client/bug_list.py | 56 | ||||
-rwxr-xr-x | client/bug_open.py | 101 | ||||
-rwxr-xr-x | client/bug_show.py | 55 |
6 files changed, 354 insertions, 0 deletions
diff --git a/client/bug.py b/client/bug.py new file mode 100755 index 0000000..24a523c --- /dev/null +++ b/client/bug.py @@ -0,0 +1,58 @@ +#!../flask/bin/python +""" +usage: bug [options] <command> [<args>...] + +options: + -u, --uri ENDPOINT Project API endpoint + -h, --help Print this help text + -v, --version Print the client version + +commands: + open Open a new ticket + list List all open bugs in the project + show Show a specific ticket by ID + + [Not implemented yet:] + resolution Set the resolution status of a ticket + edit Edit a ticket + reopen Reopen a previously closed ticket + close Close a ticket + lock Lock a ticket, preventing new comments + label Apply a label to a ticket + +See 'bug help <command>' for more information on a specific command +""" +from importlib import import_module +from subprocess import call +from docopt import docopt + +commands = ['open', 'delete', 'show', 'list', 'edit'] +def main(): + + if args['<command>'] in ['help', None]: + if not args['<args>']: + print(__doc__.lstrip().rstrip()) + else: + if args['<args>'][0] in commands: + bug_mod = import_module('bug_{}'.format(args['<args>'][0])) + print(bug_mod.__doc__.lstrip().rstrip()) + else: + exit("'{}' is not a bug.py command. See 'bug help'.".format(args['<args>'][0])) + elif args['<command>'] in commands: + if not args['--uri']: + exit("URI missing") + + bug_mod = import_module('bug_{}'.format(args['<command>'])) + argv = [args['<command>']] + args['<args>'] + arguments = args.copy() + arguments.update(docopt(bug_mod.__doc__, argv=argv)) + bug_mod.call(arguments) + else: + exit("'{}' is not a bug.py command. See 'bug help'.".format(args['<command>'])) + +if __name__ == '__main__': + args = docopt(__doc__, + version='tbt client version 0.0.0.alpha', + options_first=True) + #print(args) + main() diff --git a/client/bug_delete.py b/client/bug_delete.py new file mode 100755 index 0000000..bcce88e --- /dev/null +++ b/client/bug_delete.py @@ -0,0 +1,33 @@ +#!../flask/bin/python +""" +usage: bug delete [options] <ticket_id> + +If no arguments are given it will open your $EDITOR where the first line is +the summary following a newline and then the body of the report. Both are +required. + + -h, --help Print this help text + -i, --ticket-id ID of the ticket to delete +""" +from docopt import docopt +import json, requests + +if __name__ == '__main__': + print(docopt(__doc__)) + +def call(args): + print(args) + api_endpoint = args['--uri'] + '/api/1.0/ticket/' + + req = requests.delete(api_endpoint + args['<ticket_id>']) + + res = json.loads(req.text) + + if req.status_code == 404: + print("Ticket with ID '{}' could not be deleted: {}".format(args['<ticket_id>'], res['error'])) + elif req.status_code == 200: + print("Ticket with ID '{}' deleted successfully.".format(args['<ticket_id>'])) + else: + exit("ALERT ALERT ALERT") + + #print("{} {}\n {}".format(t['id'], t['title'], t['uri'])) diff --git a/client/bug_edit.py b/client/bug_edit.py new file mode 100755 index 0000000..42eca80 --- /dev/null +++ b/client/bug_edit.py @@ -0,0 +1,51 @@ +#!../flask/bin/python +""" +usage: bug edit [options] ticket <ticket_id> + bug edit [options] comment <comment_id> + +If both the -s and -b options are given, the summary and body of the ticket or +comment with the given ID will be updated to the specified strings. If -s is +given for a comment it is added to the top of the comment instead. + +If they are not given, your $EDITOR will be opened where the first line is the +summary following a newline and then the body of the ticket. Both are +required. + +options: + -h, --help Print this help text + -s, --summary STRING A short summary of the bug + -b, --body STRING The long description of the bug or the body of the + comment +""" +from docopt import docopt +import json, requests + +if __name__ == '__main__': + print(docopt(__doc__)) + +def call(args): + print(args) + api_endpoint = args['--uri'] + '/api/1.0/ticket' + + ticket = {} + if args['--summary']: + ticket['summary'] = args['--summary'] + else: + exit("Summary needed, no interactive edit yet") + + if args['--body']: + ticket['body'] = args['--body'] + else: + ticket['body'] = None + + headers = { + 'Content-Type': 'application/json', + 'Accept': 'text/plain' + } + payload = json.dumps(ticket) + + r = requests.post(api_endpoint, data=payload, headers=headers) + + t = json.loads(r.text).get('ticket') + + print("{} {}\n {}".format(t['id'], t['summary'], t['uri'])) diff --git a/client/bug_list.py b/client/bug_list.py new file mode 100755 index 0000000..6084414 --- /dev/null +++ b/client/bug_list.py @@ -0,0 +1,56 @@ +#!../flask/bin/python +""" +usage: bug list [options] + +If no arguments are given it will open your $EDITOR where the first line is +the summary following a newline and then the body of the report. Both are +required. + + -h, --help Print this help text +""" +from docopt import docopt +from textwrap import indent +from datetime import datetime +import json, requests + +if __name__ == '__main__': + print(docopt(__doc__)) + +def call(args): + print(args) + api_endpoint = args['--uri'] + '/api/1.0/tickets' + + r = requests.get(api_endpoint) + + tickets = json.loads(r.text).get('tickets') + + for ticket in tickets: + output = '[TBT#{}] '.format(ticket['id']) + + if 'deleted' in ticket and ticket['deleted'] == True: + output += '[DELETED] ' + + output += '[{}] '.format(ticket['status']) + + output += '{}\n'.format(ticket['summary']) + + if ticket['status'] != 'open': + output += 'Resolution: {}\n'.format(ticket['resolution']) + + if ticket['reason']: + output += 'Reason: {}\n'.format(ticket['reason']) + + output += 'Opened by: {} <{}>\n'.format(ticket['opened_by']['nickname'], ticket['opened_by']['email']) + output += 'Opened at: {} UTC\n'.format(datetime.strptime( ticket['opened_at'], "%Y-%m-%dT%H:%M:%S" )) + + if ticket['assigned_to']: + output += 'Assigned to: {} <{}>\n'.format(ticket['assigned_to']['nickname'], ticket['assigned_to']['email']) + else: + output += 'Assigned to: Unassigned\n' + + if ticket['updated_at']: + output += 'Updated at: {} UTC\n'.format(datetime.strptime(ticket['opened_at'], "%Y-%m-%dT%H:%M:%S" )) + + output += '\n' + indent('{}'.format(ticket['body']), ' ') + '\n' + + print(output) diff --git a/client/bug_open.py b/client/bug_open.py new file mode 100755 index 0000000..17a3e4f --- /dev/null +++ b/client/bug_open.py @@ -0,0 +1,101 @@ +#!../flask/bin/python +""" +usage: bug open [options] + +If no arguments are given it will open your $EDITOR where the first line is +the summary following a newline and then the body of the report. Both are +required. + + -h, --help Print this help text + -s, --summary STRING A short summary of the bug + -b, --body STRING The long description of the bug +""" +import os, re, tempfile, subprocess +from docopt import docopt +import json, requests +from bug_show import show_ticket + +if __name__ == '__main__': + print(docopt(__doc__)) + +def call(args): + print(args) + api_endpoint = args['--uri'] + '/api/1.0/ticket' + + if args['--summary']: + summary = args['--summary'] + else: + summary = '' + + if args['--body']: + body = args['--body'] + else: + body = '' + + if not(summary and body): + (summary, body) = editor_prompt(summary, body) + + ticket = { + 'summary': summary, + 'body': body, + 'user_nickname': 'demi' + } + + headers = { + 'Content-Type': 'application/json', + 'Accept': 'text/plain' + } + payload = json.dumps(ticket) + + r = requests.post(api_endpoint, data=payload, headers=headers) + + t = json.loads(r.text).get('ticket') + + print(t) + print(show_ticket(t)) + + +def editor_prompt(summary, body): + editor = os.environ.get('EDITOR','vim') + message='' + + if summary: + message += summary + + if body: + message += '\n\n' + body + + message += """ + +# Please enter the summary on a single line, followed +# by an empty line, then followed by the body of the +# ticket. +# +# Both the summary and body are required. If either of +# them are missing, or they aren't separated properly +# the submission will be aborted. +""" + + tmp = tempfile.NamedTemporaryFile() + tmp.write(message.encode("utf-8")) + tmp.flush() + + regx = re.compile('^(.+?)\n\n(.+)$', re.S) + + subprocess.call([editor, tmp.name]) + + tmp.seek(0) + data = tmp.read().decode("utf-8") + tmp.close() + + data = data[:-263] # Strip the commented out message + data = data.lstrip().rstrip() # Strip opening and ending whitespace + regmatch = regx.match(data) + + if len(regmatch.groups()) != 2: + exit("Error: summary and body not separated properly, aborting") + + summary = regmatch.group(1) + body = regmatch.group(2) + + return (summary, body) diff --git a/client/bug_show.py b/client/bug_show.py new file mode 100755 index 0000000..0c3c9b8 --- /dev/null +++ b/client/bug_show.py @@ -0,0 +1,55 @@ +#!../flask/bin/python +""" +usage: bug show [options] <ticket_id> + + -h, --help Print this help text +""" +from docopt import docopt +from textwrap import indent +from datetime import datetime +import json, requests + +if __name__ == '__main__': + print(docopt(__doc__)) + +def call(args): + print(args) + api_endpoint = args['--uri'] + '/api/1.0/ticket/' + + r = requests.get(api_endpoint + args['<ticket_id>']) + + ticket = json.loads(r.text).get('ticket') + print(ticket) + print(show_ticket(ticket)) + +def show_ticket(ticket): + output = '[TBT#{}] '.format(ticket['id']) + + if 'deleted' in ticket and ticket['deleted'] == True: + output += '[DELETED] ' + + output += '[{}] '.format(ticket['status']) + + output += '{}\n'.format(ticket['summary']) + + + if ticket['status'] != 'open': + output += 'Resolution: {}\n'.format(ticket['resolution']) + + if ticket['reason']: + output += 'Reason: {}\n'.format(ticket['reason']) + + output += 'Opened by: {} <{}>\n'.format(ticket['opened_by']['nickname'], ticket['opened_by']['email']) + output += 'Opened at: {} UTC\n'.format(datetime.strptime( ticket['opened_at'], "%Y-%m-%dT%H:%M:%S" )) + + if ticket['assigned_to']: + output += 'Assigned to: {} <{}>\n'.format(ticket['assigned_to']['nickname'], ticket['assigned_to']['email']) + else: + output += 'Assigned to: Unassigned\n' + + if ticket['updated_at']: + output += 'Updated at: {} UTC\n'.format(datetime.strptime(ticket['opened_at'], "%Y-%m-%dT%H:%M:%S" )) + + output += '\n' + indent('{}'.format(ticket['body']), ' ') + '\n' + + return output |