Update fields
This commit is contained in:
		| @@ -40,6 +40,30 @@ from dataclasses import dataclass | ||||
| from enum import Enum | ||||
| from typing import Any, Callable | ||||
|  | ||||
| from jira import Issue | ||||
| from jira.resources import CustomFieldOption, User | ||||
|  | ||||
|  | ||||
| class DeploymentRequirements(Enum): | ||||
|     """Checklist of deployment requirements for the Jira 'Deployment Requirements' multi-select field.""" | ||||
|     CODE_REVIEW_COMPLETED = "Code Review Completed" | ||||
|     UNIT_TESTS_PASSED = "Unit Tests Passed" | ||||
|     QA_SIGN_OFF = "QA Sign-off" | ||||
|     DOCUMENTATION_UPDATED = "Documentation Updated" | ||||
|     SECURITY_SCAN_APPROVED = "Security Scan Approved" | ||||
|     CHANGE_MANAGEMENT_TICKET_LINKED = "Change Management Ticket Linked" | ||||
|  | ||||
|  | ||||
| class ReleaseTrain(Enum): | ||||
|     """Valid release train options for the Jira 'Release Train' single-select field.""" | ||||
|     ALPHA_TRAIN = "Alpha Train" | ||||
|     BETA_TRAIN = "Beta Train" | ||||
|     GAMMA_TRAIN = "Gamma Train" | ||||
|     STABLE_TRAIN = "Stable Train" | ||||
|  | ||||
|     def __str__(self): | ||||
|         return self.value | ||||
|  | ||||
|  | ||||
| class FieldType(Enum): | ||||
|     """ | ||||
| @@ -68,9 +92,13 @@ class FieldType(Enum): | ||||
|     LABELS = "labels" | ||||
|  | ||||
| def single_select_formatter(value: Any): | ||||
|     if isinstance(value, Enum): | ||||
|         return {"value": value.value} | ||||
|     return {"value": value} | ||||
|  | ||||
| def multi_select_formatter(values: Any): | ||||
|     if all(isinstance(v, Enum) for v in values): | ||||
|         return [{"value": v.value} for v in values] | ||||
|     return [{"value": value} for value in (values if isinstance(values, list) else [values])] | ||||
|  | ||||
| def user_formatter(value: Any): | ||||
| @@ -91,6 +119,35 @@ FIELD_FORMATTERS = { | ||||
| } | ||||
|  | ||||
|  | ||||
| def get_single_select_formatter(value: CustomFieldOption) -> str: | ||||
|     if not isinstance(value, CustomFieldOption): | ||||
|         raise ValueError(f"Expected CustomFieldOption, got {type(value)}") | ||||
|     return value.value | ||||
|  | ||||
|  | ||||
| def get_multi_select_formatter(values: list[CustomFieldOption]) -> list[str]: | ||||
|     if not isinstance(values, list): | ||||
|         raise ValueError(f"Expected list of CustomFieldOption, got {type(values)}") | ||||
|     if not all(isinstance(v, CustomFieldOption) for v in values): | ||||
|         raise ValueError("All items in the list must be CustomFieldOption instances") | ||||
|     return [get_single_select_formatter(v) for v in values] | ||||
|  | ||||
|  | ||||
| def get_user_formatter(user: User) -> dict: | ||||
|     if not isinstance(user, User): | ||||
|         raise ValueError(f"Expected User, got {type(user)}") | ||||
|     return user.name | ||||
|  | ||||
|  | ||||
| GET_FIELD_FORMATTERS = { | ||||
|     FieldType.TEXT: lambda v: v, | ||||
|     FieldType.SINGLE_SELECT: get_single_select_formatter, | ||||
|     FieldType.MULTI_SELECT: get_multi_select_formatter, | ||||
|     FieldType.USER: get_user_formatter, | ||||
|     FieldType.LABELS: lambda v: v, | ||||
| } | ||||
|  | ||||
|  | ||||
| class JiraFields(Enum): | ||||
|     """ | ||||
|     Enumeration of high-level Jira field names used in the CLI. | ||||
| @@ -154,6 +211,10 @@ class JiraFieldInfo: | ||||
|     def formatter(self) -> Callable[[Any], Any]: | ||||
|         return FIELD_FORMATTERS[self.field_type] | ||||
|  | ||||
|     @property | ||||
|     def get_field_formatter(self) -> Callable[[Any], Any]: | ||||
|         return GET_FIELD_FORMATTERS[self.field_type] | ||||
|  | ||||
|  | ||||
| FIELD_REGISTRY = { | ||||
|     JiraFields.RELEASE_TRAIN: JiraFieldInfo( | ||||
| @@ -171,6 +232,34 @@ FIELD_REGISTRY = { | ||||
| } | ||||
|  | ||||
|  | ||||
| def get_field(issue: Issue, name: JiraFields) -> JiraFieldInfo: | ||||
|     """ | ||||
|     Retrieve a field from a Jira issue and format it according to FieldType. | ||||
|  | ||||
|     Args: | ||||
|         issue (Issue): Jira issue instance (from jira-python). | ||||
|         name (JiraFields): Logical Jira field enum member. | ||||
|  | ||||
|     Returns: | ||||
|         Any: The formatted field data (e.g. str, list, dict) appropriate to the type. | ||||
|  | ||||
|     Raises: | ||||
|         ValueError: If the field name is not a valid JiraFields enum member | ||||
|         AttributeError: If the issue does not have the field | ||||
|     """ | ||||
|     if not isinstance(name, JiraFields): | ||||
|         raise ValueError(f"Expected JiraFields enum, got {type(name)}") | ||||
|     try: | ||||
|         info = FIELD_REGISTRY[name] | ||||
|     except KeyError: | ||||
|         raise ValueError(f"Field {name} is not registered in FIELD_REGISTRY") | ||||
|     try: | ||||
|         data = getattr(issue.fields, info.field_id) | ||||
|     except AttributeError: | ||||
|         raise ValueError(f"Issue does not have field {name} ({FIELD_REGISTRY[name].field_id})") | ||||
|     return info.get_field_formatter(data) | ||||
|  | ||||
|  | ||||
| class UpdateFields: | ||||
|     """ | ||||
|     Builder class for constructing Jira issue field update payloads. | ||||
|   | ||||
							
								
								
									
										30
									
								
								cli/fields_test.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								cli/fields_test.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| from jira import JIRA | ||||
| from rich.console import Console | ||||
|  | ||||
| from fields import JiraFields as jf | ||||
| from fields import DeploymentRequirements as dr | ||||
| from fields import ReleaseTrain as rt | ||||
| from fields import UpdateFields, get_field | ||||
| from jql_utils import load_config | ||||
|  | ||||
|  | ||||
| config = load_config() | ||||
| console = Console(color_system="truecolor") | ||||
| jira = JIRA(server=config["server"], basic_auth=(config["username"], config["token"])) | ||||
|  | ||||
|  | ||||
| tick = jira.issue("AETHER-1") | ||||
|  | ||||
| deployment_requirements = get_field(tick, jf.DEPLOYMENT_REQUIREMENTS) | ||||
| reporter = get_field(tick, jf.REPORTER) | ||||
|  | ||||
| update_fields = UpdateFields() | ||||
| update_fields.add_field(jf.RELEASE_TRAIN, rt.GAMMA_TRAIN) | ||||
| update_fields.add_field( | ||||
|     jf.DEPLOYMENT_REQUIREMENTS, [dr.CODE_REVIEW_COMPLETED, dr.QA_SIGN_OFF] | ||||
| ) | ||||
|  | ||||
| tick.update(fields=update_fields.as_dict()) | ||||
|  | ||||
| for name, value in tick.raw["fields"].items(): | ||||
|     console.print(f"[bold green]{name}[/bold green]: {value}") | ||||
		Reference in New Issue
	
	Block a user