4646# This is used to ensure legacy comments are not touched
4747UPDATE_DATE = datetime (2019 , 7 , 9 , 18 , 18 , 36 , 480291 , tzinfo = timezone .utc )
4848
49+ # Jira REST API rejects comment bodies longer than this (characters).
50+ JIRA_COMMENT_BODY_MAX_CHARS = 32767
51+
4952log = logging .getLogger ("sync2jira" )
5053logging .getLogger ("snowflake.connector" ).setLevel (logging .WARNING )
5154
@@ -250,6 +253,52 @@ def _comment_format(comment):
250253 )
251254
252255
256+ def _truncate_jira_comment_body (
257+ body : str , upstream_issue_url : Optional [str ] = None
258+ ) -> str :
259+ """
260+ Ensure ``body`` fits Jira's comment size limit.
261+
262+ If truncated, prepend a notice (and optional link to the upstream GitHub issue)
263+ and append a marker so readers know where to find the full thread.
264+ """
265+ if len (body ) <= JIRA_COMMENT_BODY_MAX_CHARS :
266+ return body
267+
268+ log .info (
269+ "Truncating Jira comment body from %d to max %d characters" ,
270+ len (body ),
271+ JIRA_COMMENT_BODY_MAX_CHARS ,
272+ )
273+
274+ link_block = ""
275+ if upstream_issue_url :
276+ link_block = f"[View upstream issue on GitHub|{ upstream_issue_url } ]\n \n "
277+
278+ head = (
279+ "{warning}*(This comment was truncated to fit Jira's "
280+ f"{ JIRA_COMMENT_BODY_MAX_CHARS } -character limit.)*{{warning}}\n \n " + link_block
281+ )
282+ tail = (
283+ "\n \n {warning}*(Comment truncated"
284+ + (
285+ " — see GitHub link above for the full thread.)*"
286+ if upstream_issue_url
287+ else " — full thread not linked.)*"
288+ )
289+ + "{warning}"
290+ )
291+
292+ budget = JIRA_COMMENT_BODY_MAX_CHARS - len (head ) - len (tail )
293+ if budget < 1 :
294+ head = "{warning}*(Truncated.)*{warning}\n "
295+ tail = "\n {warning}*(…)*{warning}"
296+ budget = JIRA_COMMENT_BODY_MAX_CHARS - len (head ) - len (tail )
297+
298+ truncated_core = body [: max (budget , 0 )]
299+ return head + truncated_core + tail
300+
301+
253302def _comment_format_legacy (comment ):
254303 """
255304 Legacy function to format JIRA comments.
@@ -472,12 +521,15 @@ def check_comments_for_duplicate(client, result, username):
472521 return None
473522
474523
475- def _find_comment_in_jira (comment , j_comments ):
524+ def _find_comment_in_jira (
525+ comment , j_comments , upstream_issue_url : Optional [str ] = None
526+ ):
476527 """
477528 Helper function to filter out comments that are matching.
478529
479530 :param Dict comment: Individual comment from upstream
480531 :param List j_comments: Comments from JIRA downstream
532+ :param Optional[str] upstream_issue_url: Upstream issue URL for truncation notices
481533 :returns: Item/None
482534 :rtype: jira.resource.Comment/None
483535 """
@@ -486,7 +538,9 @@ def _find_comment_in_jira(comment, j_comments):
486538 # touch the comment; return the item as is.
487539 return comment
488540
489- formatted_comment = _comment_format (comment )
541+ formatted_comment = _truncate_jira_comment_body (
542+ _comment_format (comment ), upstream_issue_url
543+ )
490544 legacy_formatted_comment = _comment_format_legacy (comment )
491545 for item in j_comments :
492546 if item .raw ["body" ] == legacy_formatted_comment :
@@ -505,18 +559,19 @@ def _find_comment_in_jira(comment, j_comments):
505559 return None
506560
507561
508- def _comment_matching (g_comments , j_comments ):
562+ def _comment_matching (g_comments , j_comments , upstream_issue_url : Optional [ str ] = None ):
509563 """
510564 Function to filter out comments that are matching.
511565
512566 :param List g_comments: Comments from Issue object
513567 :param List j_comments: Comments from JIRA downstream
568+ :param Optional[str] upstream_issue_url: Upstream issue URL (for Jira truncation)
514569 :returns: Returns a list of comments that are not matching
515570 :rtype: List
516571 """
517572 return list (
518573 filter (
519- lambda x : _find_comment_in_jira (x , j_comments ) is None
574+ lambda x : _find_comment_in_jira (x , j_comments , upstream_issue_url ) is None
520575 or x ["changed" ] is not None ,
521576 g_comments ,
522577 )
@@ -1066,11 +1121,11 @@ def _update_comments(client, existing, issue):
10661121 # Get all existing comments
10671122 comments = client .comments (existing )
10681123 # Remove any comments that have already been added
1069- comments_d = _comment_matching (issue .comments , comments )
1124+ comments_d = _comment_matching (issue .comments , comments , issue . url )
10701125 # Loop through the comments that remain
10711126 for comment in comments_d :
10721127 # Format and add them
1073- comment_body = _comment_format (comment )
1128+ comment_body = _truncate_jira_comment_body ( _comment_format (comment ), issue . url )
10741129 client .add_comment (existing , comment_body )
10751130 if len (comments_d ) > 0 :
10761131 log .info ("Comments synchronization done on %i comments." , len (comments_d ))
0 commit comments