/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
- Create a merge request with approvals required
- Start a discussion on the merge request (or navigate to an existing discussion)
- Reply to the discussion using combined quick actions:
/approve /merge - 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
/approvecommand executes successfully - The
/mergecommand fails with: "The/mergequick 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.noteableobject 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:
- The form is submitted with an empty
merge_request_diff_head_sha - Quick actions are parsed and executed one by one
- Commands that don't require the SHA (like
/approve) succeed - The
/mergecommand 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