From bd8cbf36ec2f3d863c34a3771298c15a5524de8a Mon Sep 17 00:00:00 2001 From: Igor Drozdov Date: Thu, 21 Jul 2022 11:53:06 +0200 Subject: [PATCH 1/2] Configure branch name for creating MR from an issue - Allow specifying a template in the Project Settings UI - When an MR is created from an issue, a branch name is generated according to the configured template Changelog: added --- app/controllers/projects_controller.rb | 1 + app/models/issue.rb | 22 +++++++++--- app/models/project.rb | 1 + app/models/project_setting.rb | 1 + app/views/projects/_issue_settings.html.haml | 14 ++++++++ app/views/projects/edit.html.haml | 19 ++++++++++ app/views/projects/settings/_issues.html.haml | 13 +++++++ ...sue_branch_template_to_project_settings.rb | 17 +++++++++ db/schema_migrations/20220721065723 | 1 + db/structure.sql | 2 ++ .../_default_issue_template.html.haml | 2 +- .../projects/settings/issues_settings_spec.rb | 2 ++ .../user_manages_issues_template_spec.rb | 2 +- lib/api/entities/project.rb | 1 + lib/api/helpers/projects_helpers.rb | 2 ++ locale/gitlab.pot | 9 +++++ .../projects/settings/issues_settings_spec.rb | 36 +++++++++++++++++++ .../import_export/safe_model_attributes.yml | 1 + spec/models/issue_spec.rb | 11 ++++-- spec/models/project_setting_spec.rb | 1 + spec/views/projects/edit.html.haml_spec.rb | 16 +++++++++ 21 files changed, 165 insertions(+), 9 deletions(-) create mode 100644 app/views/projects/_issue_settings.html.haml create mode 100644 app/views/projects/settings/_issues.html.haml create mode 100644 db/migrate/20220721065723_add_issue_branch_template_to_project_settings.rb create mode 100644 db/schema_migrations/20220721065723 create mode 100644 spec/features/projects/settings/issues_settings_spec.rb diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index bdd7806a08579f..ab666d50d18be5 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -496,6 +496,7 @@ def project_params_attributes :service_desk_enabled, :merge_commit_template_or_default, :squash_commit_template_or_default, + :issue_branch_template, project_setting_attributes: project_setting_attributes ] + [project_feature_attributes: project_feature_attributes] end diff --git a/app/models/issue.rb b/app/models/issue.rb index 61fc0264360468..df28c48c9397a9 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -39,6 +39,7 @@ class Issue < ApplicationRecord DueNextMonthAndPreviousTwoWeeks = DueDateStruct.new('Due Next Month And Previous Two Weeks', 'next_month_and_previous_two_weeks').freeze SORTING_PREFERENCE_FIELD = :issues_sort + MAX_BRANCH_TEMPLATE = 255 # Types of issues that should be displayed on issue lists across the app # for example, project issues list, group issues list, and issues dashboard. @@ -394,10 +395,21 @@ def self.column_order_id_asc ) end - def self.to_branch_name(*args) - branch_name = args.map(&:to_s).each_with_index.map do |arg, i| - arg.parameterize(preserve_case: i == 0).presence - end.compact.join('-') + def self.to_branch_name(id, title, project: nil) + params = { + 'id' => id.to_s.parameterize(preserve_case: true), + 'title' => title.to_s.parameterize + } + template = project&.issue_branch_template + + branch_name = + if template.present? + Gitlab::StringPlaceholderReplacer.replace_string_placeholders(template, /(#{params.keys.join('|')})/) do |arg| + params[arg] + end + else + params.values.select(&:present?).join('-') + end if branch_name.length > 100 truncated_string = branch_name[0, 100] @@ -475,7 +487,7 @@ def to_branch_name if self.confidential? "#{iid}-confidential-issue" else - self.class.to_branch_name(iid, title) + self.class.to_branch_name(iid, title, project: project) end end diff --git a/app/models/project.rb b/app/models/project.rb index db30a74112d24b..8ecfdeb98f57e2 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -491,6 +491,7 @@ def self.integration_association_name(name) to: :project_setting delegate :merge_commit_template, :merge_commit_template=, to: :project_setting, allow_nil: true delegate :squash_commit_template, :squash_commit_template=, to: :project_setting, allow_nil: true + delegate :issue_branch_template, :issue_branch_template=, to: :project_setting, allow_nil: true delegate :log_jira_dvcs_integration_usage, :jira_dvcs_server_last_sync_at, :jira_dvcs_cloud_last_sync_at, to: :feature_usage diff --git a/app/models/project_setting.rb b/app/models/project_setting.rb index 6d40544fad4ee9..4c3be49fddd568 100644 --- a/app/models/project_setting.rb +++ b/app/models/project_setting.rb @@ -20,6 +20,7 @@ class ProjectSetting < ApplicationRecord validates :merge_commit_template, length: { maximum: Project::MAX_COMMIT_TEMPLATE_LENGTH } validates :squash_commit_template, length: { maximum: Project::MAX_COMMIT_TEMPLATE_LENGTH } + validates :issue_branch_template, length: { maximum: Issue::MAX_BRANCH_TEMPLATE } validates :target_platforms, inclusion: { in: ALLOWED_TARGET_PLATFORMS } validates :suggested_reviewers_enabled, inclusion: { in: [true, false] } diff --git a/app/views/projects/_issue_settings.html.haml b/app/views/projects/_issue_settings.html.haml new file mode 100644 index 00000000000000..302733c39fd045 --- /dev/null +++ b/app/views/projects/_issue_settings.html.haml @@ -0,0 +1,14 @@ +- form = local_assigns.fetch(:form) + +.form-group + %b= s_('ProjectSettings|Branches name') + %p.text-secondary + = s_('ProjectSettings|Default branch name for branches created from merge request.') + .mb-2 + = form.text_field :issue_branch_template, class: 'form-control mb-2', placeholder: "%{id}-%{title}" + %p.form-text.text-muted + = s_('ProjectSettings|Leave empty to use default template.') + = sprintf(s_('ProjectSettings|Maximum %{maxLength} characters.'), { maxLength: Issue::MAX_BRANCH_TEMPLATE }) + - configure_the_issue_branch_name_help_link_help_link_url = help_page_path('user/project/repository/web_editor.md', anchor: 'create-a-new-branch-from-an-issue') + - configure_the_issue_branch_name_help_link_start = ''.html_safe % { url: configure_the_issue_branch_name_help_link_help_link_url } + = s_('ProjectSettings|%{link_start}What variables can I use?%{link_end}').html_safe % { link_start: configure_the_issue_branch_name_help_link_start, link_end: ''.html_safe } diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index f6e3c15c08bf87..c49bec831351f9 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -36,6 +36,23 @@ = c.body do = _('On the left sidebar, select %{merge_requests_link} to view them.').html_safe % { merge_requests_link: link_to('Settings > Merge requests', project_settings_merge_requests_path(@project)).html_safe } +%section.rspec-merge-request-settings.settings.merge-requests-feature.no-animate#js-merge-request-settings{ class: [('expanded' if expanded), ('hidden' if @project.project_feature.send(:merge_requests_access_level) == 0)], data: { qa_selector: 'merge_request_settings_content' } } + .settings-header + %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Merge requests') + = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do + = expanded ? _('Collapse') : _('Expand') + = render_if_exists 'projects/merge_request_settings_description_text' + + .settings-content + = render_if_exists 'shared/promotions/promote_mr_features' + + = gitlab_ui_form_for @project, html: { multipart: true, class: "merge-request-settings-form js-mr-settings-form" }, authenticity_token: true do |f| + %input{ name: 'update_section', type: 'hidden', value: 'js-merge-request-settings' } + = render 'projects/merge_request_settings', form: f + = f.submit _('Save changes'), class: "btn gl-button btn-confirm rspec-save-merge-request-changes", data: { qa_selector: 'save_merge_request_changes_button' } + += render_if_exists 'projects/merge_request_approvals_settings', expanded: expanded + %section.settings.no-animate{ class: ('expanded' if expanded), data: { qa_selector: 'badges_settings_content' } } .settings-header %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only @@ -50,6 +67,8 @@ = render_if_exists 'compliance_management/compliance_framework/project_settings', expanded: expanded += render 'projects/settings/issues', project: @project, expanded: expanded + = render_if_exists 'projects/settings/default_issue_template' = render 'projects/service_desk_settings' diff --git a/app/views/projects/settings/_issues.html.haml b/app/views/projects/settings/_issues.html.haml new file mode 100644 index 00000000000000..a63fc34f007260 --- /dev/null +++ b/app/views/projects/settings/_issues.html.haml @@ -0,0 +1,13 @@ +- if project.project_feature.issues_access_level > 0 + %section.rspec-issues-settings.settings.issues-feature.no-animate#js-issue-settings{ class: [('expanded' if expanded)], data: { qa_selector: 'issues_settings_content' } } + .settings-header + %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Issues') + = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do + = expanded ? _('Collapse') : _('Expand') + %p= _('Configure default branch name for branches created from issues.') + + .settings-content + = gitlab_ui_form_for @project, html: { multipart: true, class: "issue-settings-form js-issue-settings-form" }, authenticity_token: true do |f| + %input{ name: 'update_section', type: 'hidden', value: 'js-issue-settings' } + = render 'projects/issue_settings', form: f + = f.submit _('Save changes'), class: "btn gl-button btn-confirm rspec-save-issue-changes", data: { qa_selector: 'save_issue_changes_button' } diff --git a/db/migrate/20220721065723_add_issue_branch_template_to_project_settings.rb b/db/migrate/20220721065723_add_issue_branch_template_to_project_settings.rb new file mode 100644 index 00000000000000..d65bd2c21e712c --- /dev/null +++ b/db/migrate/20220721065723_add_issue_branch_template_to_project_settings.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddIssueBranchTemplateToProjectSettings < Gitlab::Database::Migration[2.0] + disable_ddl_transaction! + + def up + with_lock_retries do + add_column :project_settings, :issue_branch_template, :text, if_not_exists: true + end + + add_text_limit :project_settings, :issue_branch_template, 255 + end + + def down + remove_column :project_settings, :issue_branch_template, if_exists: true + end +end diff --git a/db/schema_migrations/20220721065723 b/db/schema_migrations/20220721065723 new file mode 100644 index 00000000000000..78b1fedaff1cd0 --- /dev/null +++ b/db/schema_migrations/20220721065723 @@ -0,0 +1 @@ +5e3fbb2c033f8512e5fd14b8ce8c6088866c596a2b769e115dcc1feb9ce9d041 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 7f9d177a3eaf55..8f8809afeac3ba 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -20172,12 +20172,14 @@ CREATE TABLE project_settings ( target_platforms character varying[] DEFAULT '{}'::character varying[] NOT NULL, enforce_auth_checks_on_uploads boolean DEFAULT true NOT NULL, selective_code_owner_removals boolean DEFAULT false NOT NULL, + issue_branch_template text, show_diff_preview_in_email boolean DEFAULT true NOT NULL, jitsu_key text, suggested_reviewers_enabled boolean DEFAULT false NOT NULL, only_allow_merge_if_all_status_checks_passed boolean DEFAULT false NOT NULL, CONSTRAINT check_2981f15877 CHECK ((char_length(jitsu_key) <= 100)), CONSTRAINT check_3a03e7557a CHECK ((char_length(previous_default_branch) <= 4096)), + CONSTRAINT check_3ca5cbffe6 CHECK ((char_length(issue_branch_template) <= 255)), CONSTRAINT check_b09644994b CHECK ((char_length(squash_commit_template) <= 500)), CONSTRAINT check_bde223416c CHECK ((show_default_award_emojis IS NOT NULL)), CONSTRAINT check_eaf7cfb6a7 CHECK ((char_length(merge_commit_template) <= 500)) diff --git a/ee/app/views/projects/settings/_default_issue_template.html.haml b/ee/app/views/projects/settings/_default_issue_template.html.haml index 28e6059ffef9d0..e40b79284738ec 100644 --- a/ee/app/views/projects/settings/_default_issue_template.html.haml +++ b/ee/app/views/projects/settings/_default_issue_template.html.haml @@ -1,6 +1,6 @@ - if @project.feature_available?(:issuable_default_templates) - expanded = expanded_by_default? - %section.settings.issues-feature.no-animate#js-issue-settings{ class: [('expanded' if expanded), ('hidden' if @project.project_feature.send(:issues_access_level) == 0)], data: { qa_selector: 'issue_template_settings_content' } } + %section.settings.rspec-default-issue-settings.issues-feature.no-animate#js-issue-settings{ class: [('expanded' if expanded), ('hidden' if @project.project_feature.send(:issues_access_level) == 0)], data: { qa_selector: 'issue_template_settings_content' } } .settings-header %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Default description template for issues') = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do diff --git a/ee/spec/features/projects/settings/issues_settings_spec.rb b/ee/spec/features/projects/settings/issues_settings_spec.rb index 7d006a4e58657e..1903c3b7a7b8e5 100644 --- a/ee/spec/features/projects/settings/issues_settings_spec.rb +++ b/ee/spec/features/projects/settings/issues_settings_spec.rb @@ -39,6 +39,7 @@ it 'does not show the Issues settings' do expect(page).not_to have_content('Set a default description template to be used for new issues.') + expect(page).not_to have_content('Configure default branch name for branches created from issues.') within('.sharing-permissions-form') do find('.project-feature-controls[data-for="project[project_feature_attributes][issues_access_level]"] .gl-toggle').click @@ -46,6 +47,7 @@ end expect(page).to have_content('Set a default description template to be used for new issues.') + expect(page).to have_content('Configure default branch name for branches created from issues.') end end diff --git a/ee/spec/features/projects/settings/user_manages_issues_template_spec.rb b/ee/spec/features/projects/settings/user_manages_issues_template_spec.rb index 78e46a67a8bf2a..61ebfc5d18a658 100644 --- a/ee/spec/features/projects/settings/user_manages_issues_template_spec.rb +++ b/ee/spec/features/projects/settings/user_manages_issues_template_spec.rb @@ -13,7 +13,7 @@ it 'saves issue template' do fill_in 'project_issues_template', with: "This issue should contain the following." - page.within '.issues-feature' do + page.within('section.rspec-default-issue-settings') do click_button 'Save changes' end diff --git a/lib/api/entities/project.rb b/lib/api/entities/project.rb index f158695f605c3b..9b0a472400decf 100644 --- a/lib/api/entities/project.rb +++ b/lib/api/entities/project.rb @@ -133,6 +133,7 @@ class Project < BasicProjectDetails expose :suggestion_commit_message expose :merge_commit_template expose :squash_commit_template + expose :issue_branch_template expose :statistics, using: 'API::Entities::ProjectStatistics', if: -> (project, options) { options[:statistics] && Ability.allowed?(options[:current_user], :read_statistics, project) } diff --git a/lib/api/helpers/projects_helpers.rb b/lib/api/helpers/projects_helpers.rb index 07b19742c2e510..c95bf0f0c218d4 100644 --- a/lib/api/helpers/projects_helpers.rb +++ b/lib/api/helpers/projects_helpers.rb @@ -65,6 +65,7 @@ module ProjectsHelpers optional :suggestion_commit_message, type: String, desc: 'The commit message used to apply merge request suggestions' optional :merge_commit_template, type: String, desc: 'Template used to create merge commit message' optional :squash_commit_template, type: String, desc: 'Template used to create squash commit message' + optional :issue_branch_template, type: String, desc: 'Template used to create a branch from an issue' optional :initialize_with_readme, type: Boolean, desc: "Initialize a project with a README.md" optional :ci_default_git_depth, type: Integer, desc: 'Default number of revisions for shallow cloning' optional :auto_devops_enabled, type: Boolean, desc: 'Flag indication if Auto DevOps is enabled' @@ -174,6 +175,7 @@ def self.update_params_at_least_one_of :suggestion_commit_message, :merge_commit_template, :squash_commit_template, + :issue_branch_template, :repository_storage, :packages_enabled, :service_desk_enabled, diff --git a/locale/gitlab.pot b/locale/gitlab.pot index a353ed4e5447b1..54e4b51c07e48f 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -10119,6 +10119,9 @@ msgstr "" msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings." msgstr "" +msgid "Configure default branch name for branches created from issues." +msgstr "" + msgid "Configure existing installation" msgstr "" @@ -31799,6 +31802,9 @@ msgstr "" msgid "ProjectSettings|Badges" msgstr "" +msgid "ProjectSettings|Branches name" +msgstr "" + msgid "ProjectSettings|Build, test, and deploy your changes." msgstr "" @@ -31832,6 +31838,9 @@ msgstr "" msgid "ProjectSettings|Customize this project's badges." msgstr "" +msgid "ProjectSettings|Default branch name for branches created from merge request." +msgstr "" + msgid "ProjectSettings|Determine what happens to the commit history when you merge a merge request." msgstr "" diff --git a/spec/features/projects/settings/issues_settings_spec.rb b/spec/features/projects/settings/issues_settings_spec.rb new file mode 100644 index 00000000000000..04595bc018068e --- /dev/null +++ b/spec/features/projects/settings/issues_settings_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Project settings > Issues', :js do + let(:project) { create(:project, :public) } + let(:user) { create(:user) } + + before do + project.add_maintainer(user) + + sign_in(user) + end + + context 'when Issues are initially enabled' do + context 'when Pipelines are initially enabled' do + before do + visit edit_project_path(project) + end + + it 'shows the Issues settings' do + expect(page).to have_content('Configure default branch name for branches created from issues.') + + value = "feature-%{id}" + + within('section.rspec-issues-settings') do + fill_in 'project[issue_branch_template]', with: value + + click_on('Save changes') + end + + expect(project.reload.issue_branch_template).to eq(value) + end + end + end +end diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 64fed73303f9df..75d980cd5f4734 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -568,6 +568,7 @@ Project: - suggestion_commit_message - merge_commit_template - squash_commit_template +- issue_branch_template Author: - name ProjectFeature: diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index f8c731b0d1090e..62a0e091c6accd 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -864,7 +864,7 @@ describe '.to_branch_name' do it 'parameterizes arguments and joins with dashes' do - expect(described_class.to_branch_name(123, 'foo bar', '!@#$%', 'f!o@o#b$a%r^')).to eq('123-foo-bar-f-o-o-b-a-r') + expect(described_class.to_branch_name(123, 'foo bar!@#$%f!o@o#b$a%r^')).to eq('123-foo-bar-f-o-o-b-a-r') end it 'preserves the case in the first argument' do @@ -872,7 +872,7 @@ end it 'truncates branch name to at most 100 characters' do - expect(described_class.to_branch_name('a' * 101)).to eq('a' * 100) + expect(described_class.to_branch_name('a' * 101, 'a')).to eq('a' * 100) end it 'truncates dangling parts of the branch name' do @@ -884,6 +884,13 @@ # 100 characters would've got us "999-lorem...lacus-custom-fri". expect(branch_name).to eq('999-lorem-ipsum-dolor-sit-amet-consectetur-adipiscing-elit-mauris-sit-amet-ipsum-id-lacus-custom') end + + it 'takes issue branch template into account' do + project = create(:project) + project.project_setting.update!(issue_branch_template: 'feature-%{id}') + + expect(described_class.to_branch_name(123, 'title', project: project)).to eq('feature-123') + end end describe '#to_branch_name' do diff --git a/spec/models/project_setting_spec.rb b/spec/models/project_setting_spec.rb index eb0292c70058f1..b33cf0219d3145 100644 --- a/spec/models/project_setting_spec.rb +++ b/spec/models/project_setting_spec.rb @@ -20,6 +20,7 @@ describe 'validations' do it { is_expected.not_to allow_value(nil).for(:target_platforms) } it { is_expected.to allow_value([]).for(:target_platforms) } + it { is_expected.to validate_length_of(:issue_branch_template).is_at_most(255) } it { is_expected.not_to allow_value(nil).for(:suggested_reviewers_enabled) } it { is_expected.to allow_value(true).for(:suggested_reviewers_enabled) } diff --git a/spec/views/projects/edit.html.haml_spec.rb b/spec/views/projects/edit.html.haml_spec.rb index 2935e4395ba804..d145aedf9bcef6 100644 --- a/spec/views/projects/edit.html.haml_spec.rb +++ b/spec/views/projects/edit.html.haml_spec.rb @@ -105,4 +105,20 @@ it_behaves_like 'renders registration features prompt', :project_disabled_repository_size_limit end end + + context 'issue branch template' do + it 'displays default template if none is set' do + render + + expect(rendered).to have_field('project[issue_branch_template]', placeholder: "%{id}-%{title}") + end + + it 'displays the user entered value' do + project.update!(issue_branch_template: '%{title}') + + render + + expect(rendered).to have_field('project[issue_branch_template]', with: '%{title}') + end + end end -- GitLab From afc6750cb1faaf6705a59d07362ecab1ef51aefe Mon Sep 17 00:00:00 2001 From: Patrick Cyiza Date: Thu, 6 Oct 2022 16:20:21 +0200 Subject: [PATCH 2/2] Moving branch names form to repository settings --- .../settings/repository_controller.rb | 1 + app/controllers/projects_controller.rb | 1 - app/views/projects/_issue_settings.html.haml | 14 ------ .../_branch_names_fields.html.haml | 14 ++++++ .../projects/branch_defaults/_show.html.haml | 1 + app/views/projects/edit.html.haml | 19 -------- app/views/projects/settings/_issues.html.haml | 13 ----- .../_default_issue_template.html.haml | 2 +- .../projects/settings/issues_settings_spec.rb | 2 - .../user_manages_issues_template_spec.rb | 2 +- locale/gitlab.pot | 14 +++--- .../settings/repository_controller_spec.rb | 32 +++++++++++++ .../settings/branch_names_settings_spec.rb | 48 +++++++++++++++++++ .../projects/settings/issues_settings_spec.rb | 36 -------------- spec/models/issue_spec.rb | 4 +- spec/views/projects/edit.html.haml_spec.rb | 16 ------- 16 files changed, 107 insertions(+), 112 deletions(-) delete mode 100644 app/views/projects/_issue_settings.html.haml create mode 100644 app/views/projects/branch_defaults/_branch_names_fields.html.haml delete mode 100644 app/views/projects/settings/_issues.html.haml create mode 100644 spec/features/projects/settings/branch_names_settings_spec.rb delete mode 100644 spec/features/projects/settings/issues_settings_spec.rb diff --git a/app/controllers/projects/settings/repository_controller.rb b/app/controllers/projects/settings/repository_controller.rb index e3bd89def9982d..0bf9b05b3b584a 100644 --- a/app/controllers/projects/settings/repository_controller.rb +++ b/app/controllers/projects/settings/repository_controller.rb @@ -116,6 +116,7 @@ def project_params def project_params_attributes [ + :issue_branch_template, :default_branch, :autoclose_referenced_issues ] diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index ab666d50d18be5..bdd7806a08579f 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -496,7 +496,6 @@ def project_params_attributes :service_desk_enabled, :merge_commit_template_or_default, :squash_commit_template_or_default, - :issue_branch_template, project_setting_attributes: project_setting_attributes ] + [project_feature_attributes: project_feature_attributes] end diff --git a/app/views/projects/_issue_settings.html.haml b/app/views/projects/_issue_settings.html.haml deleted file mode 100644 index 302733c39fd045..00000000000000 --- a/app/views/projects/_issue_settings.html.haml +++ /dev/null @@ -1,14 +0,0 @@ -- form = local_assigns.fetch(:form) - -.form-group - %b= s_('ProjectSettings|Branches name') - %p.text-secondary - = s_('ProjectSettings|Default branch name for branches created from merge request.') - .mb-2 - = form.text_field :issue_branch_template, class: 'form-control mb-2', placeholder: "%{id}-%{title}" - %p.form-text.text-muted - = s_('ProjectSettings|Leave empty to use default template.') - = sprintf(s_('ProjectSettings|Maximum %{maxLength} characters.'), { maxLength: Issue::MAX_BRANCH_TEMPLATE }) - - configure_the_issue_branch_name_help_link_help_link_url = help_page_path('user/project/repository/web_editor.md', anchor: 'create-a-new-branch-from-an-issue') - - configure_the_issue_branch_name_help_link_start = ''.html_safe % { url: configure_the_issue_branch_name_help_link_help_link_url } - = s_('ProjectSettings|%{link_start}What variables can I use?%{link_end}').html_safe % { link_start: configure_the_issue_branch_name_help_link_start, link_end: ''.html_safe } diff --git a/app/views/projects/branch_defaults/_branch_names_fields.html.haml b/app/views/projects/branch_defaults/_branch_names_fields.html.haml new file mode 100644 index 00000000000000..65f975fbd9e3d8 --- /dev/null +++ b/app/views/projects/branch_defaults/_branch_names_fields.html.haml @@ -0,0 +1,14 @@ +- if @project.project_feature.issues_access_level > 0 + %fieldset#branch-names-settings + .form-group + = f.label :issue_branch_template, _('Branch name template'), class: 'label-bold' + %p= s_('ProjectSettings|Branches created from issues follow this pattern.') + + .form-group + .gl-mb-2 + = f.text_field :issue_branch_template, class: 'form-control gl-mb-2', placeholder: "%{id}-%{title}" + %p.form-text.text-muted + = s_('ProjectSettings|Leave empty to use default template.') + = sprintf(s_('ProjectSettings|Maximum %{maxLength} characters.'), { maxLength: Issue::MAX_BRANCH_TEMPLATE }) + - branch_name_help_link = help_page_path('user/project/repository/web_editor.md', anchor: 'create-a-new-branch-from-an-issue') + = link_to _('What variables can I use?'), branch_name_help_link, target: "_blank" diff --git a/app/views/projects/branch_defaults/_show.html.haml b/app/views/projects/branch_defaults/_show.html.haml index 6790a658dceae2..4ecbc3b7fc871c 100644 --- a/app/views/projects/branch_defaults/_show.html.haml +++ b/app/views/projects/branch_defaults/_show.html.haml @@ -13,4 +13,5 @@ = gitlab_ui_form_for @project, url: url, method: :put, html: { multipart: true, class: "issue-settings-form js-issue-settings-form" }, authenticity_token: true do |f| %input{ name: 'update_section', type: 'hidden', value: 'js-issue-settings' } = render 'projects/branch_defaults/default_branch_fields', f: f + = render 'projects/branch_defaults/branch_names_fields', f: f = f.submit _('Save changes'), pajamas_button: true, data: { qa_selector: 'save_changes_button' } diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index c49bec831351f9..f6e3c15c08bf87 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -36,23 +36,6 @@ = c.body do = _('On the left sidebar, select %{merge_requests_link} to view them.').html_safe % { merge_requests_link: link_to('Settings > Merge requests', project_settings_merge_requests_path(@project)).html_safe } -%section.rspec-merge-request-settings.settings.merge-requests-feature.no-animate#js-merge-request-settings{ class: [('expanded' if expanded), ('hidden' if @project.project_feature.send(:merge_requests_access_level) == 0)], data: { qa_selector: 'merge_request_settings_content' } } - .settings-header - %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Merge requests') - = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do - = expanded ? _('Collapse') : _('Expand') - = render_if_exists 'projects/merge_request_settings_description_text' - - .settings-content - = render_if_exists 'shared/promotions/promote_mr_features' - - = gitlab_ui_form_for @project, html: { multipart: true, class: "merge-request-settings-form js-mr-settings-form" }, authenticity_token: true do |f| - %input{ name: 'update_section', type: 'hidden', value: 'js-merge-request-settings' } - = render 'projects/merge_request_settings', form: f - = f.submit _('Save changes'), class: "btn gl-button btn-confirm rspec-save-merge-request-changes", data: { qa_selector: 'save_merge_request_changes_button' } - -= render_if_exists 'projects/merge_request_approvals_settings', expanded: expanded - %section.settings.no-animate{ class: ('expanded' if expanded), data: { qa_selector: 'badges_settings_content' } } .settings-header %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only @@ -67,8 +50,6 @@ = render_if_exists 'compliance_management/compliance_framework/project_settings', expanded: expanded -= render 'projects/settings/issues', project: @project, expanded: expanded - = render_if_exists 'projects/settings/default_issue_template' = render 'projects/service_desk_settings' diff --git a/app/views/projects/settings/_issues.html.haml b/app/views/projects/settings/_issues.html.haml deleted file mode 100644 index a63fc34f007260..00000000000000 --- a/app/views/projects/settings/_issues.html.haml +++ /dev/null @@ -1,13 +0,0 @@ -- if project.project_feature.issues_access_level > 0 - %section.rspec-issues-settings.settings.issues-feature.no-animate#js-issue-settings{ class: [('expanded' if expanded)], data: { qa_selector: 'issues_settings_content' } } - .settings-header - %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Issues') - = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do - = expanded ? _('Collapse') : _('Expand') - %p= _('Configure default branch name for branches created from issues.') - - .settings-content - = gitlab_ui_form_for @project, html: { multipart: true, class: "issue-settings-form js-issue-settings-form" }, authenticity_token: true do |f| - %input{ name: 'update_section', type: 'hidden', value: 'js-issue-settings' } - = render 'projects/issue_settings', form: f - = f.submit _('Save changes'), class: "btn gl-button btn-confirm rspec-save-issue-changes", data: { qa_selector: 'save_issue_changes_button' } diff --git a/ee/app/views/projects/settings/_default_issue_template.html.haml b/ee/app/views/projects/settings/_default_issue_template.html.haml index e40b79284738ec..28e6059ffef9d0 100644 --- a/ee/app/views/projects/settings/_default_issue_template.html.haml +++ b/ee/app/views/projects/settings/_default_issue_template.html.haml @@ -1,6 +1,6 @@ - if @project.feature_available?(:issuable_default_templates) - expanded = expanded_by_default? - %section.settings.rspec-default-issue-settings.issues-feature.no-animate#js-issue-settings{ class: [('expanded' if expanded), ('hidden' if @project.project_feature.send(:issues_access_level) == 0)], data: { qa_selector: 'issue_template_settings_content' } } + %section.settings.issues-feature.no-animate#js-issue-settings{ class: [('expanded' if expanded), ('hidden' if @project.project_feature.send(:issues_access_level) == 0)], data: { qa_selector: 'issue_template_settings_content' } } .settings-header %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Default description template for issues') = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do diff --git a/ee/spec/features/projects/settings/issues_settings_spec.rb b/ee/spec/features/projects/settings/issues_settings_spec.rb index 1903c3b7a7b8e5..7d006a4e58657e 100644 --- a/ee/spec/features/projects/settings/issues_settings_spec.rb +++ b/ee/spec/features/projects/settings/issues_settings_spec.rb @@ -39,7 +39,6 @@ it 'does not show the Issues settings' do expect(page).not_to have_content('Set a default description template to be used for new issues.') - expect(page).not_to have_content('Configure default branch name for branches created from issues.') within('.sharing-permissions-form') do find('.project-feature-controls[data-for="project[project_feature_attributes][issues_access_level]"] .gl-toggle').click @@ -47,7 +46,6 @@ end expect(page).to have_content('Set a default description template to be used for new issues.') - expect(page).to have_content('Configure default branch name for branches created from issues.') end end diff --git a/ee/spec/features/projects/settings/user_manages_issues_template_spec.rb b/ee/spec/features/projects/settings/user_manages_issues_template_spec.rb index 61ebfc5d18a658..78e46a67a8bf2a 100644 --- a/ee/spec/features/projects/settings/user_manages_issues_template_spec.rb +++ b/ee/spec/features/projects/settings/user_manages_issues_template_spec.rb @@ -13,7 +13,7 @@ it 'saves issue template' do fill_in 'project_issues_template', with: "This issue should contain the following." - page.within('section.rspec-default-issue-settings') do + page.within '.issues-feature' do click_button 'Save changes' end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 54e4b51c07e48f..8170c2f9f1a03b 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -6831,6 +6831,9 @@ msgstr "" msgid "Branch name" msgstr "" +msgid "Branch name template" +msgstr "" + msgid "Branch not loaded - %{branchId}" msgstr "" @@ -10119,9 +10122,6 @@ msgstr "" msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings." msgstr "" -msgid "Configure default branch name for branches created from issues." -msgstr "" - msgid "Configure existing installation" msgstr "" @@ -31802,7 +31802,7 @@ msgstr "" msgid "ProjectSettings|Badges" msgstr "" -msgid "ProjectSettings|Branches name" +msgid "ProjectSettings|Branches created from issues follow this pattern." msgstr "" msgid "ProjectSettings|Build, test, and deploy your changes." @@ -31838,9 +31838,6 @@ msgstr "" msgid "ProjectSettings|Customize this project's badges." msgstr "" -msgid "ProjectSettings|Default branch name for branches created from merge request." -msgstr "" - msgid "ProjectSettings|Determine what happens to the commit history when you merge a merge request." msgstr "" @@ -45625,6 +45622,9 @@ msgstr "" msgid "What templates can I create?" msgstr "" +msgid "What variables can I use?" +msgstr "" + msgid "What will you use this group for?" msgstr "" diff --git a/spec/controllers/projects/settings/repository_controller_spec.rb b/spec/controllers/projects/settings/repository_controller_spec.rb index 31fefee3daaa37..6e04e3991ab4a5 100644 --- a/spec/controllers/projects/settings/repository_controller_spec.rb +++ b/spec/controllers/projects/settings/repository_controller_spec.rb @@ -168,5 +168,37 @@ end end end + + context 'when updating branch names template from issues' do + let(:branch_name_template) { 'feat/GL-%{id}-%{title}' } + + let(:request_params) { base_params.merge({ project: project_params_attributes }) } + + subject { put :update, params: request_params } + + context('with a good request') do + let(:project_params_attributes) { { issue_branch_template: branch_name_template } } + + it "updates issue_branch_template and redirect to project_settings_repository_path" do + subject + + expect(response).to redirect_to project_settings_repository_path(project) + expect(controller).to set_flash[:notice].to("Project settings were successfully updated.") + expect(project.reload.issue_branch_template).to eq(branch_name_template) + end + end + + context('with a bad input') do + let(:project_params_attributes) { { issue_branch_template: 'a' * 260 } } + + it "updates issue_branch_template and redirect to project_settings_repository_path" do + subject + + expect(response).to redirect_to project_settings_repository_path(project) + expect(controller).to set_flash[:alert].to("Project setting issue branch template is too long (maximum is 255 characters)") + expect(project.reload.issue_branch_template).to eq(nil) + end + end + end end end diff --git a/spec/features/projects/settings/branch_names_settings_spec.rb b/spec/features/projects/settings/branch_names_settings_spec.rb new file mode 100644 index 00000000000000..fdd883bc2b6fb6 --- /dev/null +++ b/spec/features/projects/settings/branch_names_settings_spec.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Project settings > repositories > Branch names', :js do + let_it_be(:project) { create(:project, :public) } + let(:user) { create(:user) } + + before do + project.add_maintainer(user) + + sign_in(user) + end + + context 'when Issues are initially disabled' do + let(:project_feature) { project.project_feature } + + before do + project_feature.update!(issues_access_level: ProjectFeature::DISABLED) + visit project_settings_repository_path(project) + end + + it 'do not render the Branch names settings' do + expect(page).not_to have_content('Branch name template') + end + end + + context 'when Issues are initially enabled' do + before do + visit project_settings_repository_path(project) + end + + it 'shows the Branch names settings' do + expect(page).to have_content('Branch name template') + + value = "feature-%{id}" + + within('section#branch-defaults-settings') do + fill_in 'project[issue_branch_template]', with: value + + click_on('Save changes') + end + + expect(project.reload.issue_branch_template).to eq(value) + expect(page).to have_content('Branch name template') + end + end +end diff --git a/spec/features/projects/settings/issues_settings_spec.rb b/spec/features/projects/settings/issues_settings_spec.rb deleted file mode 100644 index 04595bc018068e..00000000000000 --- a/spec/features/projects/settings/issues_settings_spec.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'Project settings > Issues', :js do - let(:project) { create(:project, :public) } - let(:user) { create(:user) } - - before do - project.add_maintainer(user) - - sign_in(user) - end - - context 'when Issues are initially enabled' do - context 'when Pipelines are initially enabled' do - before do - visit edit_project_path(project) - end - - it 'shows the Issues settings' do - expect(page).to have_content('Configure default branch name for branches created from issues.') - - value = "feature-%{id}" - - within('section.rspec-issues-settings') do - fill_in 'project[issue_branch_template]', with: value - - click_on('Save changes') - end - - expect(project.reload.issue_branch_template).to eq(value) - end - end - end -end diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index 62a0e091c6accd..9dfe89b8814543 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -887,9 +887,9 @@ it 'takes issue branch template into account' do project = create(:project) - project.project_setting.update!(issue_branch_template: 'feature-%{id}') + project.project_setting.update!(issue_branch_template: 'feature-%{id}-%{title}') - expect(described_class.to_branch_name(123, 'title', project: project)).to eq('feature-123') + expect(described_class.to_branch_name(123, 'issue title', project: project)).to eq('feature-123-issue-title') end end diff --git a/spec/views/projects/edit.html.haml_spec.rb b/spec/views/projects/edit.html.haml_spec.rb index d145aedf9bcef6..2935e4395ba804 100644 --- a/spec/views/projects/edit.html.haml_spec.rb +++ b/spec/views/projects/edit.html.haml_spec.rb @@ -105,20 +105,4 @@ it_behaves_like 'renders registration features prompt', :project_disabled_repository_size_limit end end - - context 'issue branch template' do - it 'displays default template if none is set' do - render - - expect(rendered).to have_field('project[issue_branch_template]', placeholder: "%{id}-%{title}") - end - - it 'displays the user entered value' do - project.update!(issue_branch_template: '%{title}') - - render - - expect(rendered).to have_field('project[issue_branch_template]', with: '%{title}') - end - end end -- GitLab