@@ -430,19 +430,14 @@ def create_pull_request(task_id):
430430 # Apply the patch by creating/updating files
431431 logger .info (f"📦 Applying patch with { len (task .get ('changed_files' , []))} changed files..." )
432432
433- # For now, we'll use a simple approach to apply changes
434- # In a real implementation, you'd want a more sophisticated patch parser
433+ # Parse and apply the git patch to the repository
435434 patch_content = task ['git_patch' ]
436- files_updated = []
435+ files_updated = apply_patch_to_github_repo ( repo , pr_branch , patch_content , task )
437436
438- # Simple file update based on changed_files list
439- for file_path in task .get ('changed_files' , []):
440- try :
441- # This is a simplified approach - in reality you'd parse the patch properly
442- logger .info (f"📝 Updating file: { file_path } " )
443- files_updated .append (file_path )
444- except Exception as e :
445- logger .warning (f"Failed to update { file_path } : { e } " )
437+ if not files_updated :
438+ return jsonify ({'error' : 'Failed to apply patch - no file changes extracted' }), 500
439+
440+ logger .info (f"✅ Applied patch, updated { len (files_updated )} files" )
446441
447442 # Create pull request
448443 pr = repo .create_pull (
@@ -520,4 +515,146 @@ def migrate_legacy_tasks():
520515
521516 except Exception as e :
522517 logger .error (f"Error migrating legacy tasks: { str (e )} " )
523- return jsonify ({'error' : str (e )}), 500
518+ return jsonify ({'error' : str (e )}), 500
519+
520+
521+ def apply_patch_to_github_repo (repo , branch , patch_content , task ):
522+ """Apply a git patch to a GitHub repository using the GitHub API"""
523+ try :
524+ logger .info (f"🔧 Parsing patch content..." )
525+
526+ # Parse git patch format to extract file changes
527+ files_to_update = {}
528+ current_file = None
529+ new_content_lines = []
530+
531+ # This is a simplified patch parser - for production you might want a more robust one
532+ lines = patch_content .split ('\n ' )
533+ i = 0
534+
535+ while i < len (lines ):
536+ line = lines [i ]
537+
538+ # Look for file headers in patch format
539+ if line .startswith ('--- a/' ) or line .startswith ('--- /dev/null' ):
540+ # Next line should be +++ b/filename
541+ if i + 1 < len (lines ) and lines [i + 1 ].startswith ('+++ b/' ):
542+ current_file = lines [i + 1 ][6 :] # Remove '+++ b/'
543+ logger .info (f"📄 Found file change: { current_file } " )
544+
545+ # Get the original file content if it exists
546+ try :
547+ file_obj = repo .get_contents (current_file , ref = branch )
548+ original_content = file_obj .decoded_content .decode ('utf-8' )
549+ logger .info (f"📥 Got original content for { current_file } " )
550+ except :
551+ original_content = "" # New file
552+ logger .info (f"📝 New file: { current_file } " )
553+
554+ # For simplicity, we'll reconstruct the file from the diff
555+ # Skip to the actual diff content (after @@)
556+ j = i + 2
557+ while j < len (lines ) and not lines [j ].startswith ('@@' ):
558+ j += 1
559+
560+ if j < len (lines ):
561+ # Apply the diff changes
562+ new_content = apply_diff_to_content (original_content , lines [j :], current_file )
563+ if new_content is not None :
564+ files_to_update [current_file ] = new_content
565+ logger .info (f"✅ Prepared update for { current_file } " )
566+
567+ i = j
568+ i += 1
569+
570+ # Now update all the files via GitHub API
571+ updated_files = []
572+ commit_message = f"Claude Code: { task .get ('prompt' , 'Automated changes' )[:100 ]} "
573+
574+ # Get prompt from chat messages if available
575+ if task .get ('chat_messages' ):
576+ for msg in task ['chat_messages' ]:
577+ if msg .get ('role' ) == 'user' :
578+ commit_message = f"Claude Code: { msg .get ('content' , '' )[:100 ]} "
579+ break
580+
581+ for file_path , new_content in files_to_update .items ():
582+ try :
583+ # Check if file exists
584+ try :
585+ file_obj = repo .get_contents (file_path , ref = branch )
586+ # Update existing file
587+ repo .update_file (
588+ path = file_path ,
589+ message = commit_message ,
590+ content = new_content ,
591+ sha = file_obj .sha ,
592+ branch = branch
593+ )
594+ logger .info (f"📝 Updated existing file: { file_path } " )
595+ except :
596+ # Create new file
597+ repo .create_file (
598+ path = file_path ,
599+ message = commit_message ,
600+ content = new_content ,
601+ branch = branch
602+ )
603+ logger .info (f"🆕 Created new file: { file_path } " )
604+
605+ updated_files .append (file_path )
606+
607+ except Exception as file_error :
608+ logger .error (f"❌ Failed to update { file_path } : { file_error } " )
609+
610+ return updated_files
611+
612+ except Exception as e :
613+ logger .error (f"💥 Error applying patch: { str (e )} " )
614+ return []
615+
616+
617+ def apply_diff_to_content (original_content , diff_lines , filename ):
618+ """Apply diff changes to original content - simplified implementation"""
619+ try :
620+ # For now, let's use a simple approach: reconstruct from + lines
621+ # This is not a complete diff parser, but works for basic cases
622+
623+ result_lines = []
624+ original_lines = original_content .split ('\n ' ) if original_content else []
625+
626+ # Find the actual diff content starting from @@ line
627+ diff_start = 0
628+ for i , line in enumerate (diff_lines ):
629+ if line .startswith ('@@' ):
630+ diff_start = i + 1
631+ break
632+
633+ # Simple reconstruction: take context and + lines, skip - lines
634+ for line in diff_lines [diff_start :]:
635+ if line .startswith ('+++' ) or line .startswith ('---' ):
636+ continue
637+ elif line .startswith ('+' ) and not line .startswith ('+++' ):
638+ result_lines .append (line [1 :]) # Remove the +
639+ elif line .startswith (' ' ): # Context line
640+ result_lines .append (line [1 :]) # Remove the space
641+ elif line .startswith ('-' ):
642+ continue # Skip removed lines
643+ elif line .strip () == '' :
644+ continue # Skip empty lines in diff
645+ else :
646+ # Check if we've reached the next file
647+ if line .startswith ('diff --git' ) or line .startswith ('--- a/' ):
648+ break
649+
650+ # If we got content, return it, otherwise fall back to using the git diff directly
651+ if result_lines :
652+ return '\n ' .join (result_lines )
653+ else :
654+ # Fallback: return original content (no changes applied)
655+ logger .warning (f"⚠️ Could not parse diff for { filename } , keeping original" )
656+ return original_content
657+
658+ except Exception as e :
659+ logger .error (f"❌ Error applying diff to { filename } : { str (e )} " )
660+ return None
0 commit comments