summaryrefslogtreecommitdiffstats
path: root/aux-files/python-bugwarrior/gitea-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'aux-files/python-bugwarrior/gitea-support.patch')
-rw-r--r--aux-files/python-bugwarrior/gitea-support.patch584
1 files changed, 584 insertions, 0 deletions
diff --git a/aux-files/python-bugwarrior/gitea-support.patch b/aux-files/python-bugwarrior/gitea-support.patch
index 4ec4a9b..6c2c331 100644
--- a/aux-files/python-bugwarrior/gitea-support.patch
+++ b/aux-files/python-bugwarrior/gitea-support.patch
@@ -840,3 +840,587 @@ index a4c174c8..445846ff 100644
+ log.critical('[%s] has no \'gitea.token\' or \'gitea.password\'' % target)
+ sys.exit(1)
+
+From 81b3fa0b47db93fb83a54c6727f5ee3c408797c5 Mon Sep 17 00:00:00 2001
+From: msglm <msglm@techchud.xyz>
+Date: Wed, 22 May 2024 20:59:54 -0500
+Subject: [PATCH 3/4] Add basic documentation
+
+mish-mash between the github and gitlab documentation with everything I
+don't think is supported removed.
+---
+ bugwarrior/docs/services/gitea.rst | 124 +++++++++++++++++++++++++++++
+ 1 file changed, 124 insertions(+)
+ create mode 100644 bugwarrior/docs/services/gitea.rst
+
+diff --git a/bugwarrior/docs/services/gitea.rst b/bugwarrior/docs/services/gitea.rst
+new file mode 100644
+index 00000000..6ccf2308
+--- /dev/null
++++ b/bugwarrior/docs/services/gitea.rst
+@@ -0,0 +1,124 @@
++Gitea
++======
++
++You can import tasks from your Gitea instance using
++the ``gitea`` service name.
++
++Example Service
++---------------
++
++Here's an example of a Gitea target:
++
++.. config::
++
++ [user_gitea]
++ service = gitea
++ gitea.login = ralphbean
++ gitea.username = ralphbean
++ gitea.host = git.bean.com #Note: the lack of https, the service will assume HTTPS by default.
++ gitea.password = @oracle:eval:pass show 'git.bean.com'
++ gitea.token = 0000000000000000000000000000000
++
++The above example is the minimum required to import issues from
++Gitea. You can also feel free to use any of the
++configuration options described in :ref:`common_configuration_options`
++or described in `Service Features`_ below.
++
++The ``token`` is your private API token.
++
++Service Features
++----------------
++
++Include and Exclude Certain Repositories
++++++++++++++++++++++++++++++++++++++++++
++
++If you happen to be working with a large number of projects, you
++may want to pull issues from only a subset of your repositories. To
++do that, you can use the ``include_repos`` option.
++
++For example, if you would like to only pull-in issues from
++your own ``project_foo`` and team ``bar``'s ``project_fox`` repositories, you
++could add this line to your service configuration (replacing ``me`` by your own
++login):
++
++.. config::
++ :fragment: gitea
++
++ gitea.include_repos = me/project_foo, bar/project_fox
++
++Alternatively, if you have a particularly noisy repository, you can
++instead choose to import all issues excepting it using the
++``exclude_repos`` configuration option.
++
++In this example, ``noisy/repository`` is the repository you would
++*not* like issues created for:
++
++.. config::
++ :fragment: gitea
++
++ gitea.exclude_repos = noisy/repository
++
++.. hint::
++ If you omit the repository's namespace, bugwarrior will automatically add
++ your login as namespace. E.g. the following are equivalent:
++
++.. config::
++ :fragment: gitea
++
++ gitea.login = foo
++ gitea.include_repos = bar
++
++and:
++
++.. config::
++ :fragment: gitea
++
++ gitea.login = foo
++ gitea.include_repos = foo/bar
++
++Alternatively, you can use project IDs instead of names by prefixing the
++project id with `id:`:
++
++.. config::
++ :fragment: gitea
++
++ gitea.include_repos = id:1234,id:3141
++
++Import Labels as Tags
+++++++++++++++++++++++
++
++The gitea issue tracker allows you to attach labels to issues; to
++use those labels as tags, you can use the ``import_labels_as_tags``
++option:
++
++.. config::
++ :fragment: gitea
++
++ gitea.import_labels_as_tags = True
++
++Also, if you would like to control how these labels are created, you can
++specify a template used for converting the gitea label into a Taskwarrior
++tag.
++
++For example, to prefix all incoming labels with the string 'gitea_' (perhaps
++to differentiate them from any existing tags you might have), you could
++add the following configuration option:
++
++.. config::
++ :fragment: gitea
++
++ gitea.label_template = gitea_{{label}}
++
++In addition to the context variable ``{{label}}``, you also have access
++to all fields on the Taskwarrior task if needed:
++
++.. note::
++
++ See :ref:`field_templates` for more details regarding how templates
++ are processed.
++
++
++Provided UDA Fields
++-------------------
++
++.. udas:: bugwarrior.services.gitea.GiteaIssue
+
+From 1626a36c15013fc42e369cdc9ef98c23e10845c2 Mon Sep 17 00:00:00 2001
+From: msglm <msglm@techchud.xyz>
+Date: Wed, 22 May 2024 21:00:20 -0500
+Subject: [PATCH 4/4] Remove Six usage and clean the codebase
+
+Suggestions from here are implemented
+https://github.com/GothenburgBitFactory/bugwarrior/pull/1048#pullrequestreview-2070021239
+---
+ bugwarrior/services/gitea.py | 20 ++++----------------
+ 1 file changed, 4 insertions(+), 16 deletions(-)
+
+diff --git a/bugwarrior/services/gitea.py b/bugwarrior/services/gitea.py
+index 445846ff..341ec617 100644
+--- a/bugwarrior/services/gitea.py
++++ b/bugwarrior/services/gitea.py
+@@ -15,7 +15,6 @@
+ import logging
+ import pathlib
+ import re
+-import six
+ import sys
+ from urllib.parse import urlparse
+ from urllib.parse import quote_plus
+@@ -36,11 +35,10 @@ class GiteaConfig(config.ServiceConfig):
+ host = "gitea.com"
+ login: str
+ token: str
+- login: str
+ username: str
+ password: str
+- exclude_repos = []
+- include_repos = []
++ exclude_repos = config.ConfigList([])
++ include_repos = config.ConfigList([])
+
+ def get(self, key, default=None, to_type=None):
+ try:
+@@ -370,7 +368,7 @@ def __init__(self, *args, **kw):
+ 'import_labels_as_tags', default=False, to_type=bool
+ )
+ self.label_template = self.config.get(
+- 'label_template', default='{{label}}', to_type=six.text_type
++ 'label_template', default='{{label}}', to_type=bool
+ )
+ self.project_owner_prefix = self.config.get(
+ 'project_owner_prefix', default=False, to_type=bool
+@@ -380,7 +378,7 @@ def __init__(self, *args, **kw):
+ 'query',
+ default='involves:{user} state:open'.format(
+ user=self.username) if self.involved_issues else '',
+- to_type=six.text_type
++ to_type=str
+ )
+
+ @staticmethod
+@@ -552,13 +550,3 @@ def issues(self):
+ issue_obj.update_extra(extra)
+ yield issue_obj
+
+- @classmethod
+- def validate_config(cls, service_config, target):
+- if 'login' not in service_config:
+- log.critical('[%s] has no \'gitea.login\'' % target)
+- sys.exit(1)
+-
+- if 'token' not in service_config and 'password' not in service_config:
+- log.critical('[%s] has no \'gitea.token\' or \'gitea.password\'' % target)
+- sys.exit(1)
+-
+
+From 17b725774281e9742b786dbcbcf791f7f3dacf61 Mon Sep 17 00:00:00 2001
+From: msglm <msglm@techchud.xyz>
+Date: Thu, 23 May 2024 05:03:39 -0500
+Subject: [PATCH 5/6] Intake Critique and simplify
+
+Remove user+pass auth, token only now.
+Added issue API Querying for writing custom queries
+Added include_assigned,created,mentioned, and review_requested issues
+config settings
+Added ability to limit the number of issues you will query (Gitea limits
+the API by default to 50, but I host my own instance so I raised it)
+get_tags simplified greatly
+---
+ bugwarrior/services/gitea.py | 178 ++++++++++++++++++++---------------
+ 1 file changed, 102 insertions(+), 76 deletions(-)
+
+diff --git a/bugwarrior/services/gitea.py b/bugwarrior/services/gitea.py
+index 341ec617..28a92e96 100644
+--- a/bugwarrior/services/gitea.py
++++ b/bugwarrior/services/gitea.py
+@@ -29,16 +29,28 @@
+
+ log = logging.getLogger(__name__) # pylint: disable-msg=C0103
+
++#TODO: Document this with docstrings
+ class GiteaConfig(config.ServiceConfig):
+ service: typing_extensions.Literal['gitea']
+-
+ host = "gitea.com"
+- login: str
+ token: str
+ username: str
+- password: str
+- exclude_repos = config.ConfigList([])
+- include_repos = config.ConfigList([])
++ include_assigned_issues: bool = False
++ include_created_issues: bool = False
++ include_mentioned_issues: bool = False
++ include_review_requested_issues: bool = False
++ import_labels_as_tags: bool = True
++ involved_issues: bool = False
++ project_owner_prefix: bool = False
++ include_repos: config.ConfigList = config.ConfigList([])
++ exclude_repos: config.ConfigList = config.ConfigList([])
++ label_template = str = '{{label}}'
++ filter_pull_requests: bool = False
++ exclude_pull_requests: bool = False
++ """
++ The maximum number of issues the API may get from the host
++ """
++ issue_limit: int = 100
+
+ def get(self, key, default=None, to_type=None):
+ try:
+@@ -65,7 +77,7 @@ class GiteaClient(ServiceClient):
+ - get_repos:
+ - get_query:
+ - get_issues:
+- - get_directly_assigned_issues:
++ - get_special_issues:
+ - get_comments:
+ - get_pulls:
+ """
+@@ -79,16 +91,8 @@ def __init__(self, host, auth):
+
+ def _api_url(self, path, **context):
+ """ Build the full url to the API endpoint """
+- # TODO add token support
+- if 'basic' in self.auth:
+- (username, password) = self.auth['basic']
+- baseurl = 'https://{user}:{secret}@{host}/api/v1'.format(
+- host=self.host,
+- user=username,
+- secret=quote_plus(password))
+- if 'token' in self.auth:
+- baseurl = 'https://{host}/api/v1'.format(
+- host=self.host)
++ baseurl = 'https://{host}/api/v1'.format(
++ host=self.host)
+ return baseurl + path.format(**context)
+
+ # TODO Modify these for gitea support
+@@ -109,17 +113,17 @@ def get_issues(self, username, repo):
+ '/repos/{username}/{repo}/issues?per_page=100',
+ username=username, repo=repo)
+ return self._getter(url)
++
++ def get_special_issues(self, username, query: str):
++ """ Returns all issues assigned to authenticated user given a specific query.
+
+- def get_directly_assigned_issues(self, username):
+- """ Returns all issues assigned to authenticated user.
+-
+- This will return all issues assigned to the authenticated user
+- regardless of whether the user owns the repositories in which the
+- issues exist.
++ This will return all issues this authenticated user has access to and then
++ filter the issues with the query that the user supplied.
+ """
+- url = self._api_url('/repos/issues/search',
+- username=username, assignee=True)
+- return self._getter(url, passedParams={'assigned': True, 'limit': 100}) #TODO: make the limit configurable
++ logging.info("Querying /repos/issues/search with query: " + query)
++ url = self._api_url('/repos/issues/search?{query}',
++ username=username, query=query)
++ return self._getter(url)
+
+ # TODO close to gitea format: /comments/{id}
+ def get_comments(self, username, repo, number):
+@@ -134,7 +138,7 @@ def get_pulls(self, username, repo):
+ username=username, repo=repo)
+ return self._getter(url)
+
+- def _getter(self, url, subkey=None, passedParams={}):
++ def _getter(self, url, subkey=None):
+ """ Pagination utility. Obnoxious. """
+
+ kwargs = {}
+@@ -145,7 +149,7 @@ def _getter(self, url, subkey=None, passedParams={}):
+ link = dict(next=url)
+
+ while 'next' in link:
+- response = self.session.get(link['next'], params=passedParams, **kwargs)
++ response = self.session.get(link['next'], **kwargs)
+
+ # Warn about the mis-leading 404 error code. See:
+ # https://gitea.com/ralphbean/bugwarrior/issues/374
+@@ -269,6 +273,9 @@ def to_taskwarrior(self):
+ if body:
+ body = body.replace('\r\n', '\n')
+
++ if len(body) < 1:
++ body = "No annotation was provided."
++
+ created = self.parse_date(self.record.get('created_at'))
+ updated = self.parse_date(self.record.get('updated_at'))
+ closed = self.parse_date(self.record.get('closed_at'))
+@@ -295,25 +302,19 @@ def to_taskwarrior(self):
+ self.NAMESPACE: self.extra['namespace'],
+ self.STATE: self.record.get('state', '')
+ }
+-
+ def get_tags(self):
+- tags = []
+-
+- if not self.config.get('import_labels_as_tags'):
+- return tags
++ labels = [label['name'] for label in self.record.get('labels', [])]
++ return self.get_tags_from_labels(labels)
+
+- context = self.record.copy()
+- label_template = Template(self.config.get('label_template'))
+-
+- for label_dict in self.record.get('labels', []):
+- context.update({
+- 'label': self._normalize_label_to_tag(label_dict['name'])
+- })
+- tags.append(
+- label_template.render(context)
+- )
++ def get_default_description(self):
++ log.info('In get_default_description')
++ return self.build_default_description(
++ title=self.record['title'],
++ url=self.get_processed_url(self.record['url']),
++ number=self.record['number'],
++ cls=self.extra['type'],
++ )
+
+- return tags
+
+ def get_default_description(self):
+ log.info('In get_default_description')
+@@ -335,44 +336,42 @@ def __init__(self, *args, **kw):
+
+ auth = {}
+ token = self.config.token
+- self.login = self.config.login
+ if hasattr(self.config, 'token'):
+- token = self.get_password('token', login=self.login)
++ token = self.get_password('token', login=self.config.username)
+ auth['token'] = token
+- elif hasattr(self.config.hasattr, 'password'):
+- password = self.get_password('password', login=self.login)
+- auth['basic'] = (self.login, password)
+ else:
+ #Probably should be called by validate_config, but I don't care to fix that.
+- logging.critical("ERROR! Neither token or password was provided in config!")
++ logging.critical("ERROR! No token was provided in config!")
+ sys.exit(1)
+
++ #TODO: document these with docstrings
+ self.client = GiteaClient(host=self.config.host, auth=auth)
+
+ self.host = self.config.host
+
+ self.exclude_repos = self.config.exclude_repos
++
+ self.include_repos = self.config.include_repos
+
+ self.username = self.config.username
+- self.filter_pull_requests = self.config.get(
+- 'filter_pull_requests', default=False, to_type=bool
+- )
+- self.exclude_pull_requests = self.config.get(
+- 'exclude_pull_requests', default=False, to_type=bool
+- )
+- self.involved_issues = self.config.get(
+- 'involved_issues', default=False, to_type=bool
+- )
+- self.import_labels_as_tags = self.config.get(
+- 'import_labels_as_tags', default=False, to_type=bool
+- )
+- self.label_template = self.config.get(
+- 'label_template', default='{{label}}', to_type=bool
+- )
+- self.project_owner_prefix = self.config.get(
+- 'project_owner_prefix', default=False, to_type=bool
+- )
++
++ self.filter_pull_requests = self.config.filter_pull_requests
++
++ self.exclude_pull_requests = self.config.exclude_pull_requests
++
++ self.involved_issues = self.config.involved_issues
++
++ self.project_owner_prefix = self.config.project_owner_prefix
++
++ self.include_assigned_issues = self.config.include_assigned_issues
++
++ self.include_created_issues = self.config.include_created_issues
++
++ self.include_review_requested_issues = self.config.include_review_requested_issues
++
++ self.import_labels_as_tags = self.config.import_labels_as_tags
++
++ self.label_template = self.config.label_template
+
+ self.query = self.config.get(
+ 'query',
+@@ -384,11 +383,10 @@ def __init__(self, *args, **kw):
+ @staticmethod
+ def get_keyring_service(service_config):
+ #TODO grok this
+- login = service_config.login
+ username = service_config.username
+ host = service_config.host
+- return 'gitea://{login}@{host}/{username}'.format(
+- login=login, username=username, host=host)
++ return 'gitea://{username}@{host}/{username}'.format(
++ username=username, host=host)
+
+ def get_service_metadata(self):
+ return {
+@@ -417,9 +415,9 @@ def get_query(self, query):
+ issues[url] = (repo, issue)
+ return issues
+
+- def get_directly_assigned_issues(self, username):
++ def get_special_issues(self, username, query):
+ issues = {}
+- for issue in self.client.get_directly_assigned_issues(self.username):
++ for issue in self.client.get_special_issues(self.username, query):
+ repos = self.get_repository_from_issue(issue)
+ issues[issue['url']] = (repos, issue)
+ return issues
+@@ -524,10 +522,38 @@ def issues(self):
+ self.get_owned_repo_issues(
+ self.username + '/' + repo)
+ )
+- issues.update(
+- filter(self.filter_issues,
+- self.get_directly_assigned_issues(self.username).items())
+- )
++
++ '''
++ A variable used to represent the attachable HTTP query that can be attached to the /repos/issues/search API end.
++
++ if httpQuery is set to "review_requested=True?mentioned=True" for example, then the /repos/issues/search API end will be told to search for all issues where a review is requested AND where the user is mentioned.
++ '''
++ httpQuery = "limit=" + str(self.config.issue_limit) + "&"
++
++ if self.config.get('include_assigned_issues', True, bool):
++ log.info("assigned was true")
++ issues.update(
++ filter(self.filter_issues,
++ self.get_special_issues(self.username, httpQuery + "assigned=true&").items())
++ )
++ if self.config.get('include_created_issues', True, bool):
++ log.info("created was true")
++ issues.update(
++ filter(self.filter_issues,
++ self.get_special_issues(self.username, httpQuery + "created=true&").items())
++ )
++ if self.config.get('include_mentioned_issues', True, bool):
++ log.info("mentioned was true")
++ issues.update(
++ filter(self.filter_issues,
++ self.get_special_issues(self.username, httpQuery + "mentioned=true&").items())
++ )
++ if self.config.get('include_review_requested_issues', True, bool):
++ log.info("review request was true")
++ issues.update(
++ filter(self.filter_issues,
++ self.get_special_issues(self.username, httpQuery + "review_requested=true&").items())
++ )
+
+ log.info(' Found %i issues.', len(issues)) # these were debug logs
+ issues = list(filter(self.include, issues.values()))
+
+From 3eb6e743c7ee4c7892525c05d880f5d05d3f8600 Mon Sep 17 00:00:00 2001
+From: msglm <msglm@techchud.xyz>
+Date: Thu, 23 May 2024 05:13:33 -0500
+Subject: [PATCH 6/6] Documentation for previous commit
+
+---
+ bugwarrior/docs/services/gitea.rst | 31 +++++++++++++++++++++++++++---
+ 1 file changed, 28 insertions(+), 3 deletions(-)
+
+diff --git a/bugwarrior/docs/services/gitea.rst b/bugwarrior/docs/services/gitea.rst
+index 6ccf2308..19e0930a 100644
+--- a/bugwarrior/docs/services/gitea.rst
++++ b/bugwarrior/docs/services/gitea.rst
+@@ -13,11 +13,9 @@ Here's an example of a Gitea target:
+
+ [user_gitea]
+ service = gitea
+- gitea.login = ralphbean
+ gitea.username = ralphbean
+ gitea.host = git.bean.com #Note: the lack of https, the service will assume HTTPS by default.
+- gitea.password = @oracle:eval:pass show 'git.bean.com'
+- gitea.token = 0000000000000000000000000000000
++ gitea.token = @oracle:eval:pass show 'git.bean.com token'
+
+ The above example is the minimum required to import issues from
+ Gitea. You can also feel free to use any of the
+@@ -117,6 +115,33 @@ to all fields on the Taskwarrior task if needed:
+ See :ref:`field_templates` for more details regarding how templates
+ are processed.
+
++Limit Issues Imported
+++++++++++++++++++++++
++Gitea lets system administrators configure the amount of objects that any given API request will return.
++You may configure the amount to tell Gitea to give to you using the ``issue_limit`` option:
++
++.. config::
++ :fragment: gitea
++
++ gitea.issue_limit = 200
++
++Do note, this will not overwrite what the gitea instance limits you to, it merely lets you set the amount of issues you will import.
++
++
++Including various types of issues
+++++++++++++++++++++++
++
++Gitea has metadata attached to each issue, primarily: If you are assigned to an issue, if you created an issue, if an issue mentions you, and if an issue has a review reqest for you. You may set if each of these traits is worth importing by using the various ``include_*_issues`` options:
++
++.. config::
++ :fragment: gitea
++
++ gitea.include_assigned_issues = true
++ gitea.include_created_issues = true
++ gitea.include_mentioned_issues = true
++ gitea.include_review_requested_issues = true
++
++Each setting will query the API for that trait alone and then add it to your Taskwarrior task list. For example, if you have created issues and mentioned issues off, but assigned issues and review requested issues on: You will only recieve new tasks for the issues you are assigned to do or requested to review, but not for issues you've created or mentioned. Issues that have been assigned to you and created by you would be included though, as these settings merely mark inclusion, not exclusion.
+
+ Provided UDA Fields
+ -------------------