diff --git a/utilities/enissue.py b/utilities/enissue.py index 53f868b..189f498 100755 --- a/utilities/enissue.py +++ b/utilities/enissue.py @@ -24,6 +24,12 @@ Options: - PostgreSQL (su then): pg_dump dbname > outfile --test Run unit tests then exit (0) if passed. + +Partial API documentation: +options keys: +- default_time_fmt: must be either a cross-platform (python) strftime + format (See https://strftime.org/) or the literal string + "unix_timestamp" to denote a unix timestamp. ''' from __future__ import print_function import sys @@ -110,6 +116,14 @@ github_defaults = { 'default_query': {'state':'open'}, 'hide_events': ['renamed', 'assigned'], 'api_comments_url_fmt': "{instance_url}/repos/{ru}/{rn}/issues/comments", + 'known_issue_keys': { + 'created_at': 'created_at', + 'updated_at': 'updated_at', + 'closed_at': 'closed_at', + 'body': 'body', + 'title': 'title', + }, + 'default_time_fmt': "%Y-%m-%dT%H:%M:%SZ", # GitHub (Z for UTC): 2018-09-13T16:59:38Z } gitea_defaults = { @@ -125,6 +139,14 @@ gitea_defaults = { 'default_query': {'state':'open'}, # TODO: Change for Gitea ?? 'hide_events': ['renamed', 'assigned'], 'api_comments_url_fmt': "{instance_url}/api/v1/repos/{ru}/{rn}/issues/comments", + 'known_issue_keys': { + 'created_at': 'created_at', + 'updated_at': 'updated_at', + 'closed_at': 'closed_at', + 'body': 'body', + 'title': 'title', + }, + 'default_time_fmt': "unix_timestamp", } # API documentation: @@ -301,8 +323,14 @@ class Repo: repo_url -- This is required. It can be an API or web URL as long as it ends with username/reponame (except where there is no username in the URL). - remote_user -- The repo user may be used in api_repo_url_fmt. - repo_name -- The repo name may be used in api_repo_url_fmt. + remote_user -- The repo user is used in api_repo_url_fmt, + and cache path if caches is not on single_cache mode + (If present, remote_user overrides the one detected from + the repo_url). + repo_name -- The repo name is used in api_repo_url_fmt, + and cache path if caches is not on single_cache mode + (If present, repo_name overrides the one detected from + the repo_url). api_repo_url_fmt -- The format string where {ru} is where a repo user goes, and {rn} is where a repo name goes, is used for the format of @@ -352,17 +380,28 @@ class Repo: if repo_url.endswith(".git"): repo_url = repo_url[:-4] urlParts = repo_url.split("/") - remote_user = urlParts[-2] + self.remote_user = urlParts[-2] self.api_id = options.get('api_id') if urlParts[-2] == "repo.or.cz": - remote_user = "almikes@aol.com" # Wuzzy2 + self.remote_user = "almikes@aol.com" # Wuzzy2 self.api_id = "git_instaweb" # Such as https://repo.or.cz/minetest_treasurer.git # - locally, git instaweb is controlled via: # git instaweb --httpd=webrick --start # git instaweb --httpd=webrick --stop - repo_name = urlParts[-1] + remote_user = options.get('remote_user') + if remote_user is not None: + self.remote_user = remote_user + del remote_user + + + self.repo_name = urlParts[-1] + + repo_name = options.get('repo_name') + if repo_name is not None: + self.repo_name = repo_name + del repo_name if self.api_id is None: if len(urlParts) > 2: @@ -394,9 +433,9 @@ class Repo: debug("* constructing {} Repo".format(self.api_id)) debug(" * detected remote_user \"{}\" in url" - "".format(remote_user)) + "".format(self.remote_user)) debug(" * detected repo_name \"{}\" in url" - "".format(repo_name)) + "".format(self.repo_name)) if self.api_id == "Gitea": instance_url = "/".join(urlParts[:-2]) debug(" * detected Gitea url " + instance_url) @@ -414,9 +453,9 @@ class Repo: self.repository_id = options.get('repository_id') site_users_repos_meta = sites_users_repos_meta.get(instance_url) if site_users_repos_meta is not None: - user_repos_meta = site_users_repos_meta.get(remote_user) + user_repos_meta = site_users_repos_meta.get(self.remote_user) if user_repos_meta is not None: - repo_meta = user_repos_meta.get(repo_name) + repo_meta = user_repos_meta.get(self.repo_name) if repo_meta is not None: if self.repository_id is None: self.repository_id = \ @@ -448,8 +487,6 @@ class Repo: self.setCachesPath(_caches_path, flat=False) del _caches_path del _single_cache - self.remote_user = remote_user - self.repo_name = repo_name self.search_results_key = options.get('search_results_key') self.page = options.get('page') @@ -458,22 +495,22 @@ class Repo: self.api_issue_url_fmt = options['api_issue_url_fmt'] self.repo_url = self.api_repo_url_fmt.format( instance_url=instance_url, - ru=remote_user, - rn=repo_name, + ru=self.remote_user, + rn=self.repo_name, ) self.search_issues_url_fmt = \ options.get('search_issues_url_fmt') self.search_issues_url = self.search_issues_url_fmt.format( instance_url=instance_url, - ru=remote_user, - rn=repo_name, + ru=self.remote_user, + rn=self.repo_name, ) self.api_comments_url_fmt = options['api_comments_url_fmt'] self.comments_url = self.api_comments_url_fmt.format( instance_url=instance_url, - ru=remote_user, - rn=repo_name, + ru=self.remote_user, + rn=self.repo_name, ) self.issues_url = self.repo_url + "/issues" @@ -488,6 +525,43 @@ class Repo: self.hide_events = options['hide_events'] self.issues = None self.last_query_s = None + self.options = copy.deepcopy(options) + + def getKnownKey(self, name): + ''' + Get an API-specific key that matches the given name. The name + variable will only be considered valid if it exists in + self.options['known_issue_keys']. + + Sequential arguments: + name -- a well-known issue key such as 'body' that will be + translated to an API-specific key. + ''' + key = self.options['known_issue_keys'].get(name) + if key is None: + raise KeyError("{} is not a well-known key in" + " known_issue_keys. Try _getIssueValue to" + " forcefully get a value.") + return key + + def _getIssueValue(self, index, key): + ''' + Sequential arguments: + index -- an index in self.issues + key -- a key in self.options['known_issue_keys'] + ''' + return self.issues[index][key] + + def getKnown(self, index, name): + ''' + Sequential arguments: + index -- an index in self.issues + name -- a well-known issue key such as 'body' that will be + translated to an API-specific key. + ''' + key = self.getKnownKey(name) + return self._getIssueValue(index, key) + def setCachesPath(self, path, flat=True): ''' @@ -498,6 +572,9 @@ class Repo: directories that mimic the API web URL structure (See _get_issues code for subdirectories and files). ''' + if self.remote_user is None: + raise RuntimeError("self.remote_user must be initialized" + " before calling self.setCachesPath") if path is None: raise ValueError("path must not be None") self.caches_path = path