/merge quick action fails when use with /approve

Summary

The /merge quick action fails when combined with other quick actions (like /approve) in merge request discussion replies. The error "The /merge quick action requires the SHA of the head of the branch" is shown even though the user is interacting with a valid merge request.

Steps to reproduce

  1. Create a merge request with approvals required
  2. Start a discussion on the merge request (or navigate to an existing discussion)
  3. Reply to the discussion using combined quick actions: /approve /merge
  4. Submit the reply

Expected behavior

Both quick actions should execute successfully:

  • The merge request should be approved
  • The merge request should be set to auto-merge (or merge immediately if conditions are met)

Actual behavior

  • The /approve command executes successfully
  • The /merge command fails with: "The /merge quick action requires the SHA of the head of the branch"

Root Cause (⚠️ generated by duo/opencode, please verify)

The issue is in app/views/shared/notes/_form.html.haml at line 11:

= hidden_field_tag :merge_request_diff_head_sha, @note.noteable.try(:diff_head_sha)

This hidden field is rendered with an empty value when:

  • The noteable is not a MergeRequest (Issues, Commits, etc.)
  • The @note.noteable object is not properly loaded

The backend validation in lib/gitlab/quick_actions/merge_request_actions.rb:36 checks for this parameter:

if params[:merge_request_diff_head_sha].blank?
  _("The `/merge` quick action requires the SHA of the head of the branch.")

Why the main comment form works

The main comment form uses a Vue.js component (app/assets/javascripts/notes/components/comment_form.vue) which correctly passes the SHA from Vue state at line 261:

merge_request_diff_head_sha: this.getNoteableData.diff_head_sha,

Why combined commands are affected

When multiple quick actions are executed in sequence:

  1. The form is submitted with an empty merge_request_diff_head_sha
  2. Quick actions are parsed and executed one by one
  3. Commands that don't require the SHA (like /approve) succeed
  4. The /merge command fails due to the missing SHA parameter

This creates a confusing user experience where some commands work and others don't.

Proposed Solution

Update app/views/shared/notes/_form.html.haml to conditionally render the hidden field:

= hidden_field_tag :view, diff_view
= hidden_field_tag :line_type
- if @note.for_merge_request?
  = hidden_field_tag :merge_request_diff_head_sha, @note.noteable.diff_head_sha
= hidden_field_tag :in_reply_to_discussion_id
= hidden_field_tag :note_project_id

Benefits:

  • Only renders the field when needed (for merge requests)
  • Ensures the field always has a valid value when present
  • Eliminates the possibility of sending an empty SHA parameter
  • Aligns with the pattern used in other templates (e.g., app/views/shared/form_elements/_description.html.haml:14)

Additional Context

This issue is particularly relevant for the feature request in #210538 (closed) which proposes adding /create_pipeline /merge quick action combination. Users attempting similar workflows with existing commands (like /approve /merge) encounter this bug.

Related Code References

  • Backend validation: lib/gitlab/quick_actions/merge_request_actions.rb:36-56
  • Controller: app/controllers/concerns/notes_actions.rb:236
  • Service layer: app/services/notes/create_service.rb:152-156
  • Quick actions service: app/services/notes/quick_actions_service.rb:34-46
  • Working Vue component: app/assets/javascripts/notes/components/comment_form.vue:261

Labels

Related Issues

#210538 (comment 3029920370)

Assignee Loading
Time tracking Loading