Validate branch existence on merge request creation

Summary

Adds an on: :create model validation to MergeRequest that checks source and target branches actually exist in the repository.

Previously, only the UI enforced this via BuildService, while the API allowed creating MRs with non-existent branches, resulting in broken MRs with null diff_refs and misleading has_conflicts: true states.

Closes #591660

What does this MR do?

  • Adds validate :validate_branch_existence, on: :create to the MergeRequest model
  • The validation checks source_branch_exists? and target_branch_exists? using existing model methods
  • Adds skip_branch_existence_check attr_accessor to bypass validation in test factories (similar pattern to existing allow_broken)
  • Skipped when allow_broken, importing_or_transitioning?, or closed_or_merged_without_fork? (matching existing validation guards)
  • Gated behind the validate_merge_request_branch_existence feature flag (gitlab_com_derisk, disabled by default) for safe incremental rollout
  • Adds model-level and API integration specs with feature flag enabled/disabled contexts

Feature flag

This MR is gated behind the validate_merge_request_branch_existence feature flag:

  • Type: gitlab_com_derisk
  • Default: disabled
  • Actor: source_project
  • Rollout issue: #594430

Why model-level?

The validation belongs on the model to protect all creation paths (API, services, console, etc.), not just specific endpoints. A skip_branch_existence_check flag (set true in the factory) prevents breaking existing tests that create MRs with non-existent branch names.

Note on Danger bot warning

The Danger bot warns about new validations breaking existing records. This validation is on: :create only — it will not affect any existing merge requests, only new ones being created.

MR acceptance checklist

  • Tests added for model validation with feature flag on/off
  • Tests added for API endpoint with feature flag on/off
  • Tests added for CreateService with feature flag on/off
  • Follows existing validation patterns (unless: [:allow_broken, ...])
  • Uses _() for i18n on error messages
  • Feature flag YAML definition created
  • Rollout issue created
Edited by Marc Shaw

Merge request reports

Loading