From 66707894d38b33cd6e699cef63cb7d85da9aaabd Mon Sep 17 00:00:00 2001 From: 10zingpd Date: Thu, 19 Mar 2026 16:26:14 -0400 Subject: [PATCH 1/3] Fix Jira sync to handle closed tickets and correct transition matching - Fix transition matching to check destination state name instead of transition name, resolving failures when closing tickets - Add set_fix_version() to tag already-closed tickets with fix version instead of skipping them - Include resolution "Done" in close transition payload - Add Jira release page URL to summary output Co-Authored-By: Claude Sonnet 4.6 --- etc/sync_jira_release.py | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/etc/sync_jira_release.py b/etc/sync_jira_release.py index f951a4504..a9611c87e 100644 --- a/etc/sync_jira_release.py +++ b/etc/sync_jira_release.py @@ -136,6 +136,19 @@ def get_ticket_status(ticket_key): return None +def set_fix_version(ticket_key, version_id): + """Set fix version on a ticket without transitioning it.""" + update_url = f"{JIRA_BASE_URL}/rest/api/3/issue/{ticket_key}" + update_payload = {"fields": {"fixVersions": [{"id": version_id}]}} + + response = requests.put(update_url, auth=jira_auth, headers={"Content-Type": "application/json"}, json=update_payload) + + if response.status_code != 204: + print(f"⚠️ Failed to set fix version for {ticket_key}") + return False + return True + + def set_fix_version_and_close(ticket_key, version_id): """ Step 1: Set fix version while in "Awaiting Release" @@ -156,14 +169,18 @@ def set_fix_version_and_close(ticket_key, version_id): response = requests.get(transitions_url, auth=jira_auth) transitions = response.json().get("transitions", []) - close_transition = next((t for t in transitions if t["name"].lower() == "closed"), None) + close_transition = next( + (t for t in transitions if t.get("to", {}).get("name", "").lower() == "closed"), + None, + ) if not close_transition: - print(f"⚠️ No 'Closed' transition for {ticket_key}") + available = [f"{t['name']} → {t.get('to', {}).get('name', '?')}" for t in transitions] + print(f"⚠️ No transition to 'Closed' status for {ticket_key}. Available: {available}") return False - # Step 3: Transition to Closed - payload = {"transition": {"id": close_transition["id"]}} + # Step 3: Transition to Closed with Resolution "Done" + payload = {"transition": {"id": close_transition["id"]}, "fields": {"resolution": {"name": "Done"}}} response = requests.post(transitions_url, auth=jira_auth, headers={"Content-Type": "application/json"}, json=payload) @@ -216,6 +233,7 @@ def main(version_input): # 5. Process tickets in "Awaiting Release" print("🔄 Processing tickets...\n") closed_count = 0 + tagged_count = 0 skipped_count = 0 for ticket_key in ticket_keys: @@ -228,6 +246,13 @@ def main(version_input): closed_count += 1 else: print(f" ❌ Failed to close {ticket_key}") + elif status == "Closed": + print(f" {ticket_key}: {status} → Tagging fix version...") + if set_fix_version(ticket_key, version_id): + print(f" ✅ {ticket_key} tagged with fix version Python SDK {version}") + tagged_count += 1 + else: + print(f" ❌ Failed to tag fix version for {ticket_key}") else: print(f" ⏭️ {ticket_key}: {status} (skipped)") skipped_count += 1 @@ -237,8 +262,10 @@ def main(version_input): print("🎉 Release sync complete!") print(f" Version: Python SDK {version}") print(f" Tickets closed: {closed_count}") + print(f" Tickets tagged (already closed): {tagged_count}") print(f" Tickets skipped: {skipped_count}") print(f" Total tickets: {len(ticket_keys)}") + print(f" Release page: {JIRA_BASE_URL}/projects/{JIRA_PROJECT_KEY}/versions/{version_id}/tab/release-report-all-issues") print(f"{'=' * 60}") From b0469162e253ad61a3c47dbc8e2f647a157d0662 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 19 Mar 2026 20:31:03 +0000 Subject: [PATCH 2/3] refactor: eliminate code duplication in set_fix_version_and_close set_fix_version_and_close was duplicating the fix-version PUT request that the new set_fix_version() helper encapsulates. Refactor step 1 to call set_fix_version() instead. Co-Authored-By: Claude Sonnet 4.6 --- etc/sync_jira_release.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/etc/sync_jira_release.py b/etc/sync_jira_release.py index a9611c87e..3e9081f5d 100644 --- a/etc/sync_jira_release.py +++ b/etc/sync_jira_release.py @@ -155,13 +155,7 @@ def set_fix_version_and_close(ticket_key, version_id): Step 2: Transition ticket to Closed """ # Step 1: Set fix version first - update_url = f"{JIRA_BASE_URL}/rest/api/3/issue/{ticket_key}" - update_payload = {"fields": {"fixVersions": [{"id": version_id}]}} - - response = requests.put(update_url, auth=jira_auth, headers={"Content-Type": "application/json"}, json=update_payload) - - if response.status_code != 204: - print(f"⚠️ Failed to set fix version for {ticket_key}") + if not set_fix_version(ticket_key, version_id): return False # Step 2: Get available transitions From 70d1f875a6d0b9b22c82a1ab2acdd1c9795a36f6 Mon Sep 17 00:00:00 2001 From: 10zingpd Date: Thu, 19 Mar 2026 16:39:16 -0400 Subject: [PATCH 3/3] Address review feedback: additive fixVersions and transitions HTTP check - Use update.fixVersions.add instead of fields.fixVersions to append the fix version rather than replacing existing ones - Refactor set_fix_version_and_close to call set_fix_version() directly, removing the duplicated PUT logic - Add HTTP status check before parsing the transitions GET response Co-Authored-By: Claude Sonnet 4.6 --- etc/sync_jira_release.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/etc/sync_jira_release.py b/etc/sync_jira_release.py index 3e9081f5d..700019f4b 100644 --- a/etc/sync_jira_release.py +++ b/etc/sync_jira_release.py @@ -139,7 +139,7 @@ def get_ticket_status(ticket_key): def set_fix_version(ticket_key, version_id): """Set fix version on a ticket without transitioning it.""" update_url = f"{JIRA_BASE_URL}/rest/api/3/issue/{ticket_key}" - update_payload = {"fields": {"fixVersions": [{"id": version_id}]}} + update_payload = {"update": {"fixVersions": [{"add": {"id": version_id}}]}} response = requests.put(update_url, auth=jira_auth, headers={"Content-Type": "application/json"}, json=update_payload) @@ -154,7 +154,7 @@ def set_fix_version_and_close(ticket_key, version_id): Step 1: Set fix version while in "Awaiting Release" Step 2: Transition ticket to Closed """ - # Step 1: Set fix version first + # Step 1: Set fix version first (additive — preserves any existing fix versions) if not set_fix_version(ticket_key, version_id): return False @@ -162,6 +162,10 @@ def set_fix_version_and_close(ticket_key, version_id): transitions_url = f"{JIRA_BASE_URL}/rest/api/3/issue/{ticket_key}/transitions" response = requests.get(transitions_url, auth=jira_auth) + if response.status_code != 200: + print(f"⚠️ Failed to fetch transitions for {ticket_key} (HTTP {response.status_code})") + return False + transitions = response.json().get("transitions", []) close_transition = next( (t for t in transitions if t.get("to", {}).get("name", "").lower() == "closed"),