diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index 045174de25be4120b35d91dc32aeede400554442..dccb89eec79e54fca215b9c4a8eef3e4968bd0b7 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -385,6 +385,14 @@ def assignee_sidebar_data(assignee, merge_request: nil) end end + def issuable_squash_option?(issuable, project) + if issuable.persisted? + issuable.squash + else + project.squash_enabled_by_default? + end + end + private def sidebar_gutter_collapsed? diff --git a/app/views/projects/_merge_request_settings.html.haml b/app/views/projects/_merge_request_settings.html.haml index dc3a3fcc6473cc0c3f6aaf397eb2fe1834ed90de..5ffdeef355855894b5871fb4efc42a761b11c4e7 100644 --- a/app/views/projects/_merge_request_settings.html.haml +++ b/app/views/projects/_merge_request_settings.html.haml @@ -4,6 +4,9 @@ = render 'projects/merge_request_merge_options_settings', project: @project, form: form +- if Feature.enabled?(:squash_options, @project) + = render 'projects/merge_request_squash_options_settings', form: form + = render 'projects/merge_request_merge_checks_settings', project: @project, form: form = render 'projects/merge_request_merge_suggestions_settings', project: @project, form: form diff --git a/app/views/projects/_merge_request_squash_options_settings.html.haml b/app/views/projects/_merge_request_squash_options_settings.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..a5dbfeb16d829d341dfdb04b34c4cbb6e4f6503a --- /dev/null +++ b/app/views/projects/_merge_request_squash_options_settings.html.haml @@ -0,0 +1,42 @@ +- form = local_assigns.fetch(:form) + += form.fields_for :project_setting do |settings| + .form-group + %b= s_('ProjectSettings|Squash commits when merging') + %p.text-secondary + = s_('ProjectSettings|Set the default behavior and availability of this option in merge requests. Changes made are also applied to existing merge requests.') + = link_to "What is squashing?", + help_page_path('user/project/merge_requests/squash_and_merge.md'), + target: '_blank' + + .form-check.gl-mb-2 + = settings.radio_button :squash_option, :never, class: "form-check-input" + = label_tag :project_project_setting_attributes_squash_option_never, class: 'form-check-label' do + .gl-font-weight-bold + = s_('ProjectSettings|Do not allow') + .text-secondary + = s_('ProjectSettings|Squashing is never performed and the checkbox is hidden.') + + .form-check.gl-mb-2 + = settings.radio_button :squash_option, :default_off, class: "form-check-input" + = label_tag :project_project_setting_attributes_squash_option_default_off, class: 'form-check-label' do + .gl-font-weight-bold + = s_('ProjectSettings|Allow') + .text-secondary + = s_('ProjectSettings|Checkbox is visible and unselected by default.') + + .form-check.gl-mb-2 + = settings.radio_button :squash_option, :default_on, class: "form-check-input" + = label_tag :project_project_setting_attributes_squash_option_default_on, class: 'form-check-label' do + .gl-font-weight-bold + = s_('ProjectSettings|Encourage') + .text-secondary + = s_('ProjectSettings|Checkbox is visible and selected by default.') + + .form-check.gl-mb-2 + = settings.radio_button :squash_option, :always, class: "form-check-input" + = label_tag :project_project_setting_attributes_squash_option_always, class: 'form-check-label' do + .gl-font-weight-bold + = s_('ProjectSettings|Require') + .text-secondary + = s_('ProjectSettings|Squashing is always performed. Checkbox is visible and selected, and users cannot change it.') diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml index 1b3ad484bccce9c381a0f1c6fca623814494f563..cc5bd4d67c9ec441aee28b5364a578a56c6e41b1 100644 --- a/app/views/shared/issuable/_form.html.haml +++ b/app/views/shared/issuable/_form.html.haml @@ -35,7 +35,7 @@ = render_if_exists 'shared/issuable/approvals', issuable: issuable, presenter: presenter, form: form -= render 'shared/issuable/form/merge_params', issuable: issuable += render 'shared/issuable/form/merge_params', issuable: issuable, project: project = render 'shared/issuable/form/contribution', issuable: issuable, form: form diff --git a/app/views/shared/issuable/form/_merge_params.html.haml b/app/views/shared/issuable/form/_merge_params.html.haml index 2cd4e0ba761edc01863f7815183d994774598f68..6523e733e44685c8a570b6a0491618a814169762 100644 --- a/app/views/shared/issuable/form/_merge_params.html.haml +++ b/app/views/shared/issuable/form/_merge_params.html.haml @@ -1,4 +1,5 @@ - issuable = local_assigns.fetch(:issuable) +- project = local_assigns.fetch(:project) - return unless issuable.is_a?(MergeRequest) - return if issuable.closed_without_fork? @@ -14,9 +15,14 @@ = check_box_tag 'merge_request[force_remove_source_branch]', '1', issuable.force_remove_source_branch?, class: 'form-check-input' = label_tag 'merge_request[force_remove_source_branch]', class: 'form-check-label' do Delete source branch when merge request is accepted. - .form-check - = hidden_field_tag 'merge_request[squash]', '0', id: nil - = check_box_tag 'merge_request[squash]', '1', issuable.squash, class: 'form-check-input' - = label_tag 'merge_request[squash]', class: 'form-check-label' do - Squash commits when merge request is accepted. - = link_to icon('question-circle'), help_page_path('user/project/merge_requests/squash_and_merge'), target: '_blank' + - if !project.squash_never? + .form-check + - if project.squash_always? + = hidden_field_tag 'merge_request[squash]', '1', id: nil + = check_box_tag 'merge_request[squash]', '1', project.squash_enabled_by_default?, class: 'form-check-input', disabled: 'true' + - else + = hidden_field_tag 'merge_request[squash]', '0', id: nil + = check_box_tag 'merge_request[squash]', '1', issuable_squash_option?(issuable, project), class: 'form-check-input' + = label_tag 'merge_request[squash]', class: 'form-check-label' do + Squash commits when merge request is accepted. + = link_to icon('question-circle'), help_page_path('user/project/merge_requests/squash_and_merge'), target: '_blank' diff --git a/ee/app/views/projects/_merge_request_settings.html.haml b/ee/app/views/projects/_merge_request_settings.html.haml index 5b802533cdf9fd4b96f6dd7f08f5c82b2e62c8ba..6f50b3eda5e118a21d3d356860b71a37a0bdeab3 100644 --- a/ee/app/views/projects/_merge_request_settings.html.haml +++ b/ee/app/views/projects/_merge_request_settings.html.haml @@ -4,6 +4,9 @@ = render_ce 'projects/merge_request_merge_options_settings', project: @project, form: form +- if Feature.enabled?(:squash_options, @project) + = render_ce 'projects/merge_request_squash_options_settings', form: form + = render_ce 'projects/merge_request_merge_checks_settings', project: @project, form: form = render 'projects/merge_request_merge_suggestions_settings', project: @project, form: form diff --git a/locale/gitlab.pot b/locale/gitlab.pot index e20caddaf826ea18cd123eb5b056f1c4c367962a..f3db09e5e6e02fdc45f874b6e975b2f2d605bfbe 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -17748,6 +17748,9 @@ msgstr "" msgid "ProjectSettings|All discussions must be resolved" msgstr "" +msgid "ProjectSettings|Allow" +msgstr "" + msgid "ProjectSettings|Allow users to make copies of your repository to a new project" msgstr "" @@ -17763,6 +17766,12 @@ msgstr "" msgid "ProjectSettings|Build, test, and deploy your changes" msgstr "" +msgid "ProjectSettings|Checkbox is visible and selected by default." +msgstr "" + +msgid "ProjectSettings|Checkbox is visible and unselected by default." +msgstr "" + msgid "ProjectSettings|Choose your merge method, merge options, merge checks, and merge suggestions." msgstr "" @@ -17781,12 +17790,18 @@ msgstr "" msgid "ProjectSettings|Disable email notifications" msgstr "" +msgid "ProjectSettings|Do not allow" +msgstr "" + msgid "ProjectSettings|Enable 'Delete source branch' option by default" msgstr "" msgid "ProjectSettings|Enable merge trains and pipelines for merged results" msgstr "" +msgid "ProjectSettings|Encourage" +msgstr "" + msgid "ProjectSettings|Every merge creates a merge commit" msgstr "" @@ -17901,6 +17916,12 @@ msgstr "" msgid "ProjectSettings|Repository" msgstr "" +msgid "ProjectSettings|Require" +msgstr "" + +msgid "ProjectSettings|Set the default behavior and availability of this option in merge requests. Changes made are also applied to existing merge requests." +msgstr "" + msgid "ProjectSettings|Share code pastes with others out of Git repository" msgstr "" @@ -17916,6 +17937,15 @@ msgstr "" msgid "ProjectSettings|Snippets" msgstr "" +msgid "ProjectSettings|Squash commits when merging" +msgstr "" + +msgid "ProjectSettings|Squashing is always performed. Checkbox is visible and selected, and users cannot change it." +msgstr "" + +msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden." +msgstr "" + msgid "ProjectSettings|Submit changes to be merged upstream" msgstr "" diff --git a/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb b/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb index 3fc1f47d98ab8e8e0068ed644c62dd7bb1992fe7..e97e4a2030a5098cb212bd9a3289951f997367a5 100644 --- a/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb +++ b/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb @@ -28,6 +28,22 @@ end end + it 'shows Squash commit options', :aggregate_failures do + page.within '#js-merge-request-settings' do + expect(page).to have_content 'Do not allow' + expect(page).to have_content 'Squashing is never performed and the checkbox is hidden.' + + expect(page).to have_content 'Allow' + expect(page).to have_content 'Checkbox is visible and unselected by default.' + + expect(page).to have_content 'Encourage' + expect(page).to have_content 'Checkbox is visible and selected by default.' + + expect(page).to have_content 'Require' + expect(page).to have_content 'Squashing is always performed. Checkbox is visible and selected, and users cannot change it.' + end + end + context 'when Merge Request and Pipelines are initially enabled', :js do context 'when Pipelines are initially enabled' do it 'shows the Merge Requests settings' do @@ -130,4 +146,56 @@ expect(project.remove_source_branch_after_merge).to be(false) end end + + describe 'Squash commits when merging', :js do + it 'initially has :squash_option set to :default_off' do + radio = find_field('project_project_setting_attributes_squash_option_default_off') + expect(radio).to be_checked + end + + it 'allows :squash_option to be set to :default_on' do + choose('project_project_setting_attributes_squash_option_default_on') + + within('.merge-request-settings-form') do + find('.qa-save-merge-request-changes') + click_on('Save changes') + end + + find('.flash-notice') + radio = find_field('project_project_setting_attributes_squash_option_default_on') + + expect(radio).to be_checked + expect(project.reload.project_setting.squash_option).to eq('default_on') + end + + it 'allows :squash_option to be set to :always' do + choose('project_project_setting_attributes_squash_option_always') + + within('.merge-request-settings-form') do + find('.qa-save-merge-request-changes') + click_on('Save changes') + end + + find('.flash-notice') + radio = find_field('project_project_setting_attributes_squash_option_always') + + expect(radio).to be_checked + expect(project.reload.project_setting.squash_option).to eq('always') + end + + it 'allows :squash_option to be set to :never' do + choose('project_project_setting_attributes_squash_option_never') + + within('.merge-request-settings-form') do + find('.qa-save-merge-request-changes') + click_on('Save changes') + end + + find('.flash-notice') + radio = find_field('project_project_setting_attributes_squash_option_never') + + expect(radio).to be_checked + expect(project.reload.project_setting.squash_option).to eq('never') + end + end end diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb index 5a88fc1cbf1359109a7362e67897ee0c0f3a7523..4c93a8387a9ee6a52236d994daea4748837874a0 100644 --- a/spec/helpers/issuables_helper_spec.rb +++ b/spec/helpers/issuables_helper_spec.rb @@ -303,4 +303,28 @@ end end end + + describe '#issuable_squash_option?' do + using RSpec::Parameterized::TableSyntax + + where(:issuable_persisted, :squash, :squash_enabled_by_default, :expectation) do + true | true | true | true + true | false | true | false + false | false | false | false + false | false | true | true + false | true | false | false + false | true | true | true + end + + with_them do + it 'returns the correct value' do + project = double( + squash_enabled_by_default?: squash_enabled_by_default + ) + issuable = double(persisted?: issuable_persisted, squash: squash) + + expect(helper.issuable_squash_option?(issuable, project)).to eq(expectation) + end + end + end end