Skip to content

Commit d459e7a

Browse files
committed
replace Service.get_kerying_service by ServiceConfig.KEYRING_SERVICE
1 parent a704b45 commit d459e7a

37 files changed

Lines changed: 69 additions & 147 deletions

bugwarrior/command.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from lockfile import LockTimeout
1212
from lockfile.pidlockfile import PIDLockFile
1313

14-
from bugwarrior.collect import aggregate_issues, get_service
14+
from bugwarrior.collect import aggregate_issues
1515
from bugwarrior.config import get_config_path, get_keyring, load_config
1616
from bugwarrior.db import get_defined_udas_as_strings, synchronize
1717

@@ -162,9 +162,7 @@ def targets() -> Iterator[str]:
162162
for service_config in config.service_configs:
163163
for value in dict(service_config).values():
164164
if isinstance(value, str) and '@oracle:use_keyring' in value:
165-
yield get_service(service_config.service).get_keyring_service(
166-
service_config
167-
)
165+
yield service_config.keyring_service
168166

169167

170168
@vault.command()

bugwarrior/config/schema.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,10 +197,16 @@ class ServiceConfig(_ServiceConfig):
197197
.. _Pydantic: https://docs.pydantic.dev/latest/
198198
"""
199199

200+
KEYRING_SERVICE: typing.ClassVar[str]
201+
200202
# Added before validation (computed field)
201203
service: str
202204
target: str
203205

206+
@property
207+
def keyring_service(self) -> str:
208+
return self.KEYRING_SERVICE.format(**self.model_dump())
209+
204210
# Added during validation (computed field)
205211
templates: dict[str, str] = {}
206212

bugwarrior/docs/other-services/tutorial.rst

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ Now define an initial configuration schema as follows. Don't worry, we're about
7575
7676
class GitbugConfig(config.ServiceConfig):
7777
service: typing.Literal['gitbug']
78+
KEYRING_SERVICE = 'gitbug://{path}'
7879
7980
path: pathlib.Path
8081
@@ -93,6 +94,8 @@ The ``service`` attribute is how bugwarrior will know to assign a given section
9394

9495
The ``path`` is the only particular detail required to access our local git-bug instance. You'll likely need additional details such as a username and token to authenticate to the service. Look at how you accessed the API in step 1 and ask yourself which components need to be configurable.
9596

97+
The ``KEYRING_SERVICE`` attribute is a format string that returns a string identifier for secrets in the keyring. Ideally, this string uniquely identifies a given instance of the service when it is possible to have multiple instances of the service configured. Service configuration values may be referenced by field name, such as ``{path}``.
98+
9699
The ``import_labels_as_tags`` and ``port`` attributes create optional configuration fields to allow customization of bugwarrior behavior.
97100

98101
.. note::
@@ -199,10 +202,6 @@ Now for the main service class which bugwarrior will invoke to fetch issues.
199202
port=self.config.port,
200203
annotation_comments=self.main_config.annotation_comments)
201204
202-
@staticmethod
203-
def get_keyring_service(config):
204-
return f'gitbug://{config.path}'
205-
206205
def issues(self):
207206
for issue in self.client.get_issues():
208207
comments = issue.pop('comments')
@@ -217,11 +216,9 @@ Now for the main service class which bugwarrior will invoke to fetch issues.
217216
218217
yield self.get_issue_for_record(issue)
219218
220-
Here we see three required class attributes and two required methods.
221-
222-
The ``API_VERSION`` is set to the latest, while the other two attributes point to our previously defined classes.
219+
Here we see three required class attributes and one required method.
223220

224-
The ``get_keyring_service`` method returns a string identifier for secrets in the keyring. Ideally, this string uniquely identifies a given instance of the service when it is possible to have multiple instances of the service configured.
221+
The ``API_VERSION`` is set to the latest, while ``ISSUE_CLASS`` and ``CONFIG_SCHEMA`` point to our previously defined classes.
225222

226223
The ``issues`` method is a generator which yields individual issue dictionaries.
227224

bugwarrior/services/__init__.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -283,10 +283,9 @@ def get_secret(self, key: str, login: str = 'nousername') -> str:
283283
applicable.
284284
"""
285285
password = getattr(self.config, key)
286-
keyring_service = self.get_keyring_service(self.config)
287286
if not password or password.startswith("@oracle:"):
288287
password = secrets.get_service_password(
289-
keyring_service, login, oracle=password
288+
self.config.keyring_service, login, oracle=password
290289
)
291290
return password
292291

@@ -298,7 +297,7 @@ def get_issue_for_record(
298297
:param `record`: Foreign record.
299298
:param `extra`: Computed data which is not directly from the service.
300299
"""
301-
extra = extra if extra is not None else {}
300+
extra = extra or {}
302301
return self.ISSUE_CLASS(record, self.config, self.main_config, extra=extra)
303302

304303
def build_annotations(
@@ -359,12 +358,6 @@ def issues(self) -> Iterator[T_Issue]:
359358
"""
360359
raise NotImplementedError()
361360

362-
@staticmethod
363-
@abc.abstractmethod
364-
def get_keyring_service(config: schema.ServiceConfig) -> str:
365-
"""Return the keyring name for this service."""
366-
raise NotImplementedError
367-
368361

369362
class Client:
370363
"""Base class for making requests to service API's.

bugwarrior/services/azuredevops.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
class AzureDevopsConfig(config.ServiceConfig):
2020
service: Literal['azuredevops']
21+
KEYRING_SERVICE = "azuredevops://{organization}@{host}"
2122
PAT: str
2223
project: EscapedStr
2324
organization: EscapedStr
@@ -259,7 +260,3 @@ def issues(self) -> Iterator[AzureDevopsIssue]:
259260
}
260261
issue_obj.extra.update(extra)
261262
yield issue_obj
262-
263-
@staticmethod
264-
def get_keyring_service(config: AzureDevopsConfig) -> str:
265-
return f"azuredevops://{config.organization}@{config.host}"

bugwarrior/services/bitbucket.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class BitbucketConfig(config.ServiceConfig):
1515
filter_merge_requests: Union[bool, Literal['Undefined']] = 'Undefined'
1616

1717
service: Literal['bitbucket']
18+
KEYRING_SERVICE = "bitbucket://{key}/{username}"
1819

1920
username: str
2021

@@ -116,10 +117,6 @@ def __init__(
116117
'headers': {'Authorization': f"Bearer {response['access_token']}"}
117118
}
118119

119-
@staticmethod
120-
def get_keyring_service(config: BitbucketConfig) -> str:
121-
return f"bitbucket://{config.key}/{config.username}"
122-
123120
def filter_repos(self, repo_tag: str) -> bool:
124121
repo = repo_tag.split('/').pop()
125122

bugwarrior/services/bts.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
class BTSConfig(config.ServiceConfig):
2121
service: typing.Literal['bts']
22+
KEYRING_SERVICE = 'bts://'
2223

2324
email: pydantic.EmailStr = ''
2425
packages: config.ConfigList = []
@@ -107,10 +108,6 @@ class BTSService(Service[BTSIssue]):
107108
ISSUE_CLASS = BTSIssue
108109
CONFIG_SCHEMA = BTSConfig
109110

110-
@staticmethod
111-
def get_keyring_service(config: BTSConfig) -> str:
112-
return 'bts://'
113-
114111
def _record_for_bug(self, bug: debianbts.Bugreport) -> dict[str, Any]:
115112
return {
116113
'number': bug.bug_num,

bugwarrior/services/bz.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def validate_url(value: str) -> str:
3434

3535
class BugzillaConfig(config.ServiceConfig):
3636
service: typing.Literal['bugzilla']
37+
KEYRING_SERVICE = "bugzilla://{username}@{base_uri}"
3738
username: str
3839
base_uri: OptionalSchemeUrl
3940

@@ -158,10 +159,6 @@ def __init__(
158159
password = self.get_secret('password', self.config.username)
159160
self.bz.login(self.config.username, password)
160161

161-
@staticmethod
162-
def get_keyring_service(config: BugzillaConfig) -> str:
163-
return f"bugzilla://{config.username}@{config.base_uri}"
164-
165162
def get_owner(self, issue: dict[str, Any]) -> str:
166163
return issue['assigned_to']
167164

bugwarrior/services/clickup.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
class ClickupConfig(config.ServiceConfig):
1616
service: typing.Literal["clickup"]
17+
KEYRING_SERVICE = "clickup://"
1718
token: str
1819
team_id: int
1920

@@ -130,10 +131,6 @@ def __init__(
130131
super().__init__(config, main_config)
131132
self.client = ClickupClient(token=self.get_secret('token'))
132133

133-
@staticmethod
134-
def get_keyring_service(config: ClickupConfig) -> str:
135-
return "clickup://"
136-
137134
def is_assigned(self, issue: dict) -> bool:
138135
if not self.config.only_if_assigned:
139136
return True

bugwarrior/services/deck.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
class NextcloudDeckConfig(config.ServiceConfig):
1616
service: typing.Literal['deck']
17+
KEYRING_SERVICE = 'deck://{username}@{base_uri}'
1718
base_uri: config.StrippedTrailingSlashUrl
1819
username: str
1920

@@ -141,10 +142,6 @@ def __init__(
141142
password=self.config.password,
142143
)
143144

144-
@staticmethod
145-
def get_keyring_service(config: NextcloudDeckConfig) -> str:
146-
return f'deck://{config.username}@{config.base_uri}'
147-
148145
def get_owner(self, issue: NextcloudDeckIssue) -> str | None:
149146
rec = issue.record
150147
if rec.get('assignedUsers'):

0 commit comments

Comments
 (0)