-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Because issue field configuration in JIRA is highly dynamic and customizable, Bugjira needs to be able to retrieve field configuration data from an external source. This patch adds support for that operation, and also defines a very minimal set of field configuration data. The classes in bugjira/field.py will be heavily extended. Once we can make Bugjira aware of the available fields in the associated JIRA and Bugzilla backends, we will be able to add support for querying and updating those field attributes in BugjiraIssue objects. The module that loads the field configuration data is designed as a plugin. The plugin included in the source code loads json from a local file when the Bugjira instance is created. Another approach would be to load field configuration by querying a JIRA instance directly, possibly dynamically updating the field info periodically or even each time a BugjiraIssue's fields are accessed. These alternate field info access approaches could be coded into an external library that implements the plugin interface, thus allowing us to decouple the public Bugjira code from any user's particular JIRA instance configuration.
- Loading branch information
Showing
19 changed files
with
504 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"bugzilla_field_data": [ | ||
{"name": "product"}, | ||
{"name": "component"}, | ||
{"name": "status"} | ||
], | ||
"jira_field_data": [ | ||
{"name": "Issue Type", "jira_field_id": "issuetype"}, | ||
{"name": "Assignee", "jira_field_id": "assignee"} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
from pydantic import BaseModel, ConfigDict, constr | ||
|
||
"""The objects in this module are used internally to represent field | ||
configuration information for the bugzilla and jira backends used by bugjira. | ||
""" | ||
|
||
|
||
class BugjiraField(BaseModel): | ||
"""The base field class | ||
""" | ||
model_config = ConfigDict(extra="forbid") | ||
name: constr(strip_whitespace=True, min_length=1) | ||
|
||
|
||
class BugzillaField(BugjiraField): | ||
pass | ||
|
||
|
||
class JiraField(BugjiraField): | ||
jira_field_id: constr(strip_whitespace=True, min_length=1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
from bugjira.field import BugzillaField, JiraField | ||
|
||
_json_generator = None | ||
|
||
|
||
def register_json_generator(generator, config): | ||
"""Registers a generator class to serve as the source for json that | ||
specifies field configuration data. | ||
:param generator: The generator to register | ||
:type generator: class | ||
:param config: The config to use when instantiating the generator class | ||
:type config: dict | ||
""" | ||
global _json_generator | ||
_json_generator = generator(config=config) | ||
|
||
|
||
def get_bugzilla_fields() -> list[BugzillaField]: | ||
fields = [] | ||
if _json_generator is not None: | ||
for field_data in _json_generator.get_bugzilla_fields_json(): | ||
fields.append(BugzillaField(**field_data)) | ||
return fields | ||
|
||
|
||
def get_jira_fields() -> list[JiraField]: | ||
fields = [] | ||
if _json_generator is not None: | ||
for field_data in _json_generator.get_jira_fields_json(): | ||
fields.append(JiraField(**field_data)) | ||
return fields |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import json | ||
from typing import List | ||
|
||
from pydantic import BaseModel, ConfigDict, ValidationError | ||
|
||
from bugjira import field_factory | ||
from bugjira.exceptions import JsonGeneratorException | ||
from bugjira.field import BugzillaField, JiraField | ||
|
||
|
||
def get_generator(): | ||
"""Plugin modules must define the get_generator() method, which should | ||
return a generator class. | ||
""" | ||
return JsonGenerator | ||
|
||
|
||
class JsonGenerator: | ||
"""This is the default plugin class that provides json to field_factory | ||
module for generating lists of BugjiraField objects. It loads its data | ||
from a json file, specified in the input config dict under the | ||
"field_data_path" top level key. | ||
The static `register` method registers the class with the field_factory | ||
module. | ||
Replacement plugin classes should implement the `get_bugzilla_fields_json` | ||
and `get_jira_fields_json` instance methods, as well as the static | ||
`register` method. | ||
""" | ||
def __init__(self, config={}): | ||
self.config = config | ||
self.field_data = {} | ||
if config: | ||
field_data_path = config.get("field_data_path", "") | ||
if field_data_path: | ||
with open(field_data_path, "r") as file: | ||
field_data = json.load(file) | ||
try: | ||
# use pydantic class to validate the input data | ||
ValidFieldData(**field_data) | ||
except ValidationError: | ||
raise JsonGeneratorException( | ||
"Invalid field data detected" | ||
) | ||
self.field_data = field_data | ||
|
||
def get_bugzilla_fields_json(self): | ||
return self.field_data.get("bugzilla_field_data", []) | ||
|
||
def get_jira_fields_json(self): | ||
return self.field_data.get("jira_field_data", []) | ||
|
||
@staticmethod | ||
def register(config): | ||
field_factory.register_json_generator(JsonGenerator, config) | ||
|
||
|
||
class ValidFieldData(BaseModel): | ||
"""This class defines the valid format for the json data loaded by the | ||
JsonGenerator class | ||
""" | ||
model_config = ConfigDict(extra="forbid") | ||
bugzilla_field_data: List[BugzillaField] | ||
jira_field_data: List[JiraField] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import importlib | ||
|
||
from bugjira.exceptions import PluginLoaderException | ||
|
||
|
||
def import_module(name): | ||
"""Use importlib.import_module to import a plugin class | ||
:param name: The fully qualified module name to import | ||
:type name: str | ||
:return: The module returned from the importlib.import_module method | ||
:rtype: module | ||
""" | ||
return importlib.import_module(name) | ||
|
||
|
||
def load_plugin(config={}): | ||
"""Load a plugin using configuration in the supplied config dict. An empty | ||
config will result in loading the default json_generator module. | ||
:param config: A Bugjira config dict, defaults to {}. Cannot be None. | ||
:type config: dict, optional | ||
""" | ||
|
||
if config is None: | ||
raise PluginLoaderException("cannot load plugin with config=None") | ||
|
||
# default to the bugjira-supplied default json_generator module | ||
module_name = config.get("json_generator_module", | ||
"bugjira.json_generator") | ||
try: | ||
imported_module = import_module(module_name) | ||
plugin = imported_module.get_generator() | ||
except ModuleNotFoundError: | ||
raise PluginLoaderException( | ||
f"Could not load module named '{module_name}'" | ||
) | ||
plugin.register(config=config) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,5 +3,6 @@ | |
"api_key": ""}, | ||
"jira": { | ||
"URL": "", | ||
"token_auth": ""} | ||
} | ||
"token_auth": ""}, | ||
"json_generator_module": "" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"bugzilla_field_data": [ | ||
{"name": "product"}, | ||
{"name": "component"}, | ||
{"name": "status"} | ||
], | ||
"jira_field_data": [ | ||
{"name": "Issue Type", "jira_field_id": "issuetype"}, | ||
{"name": "Assignee", "jira_field_id": "assignee"} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.