@@ -342,41 +342,100 @@ async def create_merge_request(
342
342
title : str ,
343
343
** kwargs ,
344
344
) -> MergeRequestResource :
345
- """Create a new GitLab merge request."""
345
+ """Create a new GitLab merge request with cross-project support ."""
346
346
if not self .client :
347
347
await self .authenticate ()
348
348
349
349
try :
350
- project = self .client .projects .get (project_id )
350
+ # Parse branch references to handle cross-project scenarios
351
+ source_ref = self .parse_branch_reference (source_branch )
352
+ target_ref = self .parse_branch_reference (target_branch )
351
353
352
- # Verify branches exist before creating merge request
353
- try :
354
- # Check if source branch exists
355
- source_branches = project .branches .list (search = source_branch )
356
- if not any (b .name == source_branch for b in source_branches ):
357
- raise PlatformError (
358
- f"Source branch '{ source_branch } ' not found in project { project_id } . "
359
- f"Make sure the branch is pushed to the remote repository." ,
360
- self .platform_name ,
354
+ # Determine source and target projects
355
+ source_project_id = project_id
356
+ target_project_id = kwargs .get ("target_project_id" )
357
+
358
+ # Handle cross-project merge request setup
359
+ if target_project_id :
360
+ # Cross-project MR: source project creates MR to target project
361
+ print (
362
+ f"Debug: GitLab - Creating cross-project MR from project { source_project_id } to { target_project_id } "
363
+ )
364
+ source_project = self .client .projects .get (source_project_id )
365
+ target_project = self .client .projects .get (target_project_id )
366
+
367
+ # Verify source branch exists in source project
368
+ try :
369
+ source_branches = source_project .branches .list (
370
+ search = source_ref ["branch" ]
371
+ )
372
+ if not any (b .name == source_ref ["branch" ] for b in source_branches ):
373
+ raise PlatformError (
374
+ f"Source branch '{ source_ref ['branch' ]} ' not found in project { source_project_id } . "
375
+ f"Make sure the branch is pushed to the remote repository." ,
376
+ self .platform_name ,
377
+ )
378
+ except GitlabError as branch_error :
379
+ print (
380
+ f"Warning: Could not verify source branch existence: { branch_error } "
361
381
)
362
382
363
- # Check if target branch exists
364
- target_branches = project .branches .list (search = target_branch )
365
- if not any (b .name == target_branch for b in target_branches ):
366
- raise PlatformError (
367
- f"Target branch '{ target_branch } ' not found in project { project_id } " ,
368
- self .platform_name ,
383
+ # Verify target branch exists in target project
384
+ try :
385
+ target_branches = target_project .branches .list (
386
+ search = target_ref ["branch" ]
369
387
)
370
- except GitlabError as branch_error :
371
- print (f"Warning: Could not verify branch existence: { branch_error } " )
372
- # Continue with merge request creation even if branch check fails
388
+ if not any (b .name == target_ref ["branch" ] for b in target_branches ):
389
+ raise PlatformError (
390
+ f"Target branch '{ target_ref ['branch' ]} ' not found in project { target_project_id } " ,
391
+ self .platform_name ,
392
+ )
393
+ except GitlabError as branch_error :
394
+ print (
395
+ f"Warning: Could not verify target branch existence: { branch_error } "
396
+ )
397
+
398
+ # Use source project to create the MR
399
+ project = source_project
400
+ else :
401
+ # Same-project MR (existing behavior)
402
+ print (
403
+ f"Debug: GitLab - Creating same-project MR in project { source_project_id } "
404
+ )
405
+ project = self .client .projects .get (source_project_id )
406
+
407
+ # Verify branches exist in same project
408
+ try :
409
+ # Check if source branch exists
410
+ source_branches = project .branches .list (search = source_ref ["branch" ])
411
+ if not any (b .name == source_ref ["branch" ] for b in source_branches ):
412
+ raise PlatformError (
413
+ f"Source branch '{ source_ref ['branch' ]} ' not found in project { source_project_id } . "
414
+ f"Make sure the branch is pushed to the remote repository." ,
415
+ self .platform_name ,
416
+ )
417
+
418
+ # Check if target branch exists
419
+ target_branches = project .branches .list (search = target_ref ["branch" ])
420
+ if not any (b .name == target_ref ["branch" ] for b in target_branches ):
421
+ raise PlatformError (
422
+ f"Target branch '{ target_ref ['branch' ]} ' not found in project { source_project_id } " ,
423
+ self .platform_name ,
424
+ )
425
+ except GitlabError as branch_error :
426
+ print (f"Warning: Could not verify branch existence: { branch_error } " )
427
+ # Continue with merge request creation even if branch check fails
373
428
374
429
mr_data = {
375
- "source_branch" : source_branch ,
376
- "target_branch" : target_branch ,
430
+ "source_branch" : source_ref [ "branch" ] ,
431
+ "target_branch" : target_ref [ "branch" ] ,
377
432
"title" : title ,
378
433
}
379
434
435
+ # Add target_project_id for cross-project MR
436
+ if target_project_id :
437
+ mr_data ["target_project_id" ] = int (target_project_id )
438
+
380
439
# Handle assignee parameter conversion
381
440
if "assignee_username" in kwargs :
382
441
assignee_username = kwargs .pop ("assignee_username" )
@@ -573,28 +632,28 @@ def parse_branch_reference(self, branch_ref: str) -> Dict[str, Any]:
573
632
"""Parse GitLab branch reference into components.
574
633
575
634
Args:
576
- branch_ref: Branch reference in format 'branch' or 'owner :branch'
635
+ branch_ref: Branch reference in format 'branch' or 'project :branch'
577
636
578
637
Returns:
579
- Dict with keys: 'owner ' (optional), 'branch', 'is_cross_repo '
638
+ Dict with keys: 'project ' (optional), 'branch', 'is_cross_project '
580
639
"""
581
640
if ":" in branch_ref :
582
- # Cross-repository reference: 'owner :branch'
641
+ # Cross-project reference: 'project :branch'
583
642
parts = branch_ref .split (":" , 1 )
584
643
if len (parts ) != 2 :
585
644
raise ValueError (f"Invalid branch reference format: { branch_ref } " )
586
645
587
- owner , branch = parts
588
- if not owner or not branch :
646
+ project , branch = parts
647
+ if not project or not branch :
589
648
raise ValueError (f"Invalid branch reference format: { branch_ref } " )
590
649
591
- return {"owner " : owner , "branch" : branch , "is_cross_repo " : True } # type: ignore[dict-item]
650
+ return {"project " : project , "branch" : branch , "is_cross_project " : True } # type: ignore[dict-item]
592
651
else :
593
- # Same-repository reference: 'branch'
652
+ # Same-project reference: 'branch'
594
653
if not branch_ref :
595
654
raise ValueError ("Branch reference cannot be empty" )
596
655
597
- return {"branch" : branch_ref , "is_cross_repo " : False } # type: ignore[dict-item]
656
+ return {"branch" : branch_ref , "is_cross_project " : False } # type: ignore[dict-item]
598
657
599
658
# Helper methods
600
659
def _convert_to_project_resource (self , project ) -> ProjectResource :
0 commit comments