From 1c7bf46d7c0e4bd24d93f35c8354a06dd0714a6c Mon Sep 17 00:00:00 2001 From: Lukas Holecek Date: Thu, 30 Jan 2025 10:05:41 +0100 Subject: [PATCH] Fix updating Jira issues --- examples/config.yaml | 1 + src/retasc/jira_client.py | 6 ++- src/retasc/models/prerequisites/jira_issue.py | 11 +++- tests/test_run.py | 52 ++++++++++++++++++- 4 files changed, 67 insertions(+), 3 deletions(-) diff --git a/examples/config.yaml b/examples/config.yaml index 0423da2..12a0d72 100644 --- a/examples/config.yaml +++ b/examples/config.yaml @@ -4,6 +4,7 @@ product_pages_url: https://pp.example.com jira_url: https://jira.example.com jira_fields: + assignee: assignee description: description labels: labels project: project diff --git a/src/retasc/jira_client.py b/src/retasc/jira_client.py index 96ef4d6..7cecf76 100644 --- a/src/retasc/jira_client.py +++ b/src/retasc/jira_client.py @@ -43,7 +43,11 @@ def edit_issue( """ logger.info("Updating Jira issue %r with fields: %r", issue_key, fields) - self.jira.edit_issue(issue_key, fields, notify_users=notify_users) + base_url = self.jira.resource_url("issue") + url = f"{base_url}/{issue_key}" + self.jira.put( + url, data={"fields": fields}, params={"notifyUsers": notify_users} + ) @tracer.start_as_current_span("JiraClient.create_issue") def create_issue(self, fields: dict) -> dict: diff --git a/src/retasc/models/prerequisites/jira_issue.py b/src/retasc/models/prerequisites/jira_issue.py index e1517ab..76a3021 100644 --- a/src/retasc/models/prerequisites/jira_issue.py +++ b/src/retasc/models/prerequisites/jira_issue.py @@ -37,11 +37,20 @@ def _set_parent_issue(fields: dict, parent_issue_key: str | None = None): fields["parent"] = {"key": parent_issue_key} +def _is_jira_field_up_to_date(current_value, new_value): + if isinstance(new_value, dict): + return all(current_value[k] == v for k, v in new_value.items()) + + return current_value == new_value + + def _edit_issue( issue, fields, context, label: str, parent_issue_key: str | None = None ): to_update = { - k: v for k, v in fields.items() if issue["fields"][k] != v and k != "labels" + k: v + for k, v in fields.items() + if k != "labels" and not _is_jira_field_up_to_date(issue["fields"][k], v) } labels = {label, *fields.get("labels", [])} diff --git a/tests/test_run.py b/tests/test_run.py index ec88841..7414c50 100644 --- a/tests/test_run.py +++ b/tests/test_run.py @@ -362,6 +362,56 @@ def test_run_rule_jira_issue_update_labels(factory, mock_jira): mock_jira.edit_issue.assert_called_once_with("TEST-1", {"labels": expected_labels}) +def test_run_rule_jira_issue_update_complex_field(factory, mock_jira): + jira_issue_prereq = factory.new_jira_issue_prerequisite(""" + assignee: {key: alice} + """) + rule = factory.new_rule(prerequisites=[jira_issue_prereq]) + current_value = {"name": "Bob", "key": "bob"} + mock_jira.search_issues.return_value = [ + { + "key": "TEST-1", + "fields": { + "assignee": current_value, + "labels": ["retasc-id-test_jira_template_1"], + "resolution": None, + }, + } + ] + expected_fields = {"assignee": {"key": "alice"}} + report = call_run() + assert report.data == { + INPUT: { + rule.name: { + "Jira('test_jira_template_1')": { + "issue": "TEST-1", + "update": json.dumps(expected_fields), + "state": "InProgress", + }, + "state": "InProgress", + } + } + } + mock_jira.create_issue.assert_not_called() + mock_jira.edit_issue.assert_called_once_with("TEST-1", expected_fields) + + current_value["key"] = "alice" + current_value["name"] = "Alice" + report = call_run() + assert report.data == { + INPUT: { + rule.name: { + "Jira('test_jira_template_1')": { + "issue": "TEST-1", + "state": "InProgress", + }, + "state": "InProgress", + } + } + } + mock_jira.edit_issue.assert_called_once() + + def test_run_rule_jira_issue_completed(factory, mock_jira): jira_issue_prereq = factory.new_jira_issue_prerequisite(DUMMY_ISSUE) rule = factory.new_rule(prerequisites=[jira_issue_prereq]) @@ -510,7 +560,7 @@ def test_run_rule_jira_issue_unsupported_fields(factory): expected_error = ( f"Jira template {jira_issue_prereq.template!r} contains" " unsupported fields: 'field_1', 'field_2'" - "\nSupported fields: 'description', 'labels', 'project', 'summary'" + "\nSupported fields: 'assignee', 'description', 'labels', 'project', 'summary'" ) with raises(RuntimeError, match=expected_error): call_run()