From eea3d21b2290fa8d89a1913f92150a227b5bb662 Mon Sep 17 00:00:00 2001 From: David Lawrence Date: Wed, 12 Nov 2025 15:31:08 -0500 Subject: [PATCH 1/2] feature: Add step to allow auto creating of components that do not yet exist in Jira for a project --- config/config.prod.yaml | 10 ++++++---- jbi/jira/client.py | 1 + jbi/jira/service.py | 12 +++++++++++- jbi/steps.py | 1 + 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/config/config.prod.yaml b/config/config.prod.yaml index fc166d5f..ff5224d4 100644 --- a/config/config.prod.yaml +++ b/config/config.prod.yaml @@ -844,8 +844,9 @@ parameters: jira_project_key: BZFFX jira_components: - set_custom_components: - - "Firefox" + use_bug_component_with_product_prefix: true + use_bug_component: false + create_components: true steps: new: - create_issue @@ -885,8 +886,9 @@ parameters: jira_project_key: BZFFX jira_components: - set_custom_components: - - "Core" + use_bug_component_with_product_prefix: true + use_bug_component: false + create_components: true steps: new: - create_issue diff --git a/jbi/jira/client.py b/jbi/jira/client.py index 607c11b8..9c1155fe 100644 --- a/jbi/jira/client.py +++ b/jbi/jira/client.py @@ -70,6 +70,7 @@ def raise_for_status(self, *args, **kwargs): get_server_info = instrumented_method(Jira.get_server_info) get_project_components = instrumented_method(Jira.get_project_components) + create_component = instrumented_method(Jira.create_component) update_issue = instrumented_method(Jira.update_issue) update_issue_field = instrumented_method(Jira.update_issue_field) set_issue_status = instrumented_method(Jira.set_issue_status) diff --git a/jbi/jira/service.py b/jbi/jira/service.py index 4bac72d3..b3e77b31 100644 --- a/jbi/jira/service.py +++ b/jbi/jira/service.py @@ -350,6 +350,7 @@ def update_issue_components( self, context: ActionContext, components: Iterable[str], + create_components: bool = False, ) -> tuple[Optional[dict], set]: """Attempt to add components to the specified issue @@ -374,7 +375,16 @@ def update_issue_components( missing_components.remove(comp["name"]) if not jira_components: - return None, missing_components + if create_components: + for comp_name in missing_components: + new_comp = self.client.create_component( + project_key=context.jira.project, + name=comp_name, + ) + jira_components.append({"id": new_comp["id"]}) + missing_components.clear() + else: + return None, missing_components resp = self.update_issue_field( context, field="components", value=jira_components diff --git a/jbi/steps.py b/jbi/steps.py index 75f6e20f..7eccd171 100644 --- a/jbi/steps.py +++ b/jbi/steps.py @@ -405,6 +405,7 @@ def maybe_update_components( resp, missing_components = jira_service.update_issue_components( context=context, components=candidate_components, + create_components=parameters.jira_components.create_components ) except requests_exceptions.HTTPError as exc: if getattr(exc.response, "status_code", None) != 400: From 8b0a27cfdb3ba0c9734b84792e6a18ea7ef012ff Mon Sep 17 00:00:00 2001 From: David Lawrence Date: Tue, 18 Nov 2025 18:03:27 -0500 Subject: [PATCH 2/2] fix: Jira.create_component called with project_key and should be just project --- jbi/jira/service.py | 2 +- tests/unit/test_steps.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/jbi/jira/service.py b/jbi/jira/service.py index 504d8649..fe84cb81 100644 --- a/jbi/jira/service.py +++ b/jbi/jira/service.py @@ -380,7 +380,7 @@ def update_issue_components( for comp_name in missing_components: new_comp = self.client.create_component( - project_key=context.jira.project, + project=context.jira.project, name=comp_name, ) jira_components.append({"id": new_comp["id"]}) diff --git a/tests/unit/test_steps.py b/tests/unit/test_steps.py index 2d52d88e..36fba724 100644 --- a/tests/unit/test_steps.py +++ b/tests/unit/test_steps.py @@ -1378,7 +1378,7 @@ def test_maybe_update_components_create_components_normal_component( ) mocked_jira.create_component.assert_called_once_with( - project_key=action_context.jira.project, + project=action_context.jira.project, name="NewComponent", ) mocked_jira.update_issue_field.assert_called_with( @@ -1419,7 +1419,7 @@ def test_maybe_update_components_create_components_prefix_component( ) mocked_jira.create_component.assert_called_once_with( - project_key=action_context.jira.project, + project=action_context.jira.project, name="Firefox::NewComponent", ) mocked_jira.update_issue_field.assert_called_with(