@@ -78,18 +78,101 @@ def get_task_details(task_id: str) -> dict | None:
7878 logger .error (f"Failed to connect to Jira: { e } " )
7979 return None
8080
81+ def _extract_text_from_adf (body ):
82+ """
83+ Extract plain text from Atlassian Document Format (very simplified).
84+ """
85+ if isinstance (body , str ):
86+ return body
87+ if isinstance (body , dict ):
88+ parts = []
89+ for block in body .get ("content" , []):
90+ for item in block .get ("content" , []):
91+ txt = item .get ("text" )
92+ if txt :
93+ parts .append (txt )
94+ return "\n " .join (parts )
95+ return ""
96+
97+ def _current_account_id () -> str | None :
98+ try :
99+ jira_url = os .environ ["JIRA_URL" ].rstrip ("/" )
100+ auth , headers = _auth_headers ()
101+ r = requests .get (f"{ jira_url } /rest/api/3/myself" , headers = headers , auth = auth , timeout = 10 )
102+ if r .status_code == 200 :
103+ return r .json ().get ("accountId" )
104+ except Exception :
105+ pass
106+ return None
107+
108+ def _remove_previous_ai_comments (jira_url : str , task_id : str , marker : str , account_id : str | None ):
109+ auth , headers = _auth_headers ()
110+ try :
111+ resp = requests .get (
112+ f"{ jira_url } /rest/api/3/issue/{ task_id } /comment?maxResults=100" ,
113+ headers = headers , auth = auth , timeout = 20
114+ )
115+ if resp .status_code != 200 :
116+ logger .debug (f"[AI Comment] List comments status={ resp .status_code } " )
117+ return
118+ data = resp .json ()
119+ removed = 0
120+ for c in data .get ("comments" , []):
121+ cid = c .get ("id" )
122+ author_id = c .get ("author" , {}).get ("accountId" )
123+ body_text = _extract_text_from_adf (c .get ("body" ))
124+ if marker in body_text and (account_id is None or author_id == account_id ):
125+ try :
126+ d = requests .delete (
127+ f"{ jira_url } /rest/api/3/issue/{ task_id } /comment/{ cid } " ,
128+ headers = headers , auth = auth , timeout = 15
129+ )
130+ if d .status_code in (204 , 200 ):
131+ removed += 1
132+ else :
133+ logger .debug (f"[AI Comment] Delete { cid } status={ d .status_code } " )
134+ except Exception as e :
135+ logger .debug (f"[AI Comment] Delete { cid } exception: { e } " )
136+ if removed :
137+ logger .info (f"Removed { removed } previous AI comment(s)." )
138+ except Exception as e :
139+ logger .debug (f"[AI Comment] Cleanup failed: { e } " )
140+
141+
81142def add_comment (task_id : str , comment : str ):
143+ """
144+ Adds (replaces) AI assessment comment:
145+ - Deletes previous comments containing marker (and authored by this user if detectable)
146+ - Posts a fresh one.
147+ """
82148 logger .info (f"Adding comment to Jira task { task_id } ..." )
83149 try :
84150 jira_url = os .environ ["JIRA_URL" ].rstrip ("/" )
85151 auth , headers = _auth_headers ()
86- api_url = f"{ jira_url } /rest/api/2/issue/{ task_id } /comment"
152+
153+ marker = os .getenv ("JIRA_AI_COMMENT_TAG" , "🤖 AI Assessment" )
154+ if marker not in comment :
155+ comment = f"{ marker } \n \n { comment } "
156+
157+ account_id = _current_account_id ()
158+ _remove_previous_ai_comments (jira_url , task_id , marker , account_id )
159+
160+ # Use v3 first, fallback v2
87161 payload = {"body" : comment }
88- resp = requests .post (api_url , json = payload , headers = headers , auth = auth , timeout = 15 )
89- if resp .status_code == 404 :
90- logger .warning (f"Cannot add comment: issue { task_id } not found or no permission (404). Skipping." )
162+ for ver in ("3" , "2" ):
163+ api_url = f"{ jira_url } /rest/api/{ ver } /issue/{ task_id } /comment"
164+ resp = requests .post (api_url , json = payload , headers = headers , auth = auth , timeout = 20 )
165+ if resp .status_code == 404 :
166+ logger .warning (f"[Jira] 404 on comment POST v{ ver } (issue not visible)." )
167+ continue
168+ if resp .status_code == 403 :
169+ logger .warning (f"[Jira] 403 on comment POST v{ ver } (no Add Comments permission)." )
170+ continue
171+ if resp .status_code not in (201 , 200 ):
172+ logger .error (f"[Jira] comment POST v{ ver } status={ resp .status_code } body={ resp .text [:160 ]} " )
173+ continue
174+ logger .info ("✅ Comment added (replaced previous)." )
91175 return
92- resp .raise_for_status ()
93- logger .info ("✅ Successfully added comment to Jira." )
176+ logger .warning ("Failed to add comment after trying v3 and v2." )
94177 except Exception as e :
95178 logger .error (f"Failed to add comment to Jira task { task_id } . Error: { e } " )
0 commit comments