@@ -45,6 +45,35 @@ class Colors:
4545- MEDIUM: Code smells, potential bugs, missing error handling
4646- LOW: Minor improvements, suggestions, style inconsistencies"""
4747
48+ DOCUMENTATION_PROMPT = """Documentation review: you are a technical writer reviewing a git diff for documentation impact.
49+
50+ Output ONLY valid JSON - no markdown, no code blocks, no explanations.
51+
52+ Identify whether the diff changes user-facing behavior, setup steps, configuration,
53+ commands, flags, public APIs, or operational workflows that should be documented.
54+ Do not suggest documentation for purely internal refactors, test-only changes, or
55+ minor implementation details that users do not need to know.
56+
57+ Output format:
58+ {
59+ "needed": true,
60+ "summary": "one sentence describing why docs should change",
61+ "suggestions": [
62+ {
63+ "file": "README.md",
64+ "reason": "what changed in the diff",
65+ "suggestion": "specific documentation update to make"
66+ }
67+ ]
68+ }
69+
70+ If no documentation update is needed, return:
71+ {
72+ "needed": false,
73+ "summary": "No documentation updates needed.",
74+ "suggestions": []
75+ }"""
76+
4877def get_branch_diff ():
4978 """Get the diff of changed files in current branch vs main branch."""
5079 try :
@@ -130,6 +159,32 @@ def review_code(diff_content):
130159 print (f"{ Colors .CRITICAL } ✗ Error during AI review: { e } { Colors .RESET } " )
131160 return None
132161
162+ def suggest_documentation_updates (diff_content ):
163+ """Send code diff to OpenAI for documentation update suggestions."""
164+ openai = get_openai_client ()
165+ if not openai :
166+ return None
167+
168+ try :
169+ response = openai .chat .completions .create (
170+ model = "gpt-4o" ,
171+ messages = [
172+ {"role" : "system" , "content" : DOCUMENTATION_PROMPT },
173+ {"role" : "user" , "content" : f"Documentation review for this git diff:\n \n { diff_content } " }
174+ ],
175+ temperature = 0.2 ,
176+ response_format = {"type" : "json_object" }
177+ )
178+
179+ return json .loads (response .choices [0 ].message .content )
180+ except json .JSONDecodeError as e :
181+ print (f"{ Colors .CRITICAL } ✗ Failed to parse documentation response as JSON{ Colors .RESET } " )
182+ print (f"{ Colors .DIM } Error: { e } { Colors .RESET } " )
183+ return None
184+ except Exception as e :
185+ print (f"{ Colors .CRITICAL } ✗ Error during documentation review: { e } { Colors .RESET } " )
186+ return None
187+
133188def print_issues (issues , severity , color , icon ):
134189 """Print issues with consistent formatting."""
135190 if not issues :
@@ -213,6 +268,41 @@ def format_issues(issues, severity, emoji):
213268
214269 return comment
215270
271+ def format_documentation_comment (results ):
272+ """Format documentation suggestions as a GitLab markdown comment."""
273+ if not results or not results .get ('needed' ):
274+ return None
275+
276+ comment = "## Documentation Suggestions\n \n "
277+
278+ summary = results .get ('summary' , '' )
279+ if summary :
280+ comment += f"{ summary } \n \n "
281+
282+ suggestions = results .get ('suggestions' , [])
283+ if not suggestions :
284+ comment += "- **`Documentation`**: Review the diff and update documentation as needed.\n "
285+ return comment
286+
287+ for suggestion in suggestions :
288+ file_path = suggestion .get ('file' , 'Documentation' )
289+ reason = suggestion .get ('reason' , 'Documentation may need an update.' )
290+ update = suggestion .get ('suggestion' , 'Review the diff and update documentation as needed.' )
291+ comment += f"- **`{ file_path } `**: { update } \n "
292+ comment += f" - Reason: { reason } \n "
293+
294+ return comment
295+
296+ def display_documentation_results (results ):
297+ """Display documentation suggestions in the terminal."""
298+ comment = format_documentation_comment (results )
299+ if not comment :
300+ print (f"{ Colors .INFO } ℹ No documentation updates suggested{ Colors .RESET } " )
301+ return
302+
303+ print (f"\n { Colors .BOLD } DOCUMENTATION SUGGESTIONS{ Colors .RESET } " )
304+ print (comment )
305+
216306def get_merge_request_changes (project_id , mr_id , gitlab_token , api_url ):
217307 """Get the changes (diffs) from the merge request to find commit SHAs."""
218308 import requests
@@ -340,6 +430,11 @@ def run_review():
340430 sys .exit (0 )
341431 display_review_results (results )
342432
433+ print (f"{ Colors .INFO } 📝 Checking documentation impact...{ Colors .RESET } " )
434+ documentation_results = suggest_documentation_updates (diff_content )
435+ if documentation_results :
436+ display_documentation_results (documentation_results )
437+
343438def run_review_for_mr (project_id , mr_id , gitlab_token , api_url ):
344439 """Run AI code review and post inline comments to GitLab merge request."""
345440 print (f"{ Colors .INFO } 🤖 Running AI code review...{ Colors .RESET } " )
@@ -353,12 +448,17 @@ def run_review_for_mr(project_id, mr_id, gitlab_token, api_url):
353448 print (f"{ Colors .HIGH } ⚠ AI review skipped{ Colors .RESET } " )
354449 return
355450
451+ documentation_results = suggest_documentation_updates (diff_content )
452+ documentation_comment = format_documentation_comment (documentation_results )
453+
356454 # Get diff refs for inline comments
357455 diff_refs = get_diff_refs (project_id , mr_id , gitlab_token , api_url )
358456 if not diff_refs or not all (diff_refs .values ()):
359457 print (f"{ Colors .HIGH } ⚠ Could not get diff refs, posting summary only{ Colors .RESET } " )
360458 comment = format_gitlab_comment (results )
361459 post_to_merge_request (comment , project_id , mr_id , gitlab_token , api_url )
460+ if documentation_comment :
461+ post_to_merge_request (documentation_comment , project_id , mr_id , gitlab_token , api_url )
362462 return
363463
364464 # Post inline comments for each issue
@@ -386,5 +486,8 @@ def run_review_for_mr(project_id, mr_id, gitlab_token, api_url):
386486 else :
387487 print (f"{ Colors .INFO } ✓ All { total_posted } issues posted as inline comments{ Colors .RESET } " )
388488
489+ if documentation_comment :
490+ post_to_merge_request (documentation_comment , project_id , mr_id , gitlab_token , api_url )
491+
389492if __name__ == '__main__' :
390493 run_review ()
0 commit comments