Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fancy output #58

Merged
merged 2 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contrib/jirate.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"default_project": "MYPROJECT",
"_comment": "Set to true to enable eval() of code on custom fields. DANGEROUS",
"here_there_be_dragons": false,
"fancy_output": true,
"searches": {
"default": "assignee = currentUser() and status not in (Done, closed, resolved)",
"closed": "assignee = currentUser() and status in (Done, closed, resolved)"
Expand Down
66 changes: 63 additions & 3 deletions jirate/decor.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
_markdown = False
pass

display_color = True
fancy_output = False
HILIGHT = ''
NORMAL = ''

Expand All @@ -42,8 +42,54 @@
'default': 7 } # NOQA


class EscapedString(str):
def __init__(self, val):
self._len = len(val)
self._text = val
self._value = val
self._sequence = None

def __len__(self):
return self._len

def _escape(self, sequence, value=None):
if '{_value_}' not in sequence:
raise ValueError('Cannot escape; invalid input')
if not value:
value = self._text
return sequence.replace('{_value_}', value)

def escape(self, sequence, value=None):
self._value = self._escape(sequence, value)

def update(self, value):
self._value = value

def ljust(self, width):
if width <= len(self):
return str(self)
return self + (' ' * (width - len(self)))

def __str__(self):
return str(self._value)

def __repr__(self):
return str(self._value)

def __add__(self, other):
if (isinstance(other, EscapedString)):
ret = EscapedString(self._text + other._text)
ret.update(self._value + other._value)
else:
ret = EscapedString(self._text + str(other))
ret.update(self._value + str(other))
return ret


def color_string(string, color=None, bgcolor=None):
if display_color is not True:
global fancy_output

if fancy_output is not True:
return string

ret_string = ''
Expand All @@ -59,7 +105,21 @@ def color_string(string, color=None, bgcolor=None):

ret_string = '{0}{1}{2}'.format(fg_color, bg_color, string)

return ret_string
ret = EscapedString(string)
ret.update(ret_string)

return ret


def issue_link_string(issue_key, baseurl=None):
global fancy_output

if not baseurl or not fancy_output:
return issue_key

ret = EscapedString(issue_key)
ret.update(f']8;;{baseurl}/browse/{issue_key}\\{issue_key}]8;;\\')
return ret


def parse_params(arg):
Expand Down
35 changes: 21 additions & 14 deletions jirate/jira_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from jirate.args import ComplicatedArgs, GenericArgs
from jirate.jboard import JiraProject, get_jira
from jirate.decor import md_print, pretty_date, hbar_under, hbar, hbar_over, nym, vsep_print, parse_params, truncate, render_matrix, comma_separated
from jirate.decor import issue_link_string
from jirate.decor import pretty_print # NOQA
from jirate.config import get_config
from jirate.jira_fields import apply_field_renderers, render_issue_fields, max_field_width, render_field_data
Expand Down Expand Up @@ -98,7 +99,7 @@ def print_issues_by_field(issue_list, args=None):
if nym(issue.field('status')['name']) != nym(args.status):
continue
row = []
row.append(issue.key)
row.append(issue_link_string(issue.key, args.project.jira.server_url))
for field in fields:
field_key = args.project.field_to_id(field)
if not field_key:
Expand Down Expand Up @@ -849,16 +850,16 @@ def print_labels(issue, prefix='Labels: '):
print()


def print_issue_links(issue):
def print_issue_links(issue, baseurl=None):
hbar_under('Issue Links')
matrix = []
for link in issue['issuelinks']:
if 'outwardIssue' in link:
text = link['type']['outward'] + ' ' + link['outwardIssue']['key']
text = link['type']['outward'] + ' ' + issue_link_string(link['outwardIssue']['key'], baseurl)
status = link['outwardIssue']['fields']['status']['name']
desc = link['outwardIssue']['fields']['summary']
elif 'inwardIssue' in link:
text = link['type']['inward'] + ' ' + link['inwardIssue']['key']
text = link['type']['inward'] + ' ' + issue_link_string(link['inwardIssue']['key'], baseurl)
status = link['inwardIssue']['fields']['status']['name']
desc = link['inwardIssue']['fields']['summary']
# color_string throws off length calculations
Expand All @@ -881,7 +882,7 @@ def print_remote_links(links):


# Dict from search or subtask list
def _print_issue_list(header, issues):
def _print_issue_list(header, issues, baseurl=None):
if not issues:
return
hbar_under(header)
Expand All @@ -890,28 +891,29 @@ def _print_issue_list(header, issues):
if isinstance(task, str):
task = issues[task]
try:
task_key = task.key
task_key = issue_link_string(task['key'], baseurl)
status = task.raw['fields']['status']['name']
summary = task.raw['fields']['summary']
except AttributeError:
task_key = task['key']
task_key = issue_link_string(task['key'], baseurl)
status = task['fields']['status']['name']
summary = task['fields']['summary']
matrix.append([task_key, status, summary])
render_matrix(matrix, False, False)
print()


def print_subtasks(issue):
_print_issue_list('Sub-tasks', issue['subtasks'])
def print_subtasks(issue, baseurl=None):
_print_issue_list('Sub-tasks', issue['subtasks'], baseurl)


def print_issue(project, issue_obj, verbose=False, no_comments=False, no_format=False):
issue = issue_obj.raw['fields']
lsize = max(len(issue_obj.raw['key']), max_field_width(issue, verbose, project.allow_code))
key_link = issue_link_string(issue_obj.key, project.jira.server_url)
lsize = max(len(key_link), max_field_width(issue, verbose, project.allow_code))
lsize = max(lsize, len('Next States'))

vsep_print(' ', 0, issue_obj.raw['key'], lsize, issue['summary'])
vsep_print(' ', 0, key_link, lsize, issue['summary'])
render_issue_fields(issue, verbose, project.allow_code, lsize)

if verbose:
Expand All @@ -929,7 +931,7 @@ def print_issue(project, issue_obj, verbose=False, no_comments=False, no_format=
print()

if 'issuelinks' in issue and len(issue['issuelinks']):
print_issue_links(issue)
print_issue_links(issue, project.jira.server_url)

# Don't print external links unless in verbose mode since it's another API call?
if verbose:
Expand All @@ -938,11 +940,11 @@ def print_issue(project, issue_obj, verbose=False, no_comments=False, no_format=
print_remote_links(links)

if 'subtasks' in issue and len(issue['subtasks']):
print_subtasks(issue)
print_subtasks(issue, project.jira.server_url)

if issue['issuetype']['name'] == 'Epic':
ret = project.search_issues('"Epic Link" = "' + issue_obj.raw['key'] + '"')
_print_issue_list('Issues in Epic', ret)
_print_issue_list('Issues in Epic', ret, project.jira.server_url)

if no_comments:
return
Expand Down Expand Up @@ -1113,6 +1115,11 @@ def get_jira_project(project=None, config=None, config_file=None):
if jconfig['here_there_be_dragons'] is True:
allow_code = True

# Configure fancy output rendering if specified
if 'fancy_output' in jconfig and jconfig['fancy_output']:
import jirate.decor # NOQA
jirate.decor.fancy_output = True

if not project:
# Not sure why I used an array here
project = jconfig['default_project']
Expand Down
Loading