From 8caecc41ad6585224e4343360f15fd6c3e785901 Mon Sep 17 00:00:00 2001 From: trakos Date: Sun, 17 Oct 2021 06:31:37 +0200 Subject: [PATCH 1/5] Add merge commit template column in project settings table This commit adds merge_commit_template column in project_settings. It also adds this field to project's model. --- app/controllers/projects_controller.rb | 1 + app/models/project.rb | 1 + app/models/project_setting.rb | 2 ++ ...add_merge_commit_template_to_project_settings.rb | 9 +++++++++ ...rge_commit_template_limit_to_project_settings.rb | 13 +++++++++++++ db/schema_migrations/20211015021114 | 1 + db/schema_migrations/20211015024135 | 1 + db/structure.sql | 4 +++- .../gitlab/import_export/safe_model_attributes.yml | 1 + 9 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20211015021114_add_merge_commit_template_to_project_settings.rb create mode 100644 db/migrate/20211015024135_add_merge_commit_template_limit_to_project_settings.rb create mode 100644 db/schema_migrations/20211015021114 create mode 100644 db/schema_migrations/20211015024135 diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index bda52cd94e4836..9dcd398401156d 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -447,6 +447,7 @@ def project_params_attributes :suggestion_commit_message, :packages_enabled, :service_desk_enabled, + :merge_commit_template, project_setting_attributes: project_setting_attributes ] + [project_feature_attributes: project_feature_attributes] end diff --git a/app/models/project.rb b/app/models/project.rb index f7f8ae1f77c074..ce9497ea974d9c 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -452,6 +452,7 @@ def self.integration_association_name(name) :allow_merge_on_skipped_pipeline=, :has_confluence?, to: :project_setting delegate :active?, to: :prometheus_integration, allow_nil: true, prefix: true + delegate :merge_commit_template, :merge_commit_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 24d892290a6e66..6c8d2226bc9240 100644 --- a/app/models/project_setting.rb +++ b/app/models/project_setting.rb @@ -12,6 +12,8 @@ class ProjectSetting < ApplicationRecord self.primary_key = :project_id + validates :merge_commit_template, length: { maximum: 500 } + def squash_enabled_by_default? %w[always default_on].include?(squash_option) end diff --git a/db/migrate/20211015021114_add_merge_commit_template_to_project_settings.rb b/db/migrate/20211015021114_add_merge_commit_template_to_project_settings.rb new file mode 100644 index 00000000000000..adf2fdb2da7332 --- /dev/null +++ b/db/migrate/20211015021114_add_merge_commit_template_to_project_settings.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddMergeCommitTemplateToProjectSettings < Gitlab::Database::Migration[1.0] + enable_lock_retries! + + def change + add_column :project_settings, :merge_commit_template, :text # rubocop:disable Migration/AddLimitToTextColumns + end +end diff --git a/db/migrate/20211015024135_add_merge_commit_template_limit_to_project_settings.rb b/db/migrate/20211015024135_add_merge_commit_template_limit_to_project_settings.rb new file mode 100644 index 00000000000000..972872b8d2a9bc --- /dev/null +++ b/db/migrate/20211015024135_add_merge_commit_template_limit_to_project_settings.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class AddMergeCommitTemplateLimitToProjectSettings < Gitlab::Database::Migration[1.0] + disable_ddl_transaction! + + def up + add_text_limit :project_settings, :merge_commit_template, 500 + end + + def down + remove_text_limit :project_settings, :merge_commit_template + end +end diff --git a/db/schema_migrations/20211015021114 b/db/schema_migrations/20211015021114 new file mode 100644 index 00000000000000..1acbe9eded37fa --- /dev/null +++ b/db/schema_migrations/20211015021114 @@ -0,0 +1 @@ +687fa7d06a8d74b561d2b392e706fb209dbb1c0c8a483ad066820d29f7df059b \ No newline at end of file diff --git a/db/schema_migrations/20211015024135 b/db/schema_migrations/20211015024135 new file mode 100644 index 00000000000000..9f40fe5b71cb94 --- /dev/null +++ b/db/schema_migrations/20211015024135 @@ -0,0 +1 @@ +d3cafd6eb712ba3f11aa0e2bddc15bf312230e52d53ba8b7ae6c8d3cfd4aabcc \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 4279fbfd448f1d..2dab56a5d4514e 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -18288,8 +18288,10 @@ CREATE TABLE project_settings ( mr_default_target_self boolean DEFAULT false NOT NULL, previous_default_branch text, warn_about_potentially_unwanted_characters boolean DEFAULT true NOT NULL, + merge_commit_template text, CONSTRAINT check_3a03e7557a CHECK ((char_length(previous_default_branch) <= 4096)), - CONSTRAINT check_bde223416c CHECK ((show_default_award_emojis IS NOT NULL)) + CONSTRAINT check_bde223416c CHECK ((show_default_award_emojis IS NOT NULL)), + CONSTRAINT check_eaf7cfb6a7 CHECK ((char_length(merge_commit_template) <= 500)) ); CREATE TABLE project_statistics ( diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 4b125cab49b146..7aa21d7bc0f4a2 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -561,6 +561,7 @@ Project: - require_password_to_approve - autoclose_referenced_issues - suggestion_commit_message +- merge_commit_template ProjectTracingSetting: - external_url Author: -- GitLab From 61729d8adb84b735feac21ab4213786408b4e05a Mon Sep 17 00:00:00 2001 From: trakos Date: Sun, 17 Oct 2021 06:36:31 +0200 Subject: [PATCH 2/5] Create default merge commit message using customizable template Use new merge_commit_template field (when set) to create default value for merge commit message. Changelog: added --- app/models/merge_request.rb | 4 + .../merge_requests/merge_commit_message.rb | 59 ++++++ .../merge_commit_message_spec.rb | 186 ++++++++++++++++++ spec/models/merge_request_spec.rb | 16 ++ 4 files changed, 265 insertions(+) create mode 100644 lib/gitlab/merge_requests/merge_commit_message.rb create mode 100644 spec/lib/gitlab/merge_requests/merge_commit_message_spec.rb diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index bd68311fcc853a..3318ec11a8c563 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -1317,6 +1317,10 @@ def target_branch_exists? end def default_merge_commit_message(include_description: false) + if self.target_project.merge_commit_template.present? && !include_description + return ::Gitlab::MergeRequests::MergeCommitMessage.new(merge_request: self).message + end + closes_issues_references = visible_closing_issues_for.map do |issue| issue.to_reference(target_project) end diff --git a/lib/gitlab/merge_requests/merge_commit_message.rb b/lib/gitlab/merge_requests/merge_commit_message.rb new file mode 100644 index 00000000000000..f3e3988b55d803 --- /dev/null +++ b/lib/gitlab/merge_requests/merge_commit_message.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true +module Gitlab + module MergeRequests + class MergeCommitMessage + def initialize(merge_request:) + @merge_request = merge_request + end + + def message + return unless @merge_request.target_project.merge_commit_template.present? + + message = @merge_request.target_project.merge_commit_template + + # Remove placeholders that correspond to empty values and are the last word in the line + # along with all whitespace characters preceding them. + # This allows us to recreate previous default merge commit message behaviour - we skipped new line character + # before empty description and before closed issues when none were present. + PLACEHOLDERS.each do |key, value| + unless value.call(merge_request).present? + message = message.gsub(BLANK_PLACEHOLDERS_REGEXES[key], '') + end + end + + Gitlab::StringPlaceholderReplacer + .replace_string_placeholders(message, PLACEHOLDERS_REGEX) do |key| + PLACEHOLDERS[key].call(merge_request) + end + end + + private + + attr_reader :merge_request + + PLACEHOLDERS = { + 'source_branch' => ->(merge_request) { merge_request.source_branch.to_s }, + 'target_branch' => ->(merge_request) { merge_request.target_branch.to_s }, + 'title' => ->(merge_request) { merge_request.title }, + 'issues' => ->(merge_request) do + return "" if merge_request.visible_closing_issues_for.blank? + + closes_issues_references = merge_request.visible_closing_issues_for.map do |issue| + issue.to_reference(merge_request.target_project) + end + "Closes #{closes_issues_references.to_sentence}" + end, + 'description' => ->(merge_request) { merge_request.description.presence || '' }, + 'reference' => ->(merge_request) { merge_request.to_reference(full: true) } + }.freeze + + PLACEHOLDERS_REGEX = Regexp.union(PLACEHOLDERS.keys.map do |key| + Regexp.new(Regexp.escape(key)) + end).freeze + + BLANK_PLACEHOLDERS_REGEXES = (PLACEHOLDERS.map do |key, value| + [key, Regexp.new("[\n\r]+%{#{Regexp.escape(key)}}$")] + end).to_h.freeze + end + end +end diff --git a/spec/lib/gitlab/merge_requests/merge_commit_message_spec.rb b/spec/lib/gitlab/merge_requests/merge_commit_message_spec.rb new file mode 100644 index 00000000000000..5b99aa3cd06d04 --- /dev/null +++ b/spec/lib/gitlab/merge_requests/merge_commit_message_spec.rb @@ -0,0 +1,186 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::MergeRequests::MergeCommitMessage do + let(:merge_commit_template) { nil } + let(:project) { create(:project, :public, :repository, merge_commit_template: merge_commit_template) } + let(:user) { project.creator } + let(:merge_request_description) { "Merge Request Description\nNext line" } + let(:merge_request_title) { 'Bugfix' } + let(:merge_request) do + create( + :merge_request, + :simple, + source_project: project, + target_project: project, + author: user, + description: merge_request_description, + title: merge_request_title + ) + end + + subject { described_class.new(merge_request: merge_request) } + + it 'returns nil when template is not set in target project' do + expect(subject.message).to be_nil + end + + context 'when project has custom merge commit template' do + let(:merge_commit_template) { <<~MSG.rstrip } + %{title} + + See merge request %{reference} + MSG + + it 'uses custom template' do + expect(subject.message).to eq <<~MSG.rstrip + Bugfix + + See merge request #{merge_request.to_reference(full: true)} + MSG + end + end + + context 'when project has merge commit template with closed issues' do + let(:merge_commit_template) { <<~MSG.rstrip } + Merge branch '%{source_branch}' into '%{target_branch}' + + %{title} + + %{issues} + + See merge request %{reference} + MSG + + it 'omits issues and new lines when no issues are mentioned in description' do + expect(subject.message).to eq <<~MSG.rstrip + Merge branch 'feature' into 'master' + + Bugfix + + See merge request #{merge_request.to_reference(full: true)} + MSG + end + + context 'when MR closes issues' do + let(:issue_1) { create(:issue, project: project) } + let(:issue_2) { create(:issue, project: project) } + let(:merge_request_description) { "Description\n\nclosing #{issue_1.to_reference}, #{issue_2.to_reference}" } + + it 'includes them and keeps new line characters' do + expect(subject.message).to eq <<~MSG.rstrip + Merge branch 'feature' into 'master' + + Bugfix + + Closes #{issue_1.to_reference} and #{issue_2.to_reference} + + See merge request #{merge_request.to_reference(full: true)} + MSG + end + end + end + + context 'when project has merge commit template with description' do + let(:merge_commit_template) { <<~MSG.rstrip } + Merge branch '%{source_branch}' into '%{target_branch}' + + %{title} + + %{description} + + See merge request %{reference} + MSG + + it 'uses template' do + expect(subject.message).to eq <<~MSG.rstrip + Merge branch 'feature' into 'master' + + Bugfix + + Merge Request Description + Next line + + See merge request #{merge_request.to_reference(full: true)} + MSG + end + + context 'when description is empty string' do + let(:merge_request_description) { '' } + + it 'skips description placeholder and removes new line characters before it' do + expect(subject.message).to eq <<~MSG.rstrip + Merge branch 'feature' into 'master' + + Bugfix + + See merge request #{merge_request.to_reference(full: true)} + MSG + end + end + + context 'when description is nil' do + let(:merge_request_description) { nil } + + it 'skips description placeholder and removes new line characters before it' do + expect(subject.message).to eq <<~MSG.rstrip + Merge branch 'feature' into 'master' + + Bugfix + + See merge request #{merge_request.to_reference(full: true)} + MSG + end + end + + context 'when description is blank string' do + let(:merge_request_description) { "\n\r \n" } + + it 'skips description placeholder and removes new line characters before it' do + expect(subject.message).to eq <<~MSG.rstrip + Merge branch 'feature' into 'master' + + Bugfix + + See merge request #{merge_request.to_reference(full: true)} + MSG + end + end + end + + context 'when custom merge commit template contains placeholder in the middle or beginning of the line' do + let(:merge_commit_template) { <<~MSG.rstrip } + Merge branch '%{source_branch}' into '%{target_branch}' + + %{description} %{title} + + See merge request %{reference} + MSG + + it 'uses custom template' do + expect(subject.message).to eq <<~MSG.rstrip + Merge branch 'feature' into 'master' + + Merge Request Description + Next line Bugfix + + See merge request #{merge_request.to_reference(full: true)} + MSG + end + + context 'when description is empty string' do + let(:merge_request_description) { '' } + + it 'does not remove new line characters before empty placeholder' do + expect(subject.message).to eq <<~MSG.rstrip + Merge branch 'feature' into 'master' + + Bugfix + + See merge request #{merge_request.to_reference(full: true)} + MSG + end + end + end +end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index d871453e062249..22d54177f23d12 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -1638,6 +1638,22 @@ def set_compare(merge_request) expect(request.default_merge_commit_message) .not_to match("By removing all code\n\n") end + + it 'uses template from target project' do + request = build(:merge_request, title: 'Fix everything') + subject.target_project.merge_commit_template = '%{title}' + + expect(request.default_merge_commit_message) + .to eq('Fix everything') + end + + it 'ignores template when include_description is true' do + request = build(:merge_request, title: 'Fix everything') + subject.target_project.merge_commit_template = '%{title}' + + expect(request.default_merge_commit_message(include_description: true)) + .to match("See merge request #{request.to_reference(full: true)}") + end end describe "#auto_merge_strategy" do -- GitLab From 8b543a42096f2abdc98143d8ee7a26bc7e237dea Mon Sep 17 00:00:00 2001 From: trakos Date: Sun, 17 Oct 2021 06:42:05 +0200 Subject: [PATCH 3/5] Add merge commit template field in project settings and docs This change allows editing project's merge_commit_template in project settings. Additionally it adds documentation on merge commit template feature. --- ...ge_request_merge_commit_template.html.haml | 17 ++++++ .../_merge_request_settings.html.haml | 2 + .../merge_requests/commit_templates.md | 51 ++++++++++++++++++ .../merge_commit_message_template_v14_5.png | Bin 0 -> 19690 bytes doc/user/project/settings/index.md | 1 + .../_merge_request_settings.html.haml | 2 + locale/gitlab.pot | 9 ++++ spec/views/projects/edit.html.haml_spec.rb | 35 ++++++++++++ 8 files changed, 117 insertions(+) create mode 100644 app/views/projects/_merge_request_merge_commit_template.html.haml create mode 100644 doc/user/project/merge_requests/commit_templates.md create mode 100644 doc/user/project/merge_requests/img/merge_commit_message_template_v14_5.png diff --git a/app/views/projects/_merge_request_merge_commit_template.html.haml b/app/views/projects/_merge_request_merge_commit_template.html.haml new file mode 100644 index 00000000000000..185b730e0bb1ce --- /dev/null +++ b/app/views/projects/_merge_request_merge_commit_template.html.haml @@ -0,0 +1,17 @@ +- form = local_assigns.fetch(:form) + +.form-group + %b= s_('ProjectSettings|Merge commit message template') + %p.text-secondary + - configure_the_merge_commit_message_help_link_url = help_page_path('user/project/merge_requests/commit_templates.md', anchor: 'merge-commit-message-template') + - configure_the_merge_commit_message_help_link_start = ''.html_safe % { url: configure_the_merge_commit_message_help_link_url } + = s_('ProjectSettings|The commit message used when merging, if the merge method creates a merge commit. %{link_start}Learn more about syntax and variables.%{link_end}').html_safe % { link_start: configure_the_merge_commit_message_help_link_start, link_end: ''.html_safe } + .mb-2 + - default_merge_commit_template = "Merge branch '%{source_branch}' into '%{target_branch}'\n\n%{title}\n\n%{issues}\n\nSee merge request %{reference}" + = form.text_area :merge_commit_template, class: 'form-control gl-form-input', rows: 8, maxlength: 500, placeholder: default_merge_commit_template + %p.form-text.text-muted + = s_('ProjectSettings|Maximum 500 characters.') + = s_('ProjectSettings|Supported variables:') + - Gitlab::MergeRequests::MergeCommitMessage::PLACEHOLDERS.keys.each do |placeholder| + %code + = "%{#{placeholder}}".html_safe diff --git a/app/views/projects/_merge_request_settings.html.haml b/app/views/projects/_merge_request_settings.html.haml index f595b4f709b120..c5a25bec6eb3d5 100644 --- a/app/views/projects/_merge_request_settings.html.haml +++ b/app/views/projects/_merge_request_settings.html.haml @@ -10,5 +10,7 @@ = render 'projects/merge_request_merge_suggestions_settings', project: @project, form: form += render 'projects/merge_request_merge_commit_template', project: @project, form: form + - if @project.forked? = render 'projects/merge_request_target_project_settings', project: @project, form: form diff --git a/doc/user/project/merge_requests/commit_templates.md b/doc/user/project/merge_requests/commit_templates.md new file mode 100644 index 00000000000000..b615c86288cdba --- /dev/null +++ b/doc/user/project/merge_requests/commit_templates.md @@ -0,0 +1,51 @@ +--- +stage: Create +group: Code Review +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +type: reference, howto +--- + +# Commit message templates **(FREE)** + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/20263) in GitLab 14.5. + +## Merge commit message template + +As a project maintainer, you're able to configure merge commit message template. It will be used during merge to +create commit message. Template uses similar syntax to +[review suggestions](reviews/suggestions.md#configure-the-commit-message-for-applied-suggestions). + +Default merge commit message can be recreated using following template: + +```plaintext +Merge branch '%{source_branch}' into '%{target_branch}' + +%{title} + +%{issues} + +See merge request %{reference} +``` + +This commit message can be customized to follow any guidelines you might have. +To do so, expand the **Merge requests** tab within your project's **General** +settings and change the **Merge commit message template** text: + +![Custom commit message for applied suggestions](img/merge_commit_message_template_v14_5.png) + +You can use static text and following variables: + +| Variable | Description | Output example | +|--------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------| +| `%{source_branch}` | The name of the branch that is being merged. | `my-feature-branch` | +| `%{target_branch}` | The name of the branch that the changes are applied to. | `master` | +| `%{title}` | Title of the merge request. | Fix stuff | +| `%{issues}` | String with phrase "Closes " with all issues mentioned in the MR description matching [issue closing patterns](../issues/managing_issues.md#closing-issues-automatically). It will be empty when no issues were mentioned. | `Closes #465, #190 and #400` | +| `%{description}` | Description of the merge request. | Merge request description.
Can be multiline. | +| `%{reference}` | Reference to the merge request. | group-name/project-name!72359 | + +NOTE: +Empty variables that are the only word in a line will be removed along with all newline characters preceding it. + +Merge commit template field has a limit of 500 characters. This limit only applies to the template +itself. diff --git a/doc/user/project/merge_requests/img/merge_commit_message_template_v14_5.png b/doc/user/project/merge_requests/img/merge_commit_message_template_v14_5.png new file mode 100644 index 0000000000000000000000000000000000000000..f18ca640d38151c91bfa89134a93afbda11f22d3 GIT binary patch literal 19690 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

~ycc{+2v9?B|i##BI$rd&4fDuAG|Rt>~*hr@+au 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 W>8aB${pZ*J>f||r&xRGb%?<#QI)umo literal 0 HcmV?d00001 diff --git a/doc/user/project/settings/index.md b/doc/user/project/settings/index.md index 1eba4fdcdb156b..cdd6ba7356384c 100644 --- a/doc/user/project/settings/index.md +++ b/doc/user/project/settings/index.md @@ -310,6 +310,7 @@ Set up your project's merge request settings: - Enable [require an associated issue from Jira](../../../integration/jira/issues.md#require-associated-jira-issue-for-merge-requests-to-be-merged). - Enable [`delete source branch after merge` option by default](../merge_requests/getting_started.md#deleting-the-source-branch). - Configure [suggested changes commit messages](../merge_requests/reviews/suggestions.md#configure-the-commit-message-for-applied-suggestions). +- Configure [merge commit message template](../merge_requests/commit_templates.md). - Configure [the default target project](../merge_requests/creating_merge_requests.md#set-the-default-target-project) for merge requests coming from forks. ### Service Desk diff --git a/ee/app/views/projects/_merge_request_settings.html.haml b/ee/app/views/projects/_merge_request_settings.html.haml index 75cfb4d49c1c1b..8ffa06f99a4150 100644 --- a/ee/app/views/projects/_merge_request_settings.html.haml +++ b/ee/app/views/projects/_merge_request_settings.html.haml @@ -13,6 +13,8 @@ = render 'projects/merge_request_merge_suggestions_settings', project: @project, form: form += render_ce 'projects/merge_request_merge_commit_template', project: @project, form: form + - if @project.forked? = render_ce 'projects/merge_request_target_project_settings', project: @project, form: form diff --git a/locale/gitlab.pot b/locale/gitlab.pot index e5c21df7dc8274..5bb18a130f5894 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -27144,12 +27144,18 @@ msgstr "" msgid "ProjectSettings|Manages large files such as audio, video, and graphics files." msgstr "" +msgid "ProjectSettings|Maximum 500 characters." +msgstr "" + msgid "ProjectSettings|Merge checks" msgstr "" msgid "ProjectSettings|Merge commit" msgstr "" +msgid "ProjectSettings|Merge commit message template" +msgstr "" + msgid "ProjectSettings|Merge commit with semi-linear history" msgstr "" @@ -27267,6 +27273,9 @@ msgstr "" msgid "ProjectSettings|The commit message used when applying merge request suggestions. %{link_start}Learn more about suggestions.%{link_end}" msgstr "" +msgid "ProjectSettings|The commit message used when merging, if the merge method creates a merge commit. %{link_start}Learn more about syntax and variables.%{link_end}" +msgstr "" + msgid "ProjectSettings|The default target project for merge requests created in this fork project." msgstr "" diff --git a/spec/views/projects/edit.html.haml_spec.rb b/spec/views/projects/edit.html.haml_spec.rb index b44d07d2ee4537..60f4c1664f7549 100644 --- a/spec/views/projects/edit.html.haml_spec.rb +++ b/spec/views/projects/edit.html.haml_spec.rb @@ -57,6 +57,41 @@ end end + context 'merge commit template' do + it 'displays all possible variables' do + render + + expect(rendered).to have_content('%{source_branch}') + expect(rendered).to have_content('%{target_branch}') + expect(rendered).to have_content('%{title}') + expect(rendered).to have_content('%{issues}') + expect(rendered).to have_content('%{description}') + expect(rendered).to have_content('%{reference}') + end + + it 'displays a placeholder if none is set' do + render + + expect(rendered).to have_field('project[merge_commit_template]', placeholder: <<~MSG.rstrip) + Merge branch '%{source_branch}' into '%{target_branch}' + + %{title} + + %{issues} + + See merge request %{reference} + MSG + end + + it 'displays the user entered value' do + project.update!(merge_commit_template: '%{title}') + + render + + expect(rendered).to have_field('project[merge_commit_template]', with: '%{title}') + end + end + context 'forking' do before do assign(:project, project) -- GitLab From 6b903e48eb2d009c054f23153cd3c2337125e966 Mon Sep 17 00:00:00 2001 From: trakos Date: Sun, 17 Oct 2021 06:43:45 +0200 Subject: [PATCH 4/5] Expose mergeCommitTemplate field in APIs --- app/graphql/types/project_type.rb | 5 +++++ doc/api/graphql/reference/index.md | 1 + doc/api/projects.md | 15 +++++++++++++++ lib/api/entities/project.rb | 1 + lib/api/helpers/projects_helpers.rb | 2 ++ spec/graphql/types/project_type_spec.rb | 2 +- 6 files changed, 25 insertions(+), 1 deletion(-) diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index 791875242dfb1a..dd73fb8dceb408 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -381,6 +381,11 @@ class ProjectType < BaseObject description: 'Cluster agents associated with the project.', resolver: ::Resolvers::Clusters::AgentsResolver + field :merge_commit_template, + GraphQL::Types::String, + null: true, + description: 'Template used to create merge commit message in merge requests.' + def label(title:) BatchLoader::GraphQL.for(title).batch(key: project) do |titles, loader, args| LabelsFinder diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 63b38e5291b26a..60510e462831a8 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -12857,6 +12857,7 @@ Represents vulnerability finding of a security report on the pipeline. | `jobsEnabled` | [`Boolean`](#boolean) | Indicates if CI/CD pipeline jobs are enabled for the current user. | | `lastActivityAt` | [`Time`](#time) | Timestamp of the project last activity. | | `lfsEnabled` | [`Boolean`](#boolean) | Indicates if the project has Large File Storage (LFS) enabled. | +| `mergeCommitTemplate` | [`String`](#string) | Template used to create merge commit message in merge requests. | | `mergeRequestsEnabled` | [`Boolean`](#boolean) | Indicates if Merge Requests are enabled for the current user. | | `mergeRequestsFfOnlyEnabled` | [`Boolean`](#boolean) | Indicates if no merge commits should be created and all merges should instead be fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded. | | `name` | [`String!`](#string) | Name of the project (without namespace). | diff --git a/doc/api/projects.md b/doc/api/projects.md index c3f2adc463fce8..d19019c959756b 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -182,6 +182,7 @@ When the user is authenticated and `simple` is not set this returns something li "squash_option": "default_on", "autoclose_referenced_issues": true, "suggestion_commit_message": null, + "merge_commit_template": null, "marked_for_deletion_at": "2020-04-03", // Deprecated and will be removed in API v5 in favor of marked_for_deletion_on "marked_for_deletion_on": "2020-04-03", "statistics": { @@ -298,6 +299,7 @@ When the user is authenticated and `simple` is not set this returns something li "service_desk_address": null, "autoclose_referenced_issues": true, "suggestion_commit_message": null, + "merge_commit_template": null, "statistics": { "commit_count": 12, "storage_size": 2066080, @@ -464,6 +466,7 @@ GET /users/:user_id/projects "squash_option": "default_on", "autoclose_referenced_issues": true, "suggestion_commit_message": null, + "merge_commit_template": null, "marked_for_deletion_at": "2020-04-03", // Deprecated and will be removed in API v5 in favor of marked_for_deletion_on "marked_for_deletion_on": "2020-04-03", "statistics": { @@ -580,6 +583,7 @@ GET /users/:user_id/projects "service_desk_address": null, "autoclose_referenced_issues": true, "suggestion_commit_message": null, + "merge_commit_template": null, "statistics": { "commit_count": 12, "storage_size": 2066080, @@ -706,6 +710,7 @@ Example response: "squash_option": "default_on", "autoclose_referenced_issues": true, "suggestion_commit_message": null, + "merge_commit_template": null, "statistics": { "commit_count": 37, "storage_size": 1038090, @@ -817,6 +822,7 @@ Example response: "service_desk_address": null, "autoclose_referenced_issues": true, "suggestion_commit_message": null, + "merge_commit_template": null, "statistics": { "commit_count": 12, "storage_size": 2066080, @@ -984,6 +990,7 @@ GET /projects/:id "service_desk_address": null, "autoclose_referenced_issues": true, "suggestion_commit_message": null, + "merge_commit_template": null, "marked_for_deletion_at": "2020-04-03", // Deprecated and will be removed in API v5 in favor of marked_for_deletion_on "marked_for_deletion_on": "2020-04-03", "compliance_frameworks": [ "sox" ], @@ -1296,6 +1303,7 @@ POST /projects/user/:user_id | `issues_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable issues for this project. Use `issues_access_level` instead. | | `jobs_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable jobs for this project. Use `builds_access_level` instead. | | `lfs_enabled` | boolean | **{dotted-circle}** No | Enable LFS. | +| `merge_commit_template` | string | **{dotted-circle}** No | [Template](../user/project/merge_requests/commit_templates.md) used to create merge commit message in merge requests. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/20263) in GitLab 14.5.)_ | | `merge_method` | string | **{dotted-circle}** No | Set the [merge method](#project-merge-method) used. | | `merge_requests_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. | | `merge_requests_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable merge requests for this project. Use `merge_requests_access_level` instead. | @@ -1373,6 +1381,7 @@ PUT /projects/:id | `issues_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable issues for this project. Use `issues_access_level` instead. | | `jobs_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable jobs for this project. Use `builds_access_level` instead. | | `lfs_enabled` | boolean | **{dotted-circle}** No | Enable LFS. | +| `merge_commit_template` | string | **{dotted-circle}** No | [Template](../user/project/merge_requests/commit_templates.md) used to create merge commit message in merge requests. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/20263) in GitLab 14.5.)_ | | `merge_method` | string | **{dotted-circle}** No | Set the [merge method](#project-merge-method) used. | | `merge_requests_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. | | `merge_requests_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable merge requests for this project. Use `merge_requests_access_level` instead. | @@ -1531,6 +1540,7 @@ Example responses: "squash_option": "default_on", "autoclose_referenced_issues": true, "suggestion_commit_message": null, + "merge_commit_template": null, "container_registry_image_prefix": "registry.example.com/diaspora/diaspora-project-site", "_links": { "self": "http://example.com/api/v4/projects", @@ -1632,6 +1642,7 @@ Example response: "squash_option": "default_on", "autoclose_referenced_issues": true, "suggestion_commit_message": null, + "merge_commit_template": null, "container_registry_image_prefix": "registry.example.com/diaspora/diaspora-project-site", "_links": { "self": "http://example.com/api/v4/projects", @@ -1731,6 +1742,7 @@ Example response: "squash_option": "default_on", "autoclose_referenced_issues": true, "suggestion_commit_message": null, + "merge_commit_template": null, "container_registry_image_prefix": "registry.example.com/diaspora/diaspora-project-site", "_links": { "self": "http://example.com/api/v4/projects", @@ -1924,6 +1936,7 @@ Example response: "squash_option": "default_on", "autoclose_referenced_issues": true, "suggestion_commit_message": null, + "merge_commit_template": null, "container_registry_image_prefix": "registry.example.com/diaspora/diaspora-project-site", "_links": { "self": "http://example.com/api/v4/projects", @@ -2044,6 +2057,7 @@ Example response: "squash_option": "default_on", "autoclose_referenced_issues": true, "suggestion_commit_message": null, + "merge_commit_template": null, "container_registry_image_prefix": "registry.example.com/diaspora/diaspora-project-site", "_links": { "self": "http://example.com/api/v4/projects", @@ -2670,6 +2684,7 @@ Example response: "merge_method": "merge", "squash_option": "default_on", "suggestion_commit_message": null, + "merge_commit_template": null, "auto_devops_enabled": true, "auto_devops_deploy_strategy": "continuous", "autoclose_referenced_issues": true, diff --git a/lib/api/entities/project.rb b/lib/api/entities/project.rb index 41320d184f9c30..e3f1e90b80f0c6 100644 --- a/lib/api/entities/project.rb +++ b/lib/api/entities/project.rb @@ -114,6 +114,7 @@ class Project < BasicProjectDetails expose :merge_method expose :squash_option expose :suggestion_commit_message + expose :merge_commit_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 d87680ab43ee63..42d1c40dd1129a 100644 --- a/lib/api/helpers/projects_helpers.rb +++ b/lib/api/helpers/projects_helpers.rb @@ -61,6 +61,7 @@ module ProjectsHelpers optional :printing_merge_request_link_enabled, type: Boolean, desc: 'Show link to create/view merge request when pushing from the command line' optional :merge_method, type: String, values: %w(ff rebase_merge merge), desc: 'The merge method used when merging merge requests' 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 :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' @@ -160,6 +161,7 @@ def self.update_params_at_least_one_of :wiki_access_level, :avatar, :suggestion_commit_message, + :merge_commit_template, :repository_storage, :compliance_framework_setting, :packages_enabled, diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb index fc2f67f2451749..4f205e861dd4b1 100644 --- a/spec/graphql/types/project_type_spec.rb +++ b/spec/graphql/types/project_type_spec.rb @@ -34,7 +34,7 @@ container_repositories container_repositories_count pipeline_analytics squash_read_only sast_ci_configuration cluster_agent cluster_agents agent_configurations - ci_template timelogs + ci_template timelogs merge_commit_template ] expect(described_class).to include_graphql_fields(*expected_fields) -- GitLab From 18819eeca2922f9d52959c99f9d9ce28940e6784 Mon Sep 17 00:00:00 2001 From: trakos Date: Sun, 17 Oct 2021 06:59:21 +0200 Subject: [PATCH 5/5] Remove include MR description checkbox and deprecate related API field Now that we added merge commit template function, we don't need this checkbox. It wouldn't work with template. This commit also deprecates defaultMergeCommitMessageWithDescription in graphql. This field ignores mergeCommitTemplate, and doesn't serve any function internally anymore. Users are encouraged to use new merge commit template feature instead. Changelog: deprecated --- .../components/states/commit_edit.vue | 2 +- .../components/states/ready_to_merge.vue | 64 +++++++++++-------- app/graphql/types/merge_request_type.rb | 3 +- doc/api/graphql/reference/index.md | 2 +- locale/gitlab.pot | 6 +- ...er_customizes_merge_commit_message_spec.rb | 26 +++----- .../components/states/commit_edit_spec.js | 11 ++-- .../states/mr_widget_ready_to_merge_spec.js | 13 ---- 8 files changed, 59 insertions(+), 68 deletions(-) diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/commit_edit.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/commit_edit.vue index c501e410b1f65f..3eda2828e97ec5 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/commit_edit.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/commit_edit.vue @@ -41,7 +41,7 @@ export default { rows="7" @input="$emit('input', $event.target.value)" > - + diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue index aca838ce099cbd..d2cc99302a9ad5 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue @@ -18,9 +18,10 @@ import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests import createFlash from '~/flash'; import { secondsToMilliseconds } from '~/lib/utils/datetime_utility'; import simplePoll from '~/lib/utils/simple_poll'; -import { __ } from '~/locale'; +import { __, s__ } from '~/locale'; import SmartInterval from '~/smart_interval'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; +import { helpPagePath } from '~/helpers/help_page_helper'; import MergeRequest from '../../../merge_request'; import { AUTO_MERGE_STRATEGIES, @@ -179,6 +180,11 @@ export default { return this.mr.canRemoveSourceBranch; }, + commitTemplateHelpPage() { + return helpPagePath('user/project/merge_requests/commit_templates.md', { + anchor: 'merge-commit-message-template', + }); + }, commits() { if (this.glFeatures.mergeRequestWidgetGraphql) { return this.state.commitsWithoutMergeCommits.nodes; @@ -347,15 +353,6 @@ export default { updateGraphqlState() { return this.$apollo.queries.state.refetch(); }, - updateMergeCommitMessage(includeDescription) { - const commitMessage = this.glFeatures.mergeRequestWidgetGraphql - ? this.state.defaultMergeCommitMessage - : this.mr.commitMessage; - const commitMessageWithDescription = this.glFeatures.mergeRequestWidgetGraphql - ? this.state.defaultMergeCommitMessageWithDescription - : this.mr.commitMessageWithDescription; - this.commitMessage = includeDescription ? commitMessageWithDescription : commitMessage; - }, handleMergeButtonClick(useAutoMerge, mergeImmediately = false, confirmationClicked = false) { if (this.showFailedPipelineModal && !confirmationClicked) { this.isPipelineFailedModalVisible = true; @@ -508,6 +505,11 @@ export default { }); }, }, + i18n: { + mergeCommitTemplateHintText: s__( + 'mrWidget|To change this default message, edit the template for merge commit messages. %{linkStart}Learn more.%{linkEnd}', + ), + }, }; @@ -679,15 +681,20 @@ export default { input-id="merge-message-edit" class="gl-m-0! gl-p-0!" > -