Commit 39dcf147 authored by Patrick Bajao's avatar Patrick Bajao

Merge branch 'merge-commit-message-template' into 'master'

Add merge commit message template

See merge request gitlab-org/gitlab!64437
parents be3e9d52 18819eec
......@@ -41,7 +41,7 @@ export default {
rows="7"
@input="$emit('input', $event.target.value)"
></textarea>
<slot name="checkbox"></slot>
<slot name="text-muted"></slot>
</div>
</li>
</template>
......@@ -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}',
),
},
};
</script>
......@@ -679,15 +681,20 @@ export default {
input-id="merge-message-edit"
class="gl-m-0! gl-p-0!"
>
<template #checkbox>
<label>
<input
id="include-description"
type="checkbox"
@change="updateMergeCommitMessage($event.target.checked)"
/>
{{ __('Include merge request description') }}
</label>
<template #text-muted>
<p class="form-text text-muted">
<gl-sprintf :message="$options.i18n.mergeCommitTemplateHintText">
<template #link="{ content }">
<gl-link
:href="commitTemplateHelpPage"
class="inline-link"
target="_blank"
>
{{ content }}
</gl-link>
</template>
</gl-sprintf>
</p>
</template>
</commit-edit>
</ul>
......@@ -792,15 +799,16 @@ export default {
:label="__('Merge commit message')"
input-id="merge-message-edit"
>
<template #checkbox>
<label>
<input
id="include-description"
type="checkbox"
@change="updateMergeCommitMessage($event.target.checked)"
/>
{{ __('Include merge request description') }}
</label>
<template #text-muted>
<p class="form-text text-muted">
<gl-sprintf :message="$options.i18n.mergeCommitTemplateHintText">
<template #link="{ content }">
<gl-link :href="commitTemplateHelpPage" class="inline-link" target="_blank">
{{ content }}
</gl-link>
</template>
</gl-sprintf>
</p>
</template>
</commit-edit>
</ul>
......
......@@ -447,6 +447,7 @@ class ProjectsController < Projects::ApplicationController
:suggestion_commit_message,
:packages_enabled,
:service_desk_enabled,
:merge_commit_template,
project_setting_attributes: project_setting_attributes
] + [project_feature_attributes: project_feature_attributes]
end
......
......@@ -99,7 +99,8 @@ module Types
field :default_merge_commit_message, GraphQL::Types::String, null: true,
description: 'Default merge commit message of the merge request.'
field :default_merge_commit_message_with_description, GraphQL::Types::String, null: true,
description: 'Default merge commit message of the merge request with description.'
description: 'Default merge commit message of the merge request with description. Will have the same value as `defaultMergeCommitMessage` when project has `mergeCommitTemplate` set.',
deprecated: { reason: 'Define merge commit template in project and use `defaultMergeCommitMessage`', milestone: '14.5' }
field :default_squash_commit_message, GraphQL::Types::String, null: true, calls_gitaly: true,
description: 'Default squash commit message of the merge request.'
field :merge_ongoing, GraphQL::Types::Boolean, method: :merge_ongoing?, null: false,
......
......@@ -381,6 +381,11 @@ module Types
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
......
......@@ -1316,6 +1316,10 @@ class MergeRequest < ApplicationRecord
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
......
......@@ -452,6 +452,7 @@ class Project < ApplicationRecord
: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
......
......@@ -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
......
- 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 = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.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: '</a>'.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
......@@ -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
# 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
# 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
687fa7d06a8d74b561d2b392e706fb209dbb1c0c8a483ad066820d29f7df059b
\ No newline at end of file
d3cafd6eb712ba3f11aa0e2bddc15bf312230e52d53ba8b7ae6c8d3cfd4aabcc
\ No newline at end of file
......@@ -18300,8 +18300,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 (
......@@ -11489,7 +11489,7 @@ Maven metadata.
| <a id="mergerequestconflicts"></a>`conflicts` | [`Boolean!`](#boolean) | Indicates if the merge request has conflicts. |
| <a id="mergerequestcreatedat"></a>`createdAt` | [`Time!`](#time) | Timestamp of when the merge request was created. |
| <a id="mergerequestdefaultmergecommitmessage"></a>`defaultMergeCommitMessage` | [`String`](#string) | Default merge commit message of the merge request. |
| <a id="mergerequestdefaultmergecommitmessagewithdescription"></a>`defaultMergeCommitMessageWithDescription` | [`String`](#string) | Default merge commit message of the merge request with description. |
| <a id="mergerequestdefaultmergecommitmessagewithdescription"></a>`defaultMergeCommitMessageWithDescription` **{warning-solid}** | [`String`](#string) | **Deprecated** in 14.5. Define merge commit template in project and use `defaultMergeCommitMessage`. |
| <a id="mergerequestdefaultsquashcommitmessage"></a>`defaultSquashCommitMessage` | [`String`](#string) | Default squash commit message of the merge request. |
| <a id="mergerequestdescription"></a>`description` | [`String`](#string) | Description of the merge request (Markdown rendered as HTML for caching). |
| <a id="mergerequestdescriptionhtml"></a>`descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. |
......@@ -12832,6 +12832,7 @@ Represents vulnerability finding of a security report on the pipeline.
| <a id="projectjobsenabled"></a>`jobsEnabled` | [`Boolean`](#boolean) | Indicates if CI/CD pipeline jobs are enabled for the current user. |
| <a id="projectlastactivityat"></a>`lastActivityAt` | [`Time`](#time) | Timestamp of the project last activity. |
| <a id="projectlfsenabled"></a>`lfsEnabled` | [`Boolean`](#boolean) | Indicates if the project has Large File Storage (LFS) enabled. |
| <a id="projectmergecommittemplate"></a>`mergeCommitTemplate` | [`String`](#string) | Template used to create merge commit message in merge requests. |
| <a id="projectmergerequestsenabled"></a>`mergeRequestsEnabled` | [`Boolean`](#boolean) | Indicates if Merge Requests are enabled for the current user. |
| <a id="projectmergerequestsffonlyenabled"></a>`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. |
| <a id="projectname"></a>`name` | [`String!`](#string) | Name of the project (without namespace). |
......@@ -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,
......
---
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 <issue numbers>" 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.<br>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.
......@@ -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
......
......@@ -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
......
......@@ -114,6 +114,7 @@ module API
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)
}
......
......@@ -61,6 +61,7 @@ module API
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 @@ module API
:wiki_access_level,
:avatar,
:suggestion_commit_message,
:merge_commit_template,
:repository_storage,
:compliance_framework_setting,
:packages_enabled,
......
# 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
......@@ -18266,9 +18266,6 @@ msgstr ""
msgid "Include description in commit message"
msgstr ""
msgid "Include merge request description"
msgstr ""
msgid "Include new features from all tiers."
msgstr ""
......@@ -27156,12 +27153,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 ""
......@@ -27279,6 +27282,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 ""
......@@ -41409,6 +41415,9 @@ msgstr ""
msgid "mrWidget|To approve this merge request, please enter your password. This project requires all approvals to be authenticated."
msgstr ""
msgid "mrWidget|To change this default message, edit the template for merge commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
msgid "mrWidget|To merge, a Jira issue key must be mentioned in the title or description."
msgstr ""
......
......@@ -26,33 +26,27 @@ RSpec.describe 'Merge request < User customizes merge commit message', :js do
].join("\n\n")
end
let(:message_with_description) do
[
"Merge branch 'feature' into 'master'",
merge_request.title,
merge_request.description,
"See merge request #{merge_request.to_reference(full: true)}"
].join("\n\n")
end
before do
project.add_maintainer(user)
sign_in(user)
visit project_merge_request_path(project, merge_request)
end
it 'toggles commit message between message with description and without description' do
it 'has commit message without description' do
expect(page).not_to have_selector('#merge-message-edit')
first('.js-mr-widget-commits-count').click
expect(textbox).to be_visible
expect(textbox.value).to eq(default_message)
end
check('Include merge request description')
expect(textbox.value).to eq(message_with_description)
uncheck('Include merge request description')
context 'when target project has merge commit template set' do
let(:project) { create(:project, :public, :repository, merge_commit_template: '%{title}') }
expect(textbox.value).to eq(default_message)
it 'uses merge commit template' do
expect(page).not_to have_selector('#merge-message-edit')
first('.js-mr-widget-commits-count').click
expect(textbox).to be_visible
expect(textbox.value).to eq(merge_request.title)
end
end
end
......@@ -3,6 +3,7 @@ import CommitEdit from '~/vue_merge_request_widget/components/states/commit_edit
const testCommitMessage = 'Test commit message';
const testLabel = 'Test label';
const testTextMuted = 'Test text muted';
const testInputId = 'test-input-id';
describe('Commits edit component', () => {
......@@ -63,7 +64,7 @@ describe('Commits edit component', () => {
beforeEach(() => {
createComponent({
header: `<div class="test-header">${testCommitMessage}</div>`,
checkbox: `<label class="test-checkbox">${testLabel}</label >`,
'text-muted': `<p class="test-text-muted">${testTextMuted}</p>`,
});
});
......@@ -74,11 +75,11 @@ describe('Commits edit component', () => {
expect(headerSlotElement.text()).toBe(testCommitMessage);
});
it('renders checkbox slot correctly', () => {
const checkboxSlotElement = wrapper.find('.test-checkbox');
it('renders text-muted slot correctly', () => {
const textMutedElement = wrapper.find('.test-text-muted');
expect(checkboxSlotElement.exists()).toBe(true);
expect(checkboxSlotElement.text()).toBe(testLabel);
expect(textMutedElement.exists()).toBe(true);
expect(textMutedElement.text()).toBe(testTextMuted);
});
});
});
......@@ -269,19 +269,6 @@ describe('ReadyToMerge', () => {
});
describe('methods', () => {
describe('updateMergeCommitMessage', () => {
it('should revert flag and change commitMessage', () => {
createComponent();
wrapper.vm.updateMergeCommitMessage(true);
expect(wrapper.vm.commitMessage).toEqual(commitMessageWithDescription);
wrapper.vm.updateMergeCommitMessage(false);
expect(wrapper.vm.commitMessage).toEqual(commitMessage);
});
});
describe('handleMergeButtonClick', () => {
const returnPromise = (status) =>
new Promise((resolve) => {
......
......@@ -34,7 +34,7 @@ RSpec.describe GitlabSchema.types['Project'] do
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)
......
......@@ -561,6 +561,7 @@ Project:
- require_password_to_approve
- autoclose_referenced_issues
- suggestion_commit_message
- merge_commit_template
ProjectTracingSetting:
- external_url
Author:
......
# 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
......@@ -1638,6 +1638,22 @@ RSpec.describe MergeRequest, factory_default: :keep do
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
......
......@@ -57,6 +57,41 @@ RSpec.describe 'projects/edit' do
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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment