Browse Source

Load subcomponents of issues.

master
poikilos 3 years ago
parent
commit
d459267ba3
  1. 188
      utilities/enissue.py
  2. 11
      utilities/pyissuesyncd

188
utilities/enissue.py

@ -227,8 +227,11 @@ def tests():
raise AssertionError("{} is None".format(k))
def debug(msg):
def debug(*args, **kwargs):
msg = ""
if verbose:
if len(args) > 0:
msg = args[0]
error("[debug] " + msg)
def set_verbose(on):
@ -602,7 +605,7 @@ class Repo:
self.default_query = options['default_query']
self.hide_events = options['hide_events']
self.issues = None
self.last_query_s = None
self.last_url = None
self.options = copy.deepcopy(options)
def getKnownKey(self, name):
@ -765,7 +768,7 @@ class Repo:
" only one issue because a single"
" issue has its own URL with only"
" one result (not a list).")
query_s = self.issues_url # changed below if issue_no
url = self.issues_url # changed below if issue_no
this_page = 1
query_part = ""
@ -775,7 +778,7 @@ class Repo:
for k,v in query.items():
if v is not None:
# <https://stackoverflow.com/a/9345102/4541104>:
#query_s += (
#url += (
# "&{}={}".format(quote_plus(k), quote_plus(v))
#)
#
@ -813,48 +816,49 @@ class Repo:
c_issue_name = self.c_issue_name_fmt.format(issue_no=issue_no)
c_issues_sub_path = os.path.join(self.c_repo_path, "issues")
results_key = None
url = None
if issue_no is not None:
if not os.path.isdir(c_issues_sub_path):
os.makedirs(c_issues_sub_path)
c_issue_path = os.path.join(c_issues_sub_path, c_issue_name)
c_path = c_issue_path
make_list = True
# Change query_s to the issue url (formerly issue_url):
query_s = self.api_issue_url_fmt.format(
# Change url to the issue url (formerly issue_url):
url = self.api_issue_url_fmt.format(
instance_url=self.instance_url,
ru=self.remote_user,
rn=self.repo_name,
issue_no=issue_no,
)
else:
prev_query_s = query_s
prev_query_s = url
if len(searchTermStr) > 0:
query_s = self.search_issues_url
url = self.search_issues_url
results_key = self.search_results_key
if "?" not in query_s:
query_s += "?q=" + searchTermStr
if "?" not in url:
url += "?q=" + searchTermStr
else:
query_s += searchTermStr
debug(" changing query_s from {} to {}"
"".format(prev_query_s, query_s))
url += searchTermStr
debug(" changing url from {} to {}"
"".format(prev_query_s, url))
debug(" (issues will be set to the content of the {}"
" element)".format(results_key))
# Labels are NOT in the URL, but filtered later (See docstring).
if self.page is not None:
query_s = self.issues_url + "?page=" + str(self.page)
query_s += and_query_part
url = self.issues_url + "?page=" + str(self.page)
url += and_query_part
debug(" appended page query_part={} (c_path={})"
"".format(query_part, c_path))
elif len(query_part) > 0:
query_s += "?" + query_part
url += "?" + query_part
debug(" appended custom query_part={} (c_path={})"
"".format(query_part, c_path))
else:
debug(" There was no custom query.")
self.last_query_s = query_s
self.last_url = url
# ^ Differs from self.last_src, which can be a file.
@ -876,7 +880,7 @@ class Repo:
if not quiet:
print(p+"Loading cache: \"{}\"".format(c_path))
debug(p+"Cache time limit: {}".format(max_cache_delta))
debug(p+" for URL: {}".format(query_s))
debug(p+" for URL: {}".format(url))
if not quiet:
print(p+"Cache expires: {}".format(expires_s))
with open(c_path) as json_file:
@ -935,25 +939,25 @@ class Repo:
c_path
))
self.last_src = query_s
self.last_src = url
# ^ If didn't return yet, the source is a URL.
req_is_complex = False
try:
debug(p+"Query URL (query_s): {}".format(query_s))
debug(p+"Query URL (url): {}".format(url))
headers = {}
token = self.options.get('token')
if token is not None:
headers['Authorization'] = "token " + token
if len(headers) > 0:
req_is_complex = True
response = requests.get(query_s, headers=headers)
# response = req.urlopen(query_s)
res_text = response.text
# NOTE: In python3, response.content is in bytes
res = requests.get(url, headers=headers)
# res = req.urlopen(url)
res_text = res.text
# NOTE: In python3, res.content is in bytes
# (<https://stackoverflow.com/a/18810889/4541104>).
else:
response = request.urlopen(query_s)
res_text = decode_safe(response.read())
res = request.urlopen(url)
res_text = decode_safe(res.read())
except HTTPError as ex:
msg = ex.reason
if ex.code == 410:
@ -965,17 +969,17 @@ class Repo:
'code': ex.code,
'reason': msg,
'headers': ex.headers,
'url': query_s,
'url': url,
}
)
# msg = str(ex) + ": " + self.rateLimitFmt.format(query_s)
# msg = str(ex) + ": " + self.rateLimitFmt.format(url)
return (
None,
{
'code': ex.code,
'reason': msg,
'headers': ex.headers,
'url': query_s,
'url': url,
}
)
@ -1132,6 +1136,9 @@ class Repo:
fn += ".json"
c_path += ".json"
else:
error("url: {}".format(url))
error("self.labels_url: {}".format(self.labels_url))
error("self.issues_url: {}".format(self.issues_url))
raise NotImplementedError("getCachedJsonDict"
" doesn't have a cache directory"
" for {}. Try --refresh"
@ -1187,10 +1194,10 @@ class Repo:
if token is not None:
headers['Authorization'] = "token " + token
if len(headers) > 0:
res = requests.get(query_s, headers=headers)
# res = req.urlopen(query_s)
res_text = response.text
# NOTE: In python3, response.content is in bytes
res = requests.get(url, headers=headers)
# res = req.urlopen(url)
res_text = res.text
# NOTE: In python3, res.content is in bytes
# (<https://stackoverflow.com/a/18810889/4541104>).
else:
res = request.urlopen(url)
@ -1223,7 +1230,8 @@ class Repo:
return data, None
def show_issue(self, issue, refresh=False, never_expire=False):
def show_issue(self, issue, refresh=False, never_expire=False,
quiet=False):
'''
Display an issue dictionary as formatted text after getting the
issue body and other data from the internet. Gather all of the
@ -1245,11 +1253,15 @@ class Repo:
else 'code' is not present).
'''
p = self.log_prefix
print("")
shmsg = print
if quiet:
shmsg = debug
shmsg("")
debug("show_issue...")
print("#{} {}".format(issue["number"], issue["title"]))
# print(issue["html_url"])
print("")
shmsg("#{} {}".format(issue["number"], issue["title"]))
# shmsg(issue["html_url"])
shmsg("")
issue_data = issue
html_url = issue['html_url']
issue_data, err = self.getCachedJsonDict(
@ -1272,42 +1284,54 @@ class Repo:
# ^ left_w must be >=11 or "updated_at:" will push the next col.
spacer = " "
line_fmt = "{: <" + str(left_w) + "}" + spacer + "{}"
print(line_fmt.format("html_url:", issue["html_url"]))
print(line_fmt.format("by:", issue_data["user"]["login"]))
print(line_fmt.format("state:", issue_data["state"]))
shmsg(line_fmt.format("html_url:", issue["html_url"]))
shmsg(line_fmt.format("by:", issue_data["user"]["login"]))
shmsg(line_fmt.format("state:", issue_data["state"]))
assignees = issue_data.get("assignees")
if (assignees is not None) and len(assignees) > 1:
assignee_names = [a["login"] for a in assignees]
print(line_fmt.format("assignees:",
shmsg(line_fmt.format("assignees:",
" ".join(assignee_names)))
elif issue_data.get("assignee") is not None:
assignee_name = issue_data["assignee"]["login"]
print(line_fmt.format("assignee:", assignee_name))
shmsg(line_fmt.format("assignee:", assignee_name))
labels_s = "None"
if len(issue['lower_labels']) > 0:
ll = None
if issue.get('labels') is not None:
if issue.get('lower_labels') is None:
issue['lower_labels'] = []
for oldL in issue.get('labels'):
labelURL = oldL.get('url')
if labelURL is not None:
lastSlashI = labelURL.rfind('/')
if lastSlashI > -1:
ll = labelURL[lastSlashI+1:]
issue['lower_labels'].append(ll)
lls = issue.get('lower_labels')
if (lls is not None) and (len(issue['lower_labels']) > 0):
neat_labels = []
for label_s in issue['lower_labels']:
for label_s in lls:
if " " in label_s:
neat_labels.append('"' + label_s + '"')
else:
neat_labels.append(label_s)
labels_s = ", ".join(neat_labels)
# moved further down: print(line_fmt.format("labels:", labels_s))
print("")
# moved further down: shmsg(line_fmt.format("labels:", labels_s))
shmsg("")
if markdown is not None:
print('"""')
print(markdown)
print('"""')
shmsg('"""')
shmsg(markdown)
shmsg('"""')
else:
print("(no description)")
shmsg("(no description)")
comments = issue_data.get("comments")
if comments is None:
comments = 0
if comments > 0:
print("")
print("")
print("({}) comment(s):".format(comments))
shmsg("")
shmsg("")
shmsg("({}) comment(s):".format(comments))
left_margin = " "
c_prop_fmt = (left_margin + "{: <" + str(left_w) + "}"
@ -1386,22 +1410,22 @@ class Repo:
login = None
if user is not None:
print("")
print("")
shmsg("")
shmsg("")
login = user.get('login')
if login is not None:
print(c_prop_fmt.format("from:", login))
shmsg(c_prop_fmt.format("from:", login))
updated_at = evt.get("updated_at")
if updated_at is not None:
print(c_prop_fmt.format("updated_at:",
shmsg(c_prop_fmt.format("updated_at:",
updated_at))
body = evt.get("body")
if body is not None:
print("")
print(left_margin + '"""')
print(left_margin + body)
print(left_margin + '"""')
print("")
shmsg("")
shmsg(left_margin + '"""')
shmsg(left_margin + body)
shmsg(left_margin + '"""')
shmsg("")
rename = evt.get('rename')
event = evt.get('event')
@ -1421,7 +1445,7 @@ class Repo:
source_issue = source.get('issue')
if source_issue is not None:
source_number = source_issue.get('number')
print(left_margin
shmsg(left_margin
+"cross-reference: {} referenced this issue"
" in {} {}."
"".format(login, source_type, source_number))
@ -1430,7 +1454,7 @@ class Repo:
if label is not None:
label_name = label.get('name')
label_color = label.get('color')
print(left_margin+"{}: {} by {} {}"
shmsg(left_margin+"{}: {} by {} {}"
"".format(event, label_name, login,
created_at))
# elif (event == "closed") or (event == "reopened"):
@ -1442,17 +1466,17 @@ class Repo:
if label is not None:
label_name = label.get('name')
label_color = label.get('color')
print(left_margin+"{}: {} by {} {}"
shmsg(left_margin+"{}: {} by {} {}"
"".format(event, label_name, login,
created_at))
else:
print(left_margin+"{} {} by {}"
shmsg(left_margin+"{} {} by {}"
"".format(event.upper(), created_at, login))
if (rename is not None) and ('renamed' not in ignore_events):
# already said "RENAMED" above (evt.get('event'))
# print(left_margin+"renamed issue")
print(left_margin+" from:{}".format(rename.get('from')))
print(left_margin+" to:{}".format(rename.get('to')))
# shmsg(left_margin+"renamed issue")
shmsg(left_margin+" from:{}".format(rename.get('from')))
shmsg(left_margin+" to:{}".format(rename.get('to')))
reactions = evt.get('reactions')
reactions_url = None
@ -1480,10 +1504,10 @@ class Repo:
if reac_user is not None:
reac_login = reac_user.get('login')
reac_content = reac.get('content')
print(left_margin + "- <{}> :{}:"
shmsg(left_margin + "- <{}> :{}:"
"".format(reac_login, reac_content))
print("")
print(left_margin+"labels: {}".format(labels_s))
shmsg("")
shmsg(left_margin+"labels: {}".format(labels_s))
closed_by = issue_data.get('closed_by')
closed_at = issue_data.get('closed_at')
if (closed_by is not None) or (closed_at is not None):
@ -1491,7 +1515,7 @@ class Repo:
# (determine this by getting 'state').
# The "REOPENED" and "CLOSED" events also appear in the
# timeline (see this_tmln_json_url).
print()
shmsg()
state = issue_data.get('state')
if state is None:
state = options['default_query'].get('state')
@ -1499,21 +1523,23 @@ class Repo:
if closed_at is not None:
closet_at_str = " {}".format(closed_at)
if state != "open":
closed_by_login = None
if closed_by is not None:
closed_by_login = closed_by.get("login")
if closed_by_login is not None:
print(" (CLOSED{} by {})".format(
shmsg(" (CLOSED{} by {})".format(
closet_at_str,
closed_by_login
))
else:
print(" (CLOSED{})".format(closet_at_str))
shmsg(" (CLOSED{})".format(closet_at_str))
if state == "open":
print(" (REOPENED)")
shmsg(" (REOPENED)")
elif closed_at is None:
print(" (The closing date is unknown.)")
shmsg(" (The closing date is unknown.)")
print("")
print("")
shmsg("")
shmsg("")
err = None
if msg is not None:
err = {
@ -1915,7 +1941,7 @@ def main():
# ^ Never refresh, since that would already have been done.
state_msg = repo.default_query.get('state')
if state_msg is None:
state_msg = repo.last_query_s
state_msg = repo.last_url
if state_msg != "open":
print("(showing {} issue(s))".format(state_msg.upper()))
# ^ such as CLOSED

11
utilities/pyissuesyncd

@ -110,6 +110,15 @@ def get_issue(repo, options, issue_no):
options,
issue_no=issue_no,
)
if err is None:
never_expire = options.get('never_expire') is True
result, err = repo.show_issue(
results[0],
never_expire=never_expire,
quiet=True,
)
results = [result]
# ^ Get all of the details.
if results is None:
if err is not None:
if err.get('code') == 410:
@ -299,7 +308,7 @@ def start_issuesyncd(src_options, dst_options):
"".format(issue_no, src_updated_ts, src_updated_dt))
'''
# print(json.dumps(src_issue, indent=2))
continue # for debug only (if stuff below isn't implemented)
# enissue.set_verbose(True)
dst_repo = Repo(dst_options)
dst_issue, err = get_issue(dst_repo, dst_options, issue_no)

Loading…
Cancel
Save